ポータル: PyQt グラフィック ソフトウェア (プロジェクトベースの学習)
需要分析
病院における発達スクリーニング検査用の定量化ソフトウェア
入力
患者基本情報
スクリーニング検査フォーム(テンプレートフォームはすでに用意されています)
出力
スポーツ、社会適応、知能に関するさまざまな生スコア、
IQ EQ に
対応するさまざまな計算スコア
レポート形式 - 固定
ローカル (PDF/Word) に保存、テンプレートの置き換えを検討してください
フレームワーク設計
Python 3.6 + QT ベース
インターフェイス層 - QtDesigner
全体的なスタイル
量子化テーブルは大きく3つのカテゴリーに分かれており、各パートに多くのパラメータインジケーターがあるため、スタックレイアウトが採用されており、メイン
インターフェイスは2つのフレームで構成されています。
複数行のテキストボックス
https://blog.csdn.net/qq_28077617/article/details/121876632
サブページ
情報
複数の入力ボックス(lineEdit)がある場合は、Tabショートカットキーの導入を検討してください。具体的な設定方法については、こちらの記事を参照してください。
日付の入れ子
カレンダーのドロップダウンで時間を選択します
https://blog.csdn.net/weixin_39626452/article/details/86700178?spm=1001.2014.3001.5506
UI
self.dateEdit = QtWidgets.QDateEdit(self.gridLayoutWidget)
self.dateEdit.setObjectName("dateEdit")
# 设置日期显示格式
self.dateEdit.setDisplayFormat('yyyy-MM-dd')
# 设置允许日历控件弹出
self.dateEdit.setCalendarPopup(True)
# 当日期改变时触发槽函数
self.dateEdit.dateChanged.connect(self.onTimeChanged)
事業者コード
def onTimeChanged(self,time):
birthtime = time
print(birthtime)
現在時刻を取得して表示する
# 获取当前时间
testTime = datetime.datetime.now().strftime('%Y-%m-%d')
# 回传子页面 setText设置输入框显示值
self.lineEdit_TestTime.setText(testTime)
print(testTime)
カレンダー選択の日付範囲を設定する
# 设置日期范围
self.dateEdit.setMinimumDate(QDate.currentDate().addDays(-365*10))
self.dateEdit.setMaximumDate(QDate.currentDate().addDays(0))
スタックデザイン
Stacked Widget については、上記の記事を参照してください。主な注意事項は次のとおりです。
信号とスロット
# 建立堆叠布局信号与槽连接
self.pushButton_Sports.clicked.connect(self.frameController)
self.pushButton_Social.clicked.connect(self.frameController)
self.pushButton_Iq.clicked.connect(self.frameController)
シグナルとスロット作成のコードがボタン作成コードの前にあると
AttributeError: 'AppMainWindow' object has no attribute 'pushButton_Sports'
エラーが発生します
ウィンドウ適応画面サイズ
グリッドレイアウトに関して、グリッド線は自動生成されません
qt-designer はカスタム画像を追加します
この記事
を参照して、
pyrcc5 -o re_rc.py 独自のリソース ファイル名.qrcを変換してください。
ビジネス層
トラバースしてチェックボックスの状態を取得し、スコア計算に変換する
シーンの再現: 上に示したように、たくさんのチェック ボックスがあり、チェック ボックスの選択状態を順番に取得したいのですが、各 checkBox には一意の名前があり、その形式は通常 checkBox_XXX ( xxx は数字です). この命名方法は、トラバーサルに便利です。
この回答を参照してください。オブジェクト名の代わりに文字列を取得するため、従来の for ループ + オブジェクト文字列の結合は実現できません。 **getattr を使用します。 ()** checkBOX オブジェクト名を生成するメソッド
# 这里的self是页面父类-主窗口
try:
# 针对运动表,判断其最后一个得分项
for i in range(1, 31):
# 遍历checkBox对象
m = getattr(self, "checkBox_%d" % i)
if m.isChecked():
# print("checked" + m)
print("num" + str(i) + ": " + str(m.isChecked()))
sports_pass = i
print("the final score is:" + str(sports_pass))
except Exception as e:
print(e)
ここで説明したいのは、print(m)
オブジェクトの名前を入力しようとすると、エラーが報告されるということです。エラー メッセージはおそらく次のようになります:
QCheckBox ではなく、str である必要があります(これが例外がキャッチされる理由でもあります) ).
ここの m はオブジェクト参照と見なすことができ、print 関数は文字列のみを出力できるため、ここでエラーを報告しても何も問題はありません。これが、一部の人が前の回答でエラーを報告する理由でもあると思います;
m を出力したい場合は、str(m) を使用すると、それが見つかります これはオブジェクトですが、アドレスを出力する必要がありますか?
docx レポート テンプレートを生成する
辞書(zip)
主に比較と置換のためのキーワード辞書を生成するために使用されます。
py-docx スリーパーティ ライブラリ
指定した場所にファイルを保存します (ファイルの保存ダイアログが表示されます)。
pyqt5 はすでにファイル リソース ダイアログ、つまり getSaveFileName を提供しています。
filepath, type = QFileDialog.getSaveFileName(self, '报告保存', '/'+ '%s_报告单.docx' % model, 'docx(*.docx)')
# '报告保存' 是对话框的标题,中间那一长串是保存的路径,后面是默认保存位置
# 这里我是根据患者测试时间和姓名 默认给出了文件名字,使用%s 占位符 将字符串model和 路径以及后缀名拼接
doc_t.save(filepath)
# 再使用doc_t.save将文件保存至指定filepath
レポートを生成し、完全なコードを指定されたパスに保存します
予防
保存ダイアログを開いた後、保存をキャンセルするとプログラムは空のパス ('') を返し、このときエラーが報告されるため、プログラムのパスが空かどうかを判断する必要があります。
import datetime
import docx
from PyQt5.QtWidgets import QFileDialog
def createReport(self,list):
try:
# 需制作缴费通知单数据
report_data = list
# print(list)
# 模板内设置的标志:
tags_1 = ['name','id','gender','birthday','preweek','testdate','months','sports',
'social','intel','min','mi','dqn','dq','advice']
# print(report_data)
# 生成字典类型的数据集
notice_dict = dict(zip(tags_1, report_data))
# print(notice_dict)
doc_t, runs_t = get_runs('报告模板.docx')
# 遍历模板run对象 和 notice_dict key 匹配
# 匹配成功则替换 run 内容
for run_t in runs_t:
if run_t.text in notice_dict.keys():
run_t.text = str(notice_dict[run_t.text])
#生成格式化文件名
model = datetime.datetime.now().strftime('%Y%m%d') + '_'+ list[0]
# 文件保存路径
save_doc(self,doc_t,model)
except Exception as e:
print(e)
# 定义获取 word 模板正文段落、表格 run 对象函数
def get_runs(path):
doc = docx.Document(path)
runs_g = []
# 获取段落 run 对象
# print(doc.paragraphs)
for par_g in doc.paragraphs:
for run_g in par_g.runs:
runs_g.append(run_g)
# print(run_g.text)
# # 获取表格 run 对象
# table_g = doc.tables[0]
# for cell_g in table_g._cells:
# for cell_par_g in cell_g.paragraphs:
# for cell_run_g in cell_par_g.runs:
# runs_g.append(cell_run_g)
# print(cell_run_g.text)
return doc, runs_g
# 文件保存路径
def save_doc(self,doc_t,model):
filepath, type = QFileDialog.getSaveFileName(self, '文件保存', '/'+ '%s_报告单.docx' % model, 'docx(*.docx)')
print(filepath)
doc_t.save(filepath)
#
メニューバーをクリックしてヘルプドキュメントをポップアップ表示します
def trigger_helpDoc(self):
webbrowser.open('Help.pdf', new=1)
最近保存したパスを開く
外部の Word/WPS ソフトウェアを使用して生成されたドキュメントをプレビューする
インターネットでたくさん検索しましたが、そのほとんどは Word インターフェイスを呼び出し、Pyqt フレームワークでドキュメントを表示します。ここでの要件は、Python を使用して外部ソフトウェアを呼び出し、対応するソフトウェアでドキュメントを開くことです。pywin32com ライブラリを使用します
。pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pypiwin32
from win32com.client import Dispatch
# 这里定义了打开的程序接口
app = Dispatch('Word.Application')
# 这里是打开文件的路径
app.Documents.Open(self.pathtemp)
# 设置word文件可见
app.Visible = True
time.sleep(0.5)
ここには問題があります。レポートは生成され保存された後でのみプレビューできるということです。レポートを保存する前にプレビューしたいのですが、失敗します。
# 具体过程参见前面的 docx文件生成并保存
doc_t, runs_t = get_runs('报告模板.docx')
app.Documents.Open(doc_t)
ソフトウェアのパッケージ化
スペック構成ファイルについて
UPXは利用できません
「.png」ファイルを「.ico」に変換して、再試行してください。
exe.notan実行可能ファイル
実行不可能なファイルを生成する
アイコン ファイル \image\logo.ico を開けません
1. アイコンのサイズが間違っていることがわかります 16*16
2. ico ファイルのパスが \image\logo.ico ではなく image\logo.ico になっています
アイコンが消える
アイコンファイルをexe実行ファイルにコピーする必要があります。
pyinstaller パッケージ ファイルが大きすぎます
Pipenvを使用する
この記事は、pyinstaller XXX.spec
構成ファイルを使用して、pipenv 環境でプログラムを出力するというyyds の提案です。私のソフトウェアは、元の 200M から 40M に縮小しました。
PyQt5のインストールに失敗しました
pip install PyQt5-sip== 12.9.1 を直接インストールし
、PyQt5 を正常にインストールします
リソースファイルとexeの2次パッケージ化
パッケージ化前のリソース ファイルは、非常に低い位置にあるフォルダーの下にすべて散在していることがわかります。Winrar
で 2 回目のパッケージ化を行うと、ファイルは全体になります。
Winrar を使用して
記事 2 を参照
してください。ただし、パッケージ化後にアイコンを変更できません。後で、これは Winrar のバージョンの問題であることがわかり、アイコンを変更するオプションがありませんでした。
Qの質問のまとめ
Python の問題: 'Nonetype' オブジェクトは反復可能ではありません
ここでは関数は一般的に定義されていますが、戻り値は与えられていません
データのトークン化エラー。C エラー: 3 行目に 1 フィールドが予期されていましたが、2 が表示されました
これは機能しません。
後でわかりましたが、それが .xlsx ドキュメントを .csv に直接変更した理由でした
ModuleNotFoundError: 「例外」という名前のモジュールがありません
pydocx で段落を走査するが、一部の部分がスキップされることについて
以下の図のトレーニング提案のアドバイス フィールドは論理的に置き換える必要があります。
def get_runs(path):
doc = docx.Document(path)
runs_g = []
# 获取段落 run 对象
print(doc.paragraphs)
for par_g in doc.paragraphs:
for run_g in par_g.runs:
runs_g.append(run_g)
print(run_g.text)
# 获取表格 run 对象
# table_g = doc.tables[0]
# for cell_g in table_g._cells:
# for cell_par_g in cell_g.paragraphs:
# for cell_run_g in cell_par_g.runs:
# runs_g.append(cell_run_g)
return doc, runs_g
問題を見つけるために、トラバーサル プロセスを出力します。特定のコンテンツを出力するには run_g.text メソッドを使用する必要があることに注意してください。それ以外の場合は、オブジェクト アドレスを出力するだけです。出力後、最後の処理が行われたことがわかります
。得られるのはアドバイスです。つまり、アドバイスが分離されています。最終的な置換では、対応するキーワードが見つかりませんでした。解決策は、アドバイスと
キーワードをテンプレートに入力してプログラムを再度実行することです。わかりません。なぜこの問題があるのでしょうか? ? ? 形而上学?? ?