PyQt5设计思路(长期更新,每写⼀篇新博客都会更新⼀次)概述
⽬前有关于PyQt5的系统的教程较少,毕竟Python的主要⽤途也不是做图形界⾯。但是鉴于作者最近想将很多的感兴趣的研究成果打包到⼀个应⽤⾥展⽰,⽽这些成果移植到Python会具有很强的可读性,所以就产⽣了⽤PyQt5来做GUI的念头。不过作者虽然听说Python的⼤名很多年,但是认真的⽤Python做⼀个稍复杂规模的应⽤还是第⼀回,制作过程中很多地⽅都是参考⽤其他语⾔做GUI Projct的经验和
Qt(C++)的官⽅⽂档,或者⼲脆⾃⼰摸索出来的。
本应⽤是作者秉持“可扩展+最⼤程度降低重复代码”的理念制作完成的。
设计⽬标
为了便于后续对代码的修改管理,在设计最初就应该定好⼀个合理的框架。为了做到这点,作者个⼈认为有以下⼏点是必须要遵守的。
1) 禁⽌组件的个性化命名。这点是很重要的,虽然将某个按钮按照它调⽤的函数来做相关的命名后,在Debug的时候是很容易修正⼀些逻辑设计上的问题的。但是当应⽤越做越⼤的时候,个性化的命名会“锁住”你的设计框架,从⽽在⼈们想要修改设计思路的时候,感到如陷泥沼般的困难。
2) 设计⼀个函数来批量的”new”你的组件,将你的组件和数据统⼀放到⼀个“容器”⾥,对组件和数据来说这个容器是字典较为合适,⽽字典的最底层往往是⼀个列表较为合适。
3) ⽤属性来代替global变量,毕竟global变量总给⼈⼀种很不⼯整的感觉。
4) 设计每⼀个页⾯的时候只写布局和指定每个控件信号对应的槽。
5) 尽量避免定时器的使⽤。
6) 将⿏标和键盘绑定在和菜单相关的对象上,⽽⾮窗体对象本⾝。
设计框架
1) 设计⼀个⽗类,其中包含存储控件和全局变量的容器。
2) 设计⼀个函数统⼀管理action。
3) 设计⼀个函数统⼀管理menu Bar。
4) 设计⼀个函数,使得该函数针对同类型和槽函数均相同的组件可以批量创建。
5) 设计⼀个函数,使得该函数可以⾃动读取存储的数据,并且根据读取的内容调整相关的控件的各种参数。
5) 针对每⼀个页⾯,设计⼀个函数来进⾏布局和指定每个控件信号对应的槽。
6) 针对每⼀个页⾯,设计⼀个函数来写⾃定义槽。
6) 设计⼀个代数模块来统⼀管理⾃定义的代数计算相关的类。
7) 设计⼀个画布模块来统⼀管理后台的即时动画计算和静态图形的绘制。
代码(框架分部)
容器:
1#!/usr/bin/python
2
3
4class MainData:
元旦高速2023免费吗5"""
6 frame of page data about PyQt5
7"""
8
9def__init__(self):
10 self.action = dict()
11 self.canvas = dict()
12 l = {"QLabel": [], "QTabWidget": [], "QPushButton": [], "QTextEdit": [],
13"QRadioButton": [], "QComboBox": [], "QSpinBox": [], "QTableWidget": [], "QLCDNumber": []}
14 lData = dict()
15
16def controlClear(self):
17"""
18 remove all the controls except menuBar before open a new page
19"""
20 l = {"QLabel": [], "QTabWidget": [], "QPushButton": [], "QTextEdit": [], 21"QRadioButton": [], "QComboBox": [], "QSpinBox": [], "QTableWidget": [], "QLCDNumber": []} 22
23def addFrame(self, imageName):
24"""
25 add a empty dictionary to record page data
26"""
27 lData[imageName] = dict()
28 lData[imageName]["QRadioButton"] = {"isChecked": []}
29 lData[imageName]["QComboBox"] = {"itemText": [], "currentIndex": []}
30 lData[imageName]["QSpinBox"] = {"value": []}
31 lData[imageName]["QTableWidget"] = {"data": []}
32 lData[imageName]["QLCDNumber"] = {"value": []}
33 lData[imageName]["save"] = []
34
35def controlDataClear(self, imageName):
36"""
37 remove data before refresh current page
38"""
39 lData[imageName]["QRadioButton"]["isChecked"] = []
40 lData[imageName]["QComboBox"]["itemText"] = []
41 lData[imageName]["QComboBox"]["currentIndex"] = []
42 lData[imageName]["QSpinBox"]["value"] = []
43 lData[imageName]["QTableWidget"]["data"] = []
44 lData[imageName]["QLCDNumber"]["value"] = []
45 lData[imageName]["save"] = []
MainData
窗体:
1#!/usr/bin/python
2# coding=utf-8
3
4from__future__import division
5from MainData import MainData
6from CanvasManager import *
7from AlgorithmManager import *
8from PyQt5.QtCore import Qt
9from PyQt5.QtGui import (QIcon, QFont)
10from PyQt5.QtWidgets import (qApp,
11 QAction,
12 QComboBox,
13 QDesktopWidget,
14 QFileDialog,
15 QGridLayout,
16 QInputDialog,
17 QRadioButton,
18 QLabel,
19 QLCDNumber,
20 QMainWindow,
21 QMessageBox,
22 QPushButton,
23 QSpinBox,
24 QTableWidget,
25 QTableWidgetItem,
26 QTabWidget,
27 QTextEdit,
28 QToolTip,
29 QWidget)
30
31
32# noinspection PyNonAsciiChar
33class App(QMainWindow, MainData):
34"""
35 @
36"""
37
38# noinspection PyArgumentList,PyMissingConstructor
39def__init__(self):
40# noinspection PyCompatibility
41 QMainWindow.__init__(self)
42
43# noinspection PyCallByClass,PyTypeChecker
44 QToolTip.setFont(QFont('SansSerif', 10))
45 self.setGeometry(100, 100, 900, 550)
46 qr = self.frameGeometry()
47 cp = QDesktopWidget().availableGeometry().center()
48 qr.moveCenter(cp)
49 pLeft())
50 self.setWindowTitle('MathDemo')
51 self.setWindowIcon(QIcon('python.png'))
52 self.setWindowFlags(Qt.WindowStaysOnTopHint)
如何格式化53
54 self.actionLoad()
55
56 uBarLoad()
57
58>>>>>>>>>
59# set current image that you are operating. #
60>>>>>>>>>
61 self.currentImage = ""
62 self.rainImage()
63
64 self.statusBar().showMessage('Ready')
65
66 self.show()
67
68def actionLoad(self):
69"""
70 set MainData.action
71"""
72
73 self.action["showOpenDialog"] = QAction('Open File', self)
74 self.action["showOpenDialog"].setIcon(QIcon('open.png'))
75 self.action["showOpenDialog"].setShortcut('Ctrl+O')
76 self.action["showOpenDialog"].setStatusTip('Open File')
77 self.action["showOpenDialog"].t(self.showOpenDialog)
78
79 self.action["qApp.quit"] = QAction('Exit application', self)
80 self.action["qApp.quit"].setIcon(QIcon('exit.jpg'))
81 self.action["qApp.quit"].setShortcut('Ctrl+Q')
82 self.action["qApp.quit"].setStatusTip('Exit application')
83 self.action["qApp.quit"].t(qApp.quit)
84
85 self.action["orthogonalTableImage"] = QAction('Orthogonal Table', self)
86 self.action["orthogonalTableImage"].setIcon(QIcon('numpy_logo.jpg'))
87 self.action["orthogonalTableImage"].setShortcut('Ctrl+T')
88 self.action["orthogonalTableImage"].setStatusTip('Orthogonal Table')
89 self.action["orthogonalTableImage"].hogonalTableImage)
遗忘保卫者在哪换
90
91 self.action["convexHullImage"] = QAction('Convex Hull', self)
92 self.action["convexHullImage"].setIcon(QIcon('numpy_logo.jpg'))
93 self.action["convexHullImage"].setShortcut('Ctrl+C')
94 self.action["convexHullImage"].setStatusTip('Convex Hull')
95 self.action["convexHullImage"].vexHullImage)
96
97 self.action["gravitationalSystemImage"] = QAction('Gravitational System', self)
98 self.action["gravitationalSystemImage"].setIcon(QIcon('scipy_logo.jpg'))
99 self.action["gravitationalSystemImage"].setShortcut('Ctrl+G')
100 self.action["gravitationalSystemImage"].setStatusTip('Gravitational System')
101 self.action["gravitationalSystemImage"].avitationalSystemImage) 102
103 self.action["analyticFunctionImage"] = QAction('Analytic Function', self)
104 self.action["analyticFunctionImage"].setIcon(QIcon('numpy_logo.jpg'))
105 self.action["analyticFunctionImage"].setShortcut('Ctrl+A')
106 self.action["analyticFunctionImage"].setStatusTip('Analytic Function')
107 self.action["analyticFunctionImage"].t(self.analyticFunctionImage)
108
109 self.action["sourceCodeImage"] = QAction('Source Code', self)
110 self.action["sourceCodeImage"].setShortcut('F2')
111 self.action["sourceCodeImage"].setStatusTip('Source Code')
112 self.action["sourceCodeImage"].t(self.sourceCodeImage)
113
114def menuBarLoad(self):
115"""
116 uBar
117"""
118 self.statusBar()
119 menubar = uBar()
120
121 fileMenu = menubar.addMenu('&File')
122 fileMenu.addAction(self.action["showOpenDialog"])
123 fileMenu.addAction(self.action["qApp.quit"])
124
125 statisticsMenu = menubar.addMenu('&Statistics')
126 statisticsMenu.addAction(self.action["orthogonalTableImage"])
127
128 statisticsMenu = menubar.addMenu('&Geometry')
129 statisticsMenu.addAction(self.action["convexHullImage"])
130
131 statisticsMenu = menubar.addMenu('&Ode')
132 statisticsMenu.addAction(self.action["gravitationalSystemImage"])
133
134 statisticsMenu = menubar.addMenu('&Complex')
135 statisticsMenu.addAction(self.action["analyticFunctionImage"])
136
137 statisticsMenu = menubar.addMenu('&Help')
138 statisticsMenu.addAction(self.action["sourceCodeImage"])
139
140def controlLayout(self, layout=None, name=None, var=None, position=None, signal=None):
141"""
142 control layout
143 :param layout: GridLayout = QGridLayout()
144 :param name: name of control, name is a string
145 :param var: var is a dict
146 :param position: position is a list with 4 numeric
147 :param signal: signal function
148"""
149if name == "QLabel":
150# var = {"text": [string]}
151for j in range(0, len(position)):
152 l[name].append(QLabel(var["text"][j]))
153 l[name][-1].setAlignment(Qt.AlignCenter)
154# noinspection PyArgumentList
155 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 156
157if name == "QTabWidget":
158# var = {"text": [[string]], "widget": [[PyQt5.QtWidgets.QWidget]]}
159for j in range(0, len(position)):
160 l[name].append(QTabWidget())
161for k in range(0, len(var["text"][j])):
162 l[name][-1].addTab(var["widget"][j][k], (var["text"][j][k]))
163# noinspection PyArgumentList
164 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 165
166if name == "QPushButton":
167# var = {"text": [string]}
168for j in range(0, len(position)):
169 l[name].append(QPushButton(var["text"][j]))
170# noinspection PyArgumentList
171 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 172if signal is not None:
173 l[name][-1].t(signal)
174
175if name == "QTextEdit":
176# var = {"text": [[string]]}
177for j in range(0, len(position)):
178 l[name].append(QTextEdit())
端敬皇后179if len(var["text"]) != 0:
180if len(var["text"][j]) != 0:
181for line in var["text"][j]:
182 l[name][-1].append(line)
183# noinspection PyArgumentList
184 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 185
186if name == "QRadioButton":
187# var = {"text": [string], "isChecked": [bool]}
188for j in range(0, len(position)):
189 l[name].append(QRadioButton(var["text"][j]))
190 l[name][-1].setChecked(var["isChecked"][j])
191# noinspection PyArgumentList
192 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 193if signal is not None:
194 l[name][-1].t(signal)
195
196if name == "QComboBox":
197# var = {"itemText": [[string]], "currentIndex": [int]}
198for j in range(0, len(position)):
199 l[name].append(QComboBox())
200 l[name][-1].addItems(var["itemText"][j])
201if len(var["currentIndex"]) != 0:
202 l[name][-1].setCurrentIndex(var["currentIndex"][j])
203# noinspection PyArgumentList
204 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 205if signal is not None:
206 l[name][-1].t(signal)
207
208if name == "QSpinBox":
209# var = {"range": [[int, int]], "singleStep": [int], "prefix": [string], "suffix": [string], "value": [int]}
210for j in range(0, len(position)):
211 l[name].append(QSpinBox())
212 l[name][-1].setRange(var["range"][j][0], var["range"][j][1])
213 l[name][-1].setSingleStep(var["singleStep"][j])
214if len(var["prefix"]) != 0:
215if len(var["prefix"][j]) != 0:
216 l[name][-1].setPrefix(var["prefix"][j])
217if len(var["suffix"]) != 0:
218if len(var["suffix"][j]) != 0:
219 l[name][-1].setSuffix(var["suffix"][j])
220 l[name][-1].setValue(var["value"][j])
221# noinspection PyArgumentList
222 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 223if signal is not None:
224 l[name][-1].t(signal)
225
226if name == "QTableWidget":
227# var = {"headerLabels": [[string]], "data": [numpy.array]}
228for i in range(0, len(position)):
229 l[name].append(QTableWidget(1, 1))
230if len(var["headerLabels"]) != 0:
231if len(var["headerLabels"][i]) != 0:
232 l[name][-1].setColumnCount(len(var["headerLabels"][i]))
233 l[name][-1].setHorizontalHeaderLabels(var["headerLabels"][i])
234if len(var["data"]) != 0:
235if len(var["data"][i]) != 0:
236 row, column = var["data"][i].shape
237 l[name][-1].setRowCount(row)
238 l[name][-1].setColumnCount(column)
239for j in range(0, row):
240for k in range(0, column):
241 newItem = QTableWidgetItem(str(var["data"][i][j][k]))怎么回qq密码
242 l[name][-1].setItem(j, k, newItem)
243 l[name][-1].resizeColumnsToContents()
244# noinspection PyArgumentList
245 layout.l[name][-1], position[i][0], position[i][1], position[i][2], position[i][3]) 246
247if name == "QLCDNumber":
248# var = {"value": [int]}
249for j in range(0, len(position)):
250 l[name].append(QLCDNumber(self))
251if len(var["value"]) != 0:
252if len(var["value"][j]) != 0:
253 l[name][-1].display(var["value"][j])
254else:
255 l[name][-1].display(0)
256# noinspection PyArgumentList
257 layout.l[name][-1], position[j][0], position[j][1], position[j][2], position[j][3]) 258
259def imageRead(self, imageName=None):
260"""
261 load data into current page, or write data from current page.
262"""
263if l["QRadioButton"]) != 0:
264 length = l["QRadioButton"])
265for j in range(0, length):
266 isChecked = lData[imageName]["QRadioButton"]["isChecked"][j]
267 l["QRadioButton"][j].setChecked(isChecked)
268
269if l["QComboBox"]) != 0:
270pass
271
272if l["QComboBox"]) != 0:
273 length = l["QComboBox"])
华为企业价值观274for j in range(0, length):
275 currentIndex = lData[imageName]["QComboBox"]["currentIndex"][j]
276 l["QComboBox"][j].setCurrentIndex(currentIndex)
277
278if l["QSpinBox"]) != 0:
279 length = l["QSpinBox"])
280for j in range(0, length):
281 value = lData[imageName]["QSpinBox"]["value"][j]
282 l["QSpinBox"][j].setValue(value)
283
284if l["QTableWidget"]) != 0:
285 length = l["QTableWidget"])
286for i in range(0, length):
287 data = lData[imageName]["QTableWidget"]["data"][i]
288 row, column = data.shape
289 l["QTableWidget"][i].setRowCount(row)
290 l["QTableWidget"][i].setColumnCount(column)
291for j in range(0, row):
292for k in range(0, column):
293 newItem = QTableWidgetItem(str(data[j][k]))
294 l["QTableWidget"][i].setItem(j, k, newItem)
295 l["QTableWidget"][i].resizeColumnsToContents()
296
297if l["QLCDNumber"]) != 0:
298 length = l["QLCDNumber"])
299for j in range(0, length):
300 value = lData[imageName]["QLCDNumber"]["value"][j]
301 l["QLCDNumber"][j].display(value)
302
303def rainImage(self):
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
创建目录与文件的命令【mkdir、touch】
« 上一篇
Ubuntu创建VLAN接口配置
下一篇 »
发表评论