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 
 4 class MainData:
 5     """
 6     frame of page data about PyQt5
 7     """
 8 
 9     def __init__(self):
10         self.action = dict()
11         self.canvas = dict()
12         self.control = {"QLabel": [], "QTabWidget": [], "QPushButton": [], "QTextEdit": [],
13                         "QRadioButton": [], "QComboBox": [], "QSpinBox": [], "QTableWidget": [], "QLCDNumber": []}
14         self.controlData = dict()
15 
16     def controlClear(self):
17         """
18         remove all the controls except menuBar before open a new page
19         """
20         self.control = {"QLabel": [], "QTabWidget": [], "QPushButton": [], "QTextEdit": [],
21                         "QRadioButton": [], "QComboBox": [], "QSpinBox": [], "QTableWidget": [], "QLCDNumber": []}
22 
23     def addFrame(self, imageName):
24         """
25         add a empty dictionary to record page data
26         """
27         self.controlData[imageName] = dict()
28         self.controlData[imageName]["QRadioButton"] = {"isChecked": []}
29         self.controlData[imageName]["QComboBox"] = {"itemText": [], "currentIndex": []}
30         self.controlData[imageName]["QSpinBox"] = {"value": []}
31         self.controlData[imageName]["QTableWidget"] = {"data": []}
32         self.controlData[imageName]["QLCDNumber"] = {"value": []}
33         self.controlData[imageName]["save"] = []
34 
35     def controlDataClear(self, imageName):
36         """
37         remove data  before refresh current page
38         """
39         self.controlData[imageName]["QRadioButton"]["isChecked"] = []
40         self.controlData[imageName]["QComboBox"]["itemText"] = []
41         self.controlData[imageName]["QComboBox"]["currentIndex"] = []
42         self.controlData[imageName]["QSpinBox"]["value"] = []
43         self.controlData[imageName]["QTableWidget"]["data"] = []
44         self.controlData[imageName]["QLCDNumber"]["value"] = []
45         self.controlData[imageName]["save"] = []
MainData

 窗体:

   1 #!/usr/bin/python
   2 # coding=utf-8
   3 
   4 from __future__ import division
   5 from MainData import MainData
   6 from CanvasManager import *
   7 from AlgorithmManager import *
   8 from PyQt5.QtCore import Qt
   9 from PyQt5.QtGui import (QIcon, QFont)
  10 from 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
  33 class App(QMainWindow, MainData):
  34     """
  35     @
  36     """
  37 
  38     # noinspection PyArgumentList,PyMissingConstructor
  39     def __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         self.move(qr.topLeft())
  50         self.setWindowTitle('MathDemo')
  51         self.setWindowIcon(QIcon('python.png'))
  52         self.setWindowFlags(Qt.WindowStaysOnTopHint)
  53 
  54         self.actionLoad()
  55 
  56         self.menuBarLoad()
  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 
  68     def 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"].triggered.connect(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"].triggered.connect(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"].triggered.connect(self.orthogonalTableImage)
  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"].triggered.connect(self.convexHullImage)
  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"].triggered.connect(self.gravitationalSystemImage)
 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"].triggered.connect(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"].triggered.connect(self.sourceCodeImage)
 113 
 114     def menuBarLoad(self):
 115         """
 116         set MainWindow.menuBar
 117         """
 118         self.statusBar()
 119         menubar = self.menuBar()
 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 
 140     def 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         """
 149         if name == "QLabel":
 150             # var = {"text": [string]}
 151             for j in range(0, len(position)):
 152                 self.control[name].append(QLabel(var["text"][j]))
 153                 self.control[name][-1].setAlignment(Qt.AlignCenter)
 154                 # noinspection PyArgumentList
 155                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 156 
 157         if name == "QTabWidget":
 158             # var = {"text": [[string]], "widget": [[PyQt5.QtWidgets.QWidget]]}
 159             for j in range(0, len(position)):
 160                 self.control[name].append(QTabWidget())
 161                 for k in range(0, len(var["text"][j])):
 162                     self.control[name][-1].addTab(var["widget"][j][k], self.tr(var["text"][j][k]))
 163                 # noinspection PyArgumentList
 164                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 165 
 166         if name == "QPushButton":
 167             # var = {"text": [string]}
 168             for j in range(0, len(position)):
 169                 self.control[name].append(QPushButton(var["text"][j]))
 170                 # noinspection PyArgumentList
 171                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 172                 if signal is not None:
 173                     self.control[name][-1].clicked.connect(signal)
 174 
 175         if name == "QTextEdit":
 176             # var = {"text": [[string]]}
 177             for j in range(0, len(position)):
 178                 self.control[name].append(QTextEdit())
 179                 if len(var["text"]) != 0:
 180                     if len(var["text"][j]) != 0:
 181                         for line in var["text"][j]:
 182                             self.control[name][-1].append(line)
 183                 # noinspection PyArgumentList
 184                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 185 
 186         if name == "QRadioButton":
 187             # var = {"text": [string], "isChecked": [bool]}
 188             for j in range(0, len(position)):
 189                 self.control[name].append(QRadioButton(var["text"][j]))
 190                 self.control[name][-1].setChecked(var["isChecked"][j])
 191                 # noinspection PyArgumentList
 192                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 193                 if signal is not None:
 194                     self.control[name][-1].clicked.connect(signal)
 195 
 196         if name == "QComboBox":
 197             # var = {"itemText": [[string]], "currentIndex": [int]}
 198             for j in range(0, len(position)):
 199                 self.control[name].append(QComboBox())
 200                 self.control[name][-1].addItems(var["itemText"][j])
 201                 if len(var["currentIndex"]) != 0:
 202                     self.control[name][-1].setCurrentIndex(var["currentIndex"][j])
 203                 # noinspection PyArgumentList
 204                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 205                 if signal is not None:
 206                     self.control[name][-1].currentIndexChanged.connect(signal)
 207 
 208         if name == "QSpinBox":
 209             # var = {"range": [[int, int]], "singleStep": [int], "prefix": [string], "suffix": [string], "value": [int]}
 210             for j in range(0, len(position)):
 211                 self.control[name].append(QSpinBox())
 212                 self.control[name][-1].setRange(var["range"][j][0], var["range"][j][1])
 213                 self.control[name][-1].setSingleStep(var["singleStep"][j])
 214                 if len(var["prefix"]) != 0:
 215                     if len(var["prefix"][j]) != 0:
 216                         self.control[name][-1].setPrefix(var["prefix"][j])
 217                 if len(var["suffix"]) != 0:
 218                     if len(var["suffix"][j]) != 0:
 219                         self.control[name][-1].setSuffix(var["suffix"][j])
 220                 self.control[name][-1].setValue(var["value"][j])
 221                 # noinspection PyArgumentList
 222                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 223                 if signal is not None:
 224                     self.control[name][-1].valueChanged.connect(signal)
 225 
 226         if name == "QTableWidget":
 227             # var = {"headerLabels": [[string]], "data": [numpy.array]}
 228             for i in range(0, len(position)):
 229                 self.control[name].append(QTableWidget(1, 1))
 230                 if len(var["headerLabels"]) != 0:
 231                     if len(var["headerLabels"][i]) != 0:
 232                         self.control[name][-1].setColumnCount(len(var["headerLabels"][i]))
 233                         self.control[name][-1].setHorizontalHeaderLabels(var["headerLabels"][i])
 234                 if len(var["data"]) != 0:
 235                     if len(var["data"][i]) != 0:
 236                         row, column = var["data"][i].shape
 237                         self.control[name][-1].setRowCount(row)
 238                         self.control[name][-1].setColumnCount(column)
 239                         for j in range(0, row):
 240                             for k in range(0, column):
 241                                 newItem = QTableWidgetItem(str(var["data"][i][j][k]))
 242                                 self.control[name][-1].setItem(j, k, newItem)
 243                 self.control[name][-1].resizeColumnsToContents()
 244                 # noinspection PyArgumentList
 245                 layout.addWidget(self.control[name][-1], position[i][0], position[i][1], position[i][2], position[i][3])
 246 
 247         if name == "QLCDNumber":
 248             # var = {"value": [int]}
 249             for j in range(0, len(position)):
 250                 self.control[name].append(QLCDNumber(self))
 251                 if len(var["value"]) != 0:
 252                     if len(var["value"][j]) != 0:
 253                         self.control[name][-1].display(var["value"][j])
 254                     else:
 255                         self.control[name][-1].display(0)
 256                 # noinspection PyArgumentList
 257                 layout.addWidget(self.control[name][-1], position[j][0], position[j][1], position[j][2], position[j][3])
 258 
 259     def imageRead(self, imageName=None):
 260         """
 261         load data into current page, or write data from current page.
 262         """
 263         if len(self.control["QRadioButton"]) != 0:
 264             length = len(self.control["QRadioButton"])
 265             for j in range(0, length):
 266                 isChecked = self.controlData[imageName]["QRadioButton"]["isChecked"][j]
 267                 self.control["QRadioButton"][j].setChecked(isChecked)
 268 
 269         if len(self.control["QComboBox"]) != 0:
 270             pass
 271 
 272         if len(self.control["QComboBox"]) != 0:
 273             length = len(self.control["QComboBox"])
 274             for j in range(0, length):
 275                 currentIndex = self.controlData[imageName]["QComboBox"]["currentIndex"][j]
 276                 self.control["QComboBox"][j].setCurrentIndex(currentIndex)
 277 
 278         if len(self.control["QSpinBox"]) != 0:
 279             length = len(self.control["QSpinBox"])
 280             for j in range(0, length):
 281                 value = self.controlData[imageName]["QSpinBox"]["value"][j]
 282                 self.control["QSpinBox"][j].setValue(value)
 283 
 284         if len(self.control["QTableWidget"]) != 0:
 285             length = len(self.control["QTableWidget"])
 286             for i in range(0, length):
 287                 data = self.controlData[imageName]["QTableWidget"]["data"][i]
 288                 row, column = data.shape
 289                 self.control["QTableWidget"][i].setRowCount(row)
 290                 self.control["QTableWidget"][i].setColumnCount(column)
 291                 for j in range(0, row):
 292                     for k in range(0, column):
 293                         newItem = QTableWidgetItem(str(data[j][k]))
 294                         self.control["QTableWidget"][i].setItem(j, k, newItem)
 295                 self.control["QTableWidget"][i].resizeColumnsToContents()
 296 
 297         if len(self.control["QLCDNumber"]) != 0:
 298             length = len(self.control["QLCDNumber"])
 299             for j in range(0, length):
 300                 value = self.controlData[imageName]["QLCDNumber"]["value"][j]
 301                 self.control["QLCDNumber"][j].display(value)
 302 
 303     def rainImage(self):
 304         """
 305         @
 306         """
 307         self.currentImage = "rainImage"
 308         self.controlClear()
 309 
 310         layout = QGridLayout()
 311         layout.setSpacing(10)
 312 
 313         # noinspection PyArgumentList
 314         widget = QWidget()
 315         self.canvas["rainImage"] = RainCanvas(parent=widget)
 316         layout.addWidget(self.canvas["rainImage"])
 317 
 318         widget.setLayout(layout)
 319         self.setCentralWidget(widget)
 320 
 321     def orthogonalTableImage(self):
 322         """
 323         layout and initialization data
 324         """
 325         ##########################
 326         # layout of current page #
 327         ##########################
 328         self.currentImage = "orthogonalTableImage"
 329         self.controlClear()
 330 
 331         layout = QGridLayout()
 332         layout.setSpacing(10)
 333 
 334         text = ['水平数', '重复次数', '实验次数', '因素数']
 335         position = [[0, 0, 1, 1], [0, 2, 1, 1], [0, 4, 1, 1], [0, 6, 1, 1]]
 336         self.controlLayout(layout=layout, name="QLabel", var={"text": text}, position=position, signal=None)
 337 
 338         itemText = [list(map(str, range(2, 10))), list(map(str, range(0, 10)))]
 339         position = [[0, 1, 1, 1], [0, 3, 1, 1]]
 340         self.controlLayout(layout=layout, name="QComboBox", var={"itemText": itemText, "currentIndex": []},
 341                            position=position, signal=self.orthogonalTableImageSignal)
 342 
 343         position = [[0, 5, 1, 1], [0, 7, 1, 1]]
 344         self.controlLayout(layout=layout, name="QLCDNumber", var={"value": []}, position=position, signal=None)
 345 
 346         # noinspection PyArgumentList
 347         widget = [[QWidget(), QWidget()]]
 348         for j in range(0, 2):
 349             widgetLayout = QGridLayout()
 350             position = [[0, 0, 1, 1]]
 351             self.controlLayout(layout=widgetLayout, name="QTableWidget", var={"headerLabels": [], "data": []},
 352                                position=position, signal=None)
 353             widget[0][j].setLayout(widgetLayout)
 354         text = [["Table", "Title"]]
 355         position = [[1, 0, 1, 8]]
 356         self.controlLayout(layout=layout, name="QTabWidget", var={"text": text, "widget": widget},
 357                            position=position, signal=None)
 358 
 359         # noinspection PyArgumentList
 360         widget = QWidget()
 361         widget.setLayout(layout)
 362         self.setCentralWidget(widget)
 363 
 364         ###########################################################################
 365         # initialization self.controlData["orthogonalTableImage"] then refresh it #
 366         # refresh self.control["orthogonalTableImage"]                            #
 367         ###########################################################################
 368         if "orthogonalTableImage" not in self.controlData:
 369             self.addFrame("orthogonalTableImage")
 370             self.orthogonalTableImageSignal()
 371         else:
 372             for j in range(0, len(self.control["QComboBox"])):
 373                 self.control["QComboBox"][j].currentIndexChanged.disconnect(self.orthogonalTableImageSignal)
 374             self.imageRead(imageName="orthogonalTableImage")
 375             for j in range(0, len(self.control["QComboBox"])):
 376                 self.control["QComboBox"][j].currentIndexChanged.connect(self.orthogonalTableImageSignal)
 377 
 378         self.statusBar().showMessage('Ready')
 379 
 380     def orthogonalTableImageSignal(self):
 381         """
 382         respond of current page(orthogonalTableImage), then write data into MainData.controlData
 383         """
 384         self.statusBar().showMessage('Starting generate table and title...')
 385 
 386         ###########################################################
 387         # initialization self.controlData["orthogonalTableImage"] #
 388         ###########################################################
 389         imageName = "orthogonalTableImage"
 390         self.controlDataClear(imageName)
 391 
 392         ####################################################
 393         # refresh self.controlData["orthogonalTableImage"] #
 394         ####################################################
 395         for j in range(0, len(self.control["QComboBox"])):
 396             itemText = list()
 397             for k in range(0, self.control["QComboBox"][j].count()):
 398                 itemText.append(self.control["QComboBox"][j].itemText(k))
 399             self.controlData[imageName]["QComboBox"]["itemText"].append(itemText)
 400 
 401             currentIndex = self.control["QComboBox"][j].currentIndex()
 402             self.controlData[imageName]["QComboBox"]["currentIndex"].append(currentIndex)
 403 
 404         level = int(self.control["QComboBox"][0].currentText())
 405         time = int(self.control["QComboBox"][1].currentText())
 406         obj = OrthogonalTableMap(level, time)
 407         row, column = obj.table.shape
 408 
 409         self.controlData[imageName]["QLCDNumber"]["value"].append(row)
 410         self.controlData[imageName]["QLCDNumber"]["value"].append(column)
 411 
 412         self.controlData[imageName]["QTableWidget"]["data"].append(obj.table)
 413         self.controlData[imageName]["QTableWidget"]["data"].append(obj.title)
 414 
 415         self.controlData[imageName]["save"] = [level, time, obj.table, obj.title]
 416 
 417         ################################################
 418         # refresh self.control["orthogonalTableImage"] #
 419         ################################################
 420         for j in range(0, len(self.control["QComboBox"])):
 421             self.control["QComboBox"][j].currentIndexChanged.disconnect(self.orthogonalTableImageSignal)
 422         self.imageRead(imageName=imageName)
 423         for j in range(0, len(self.control["QComboBox"])):
 424             self.control["QComboBox"][j].currentIndexChanged.connect(self.orthogonalTableImageSignal)
 425 
 426         if obj.error == 1:
 427             self.statusBar().showMessage('Unable to generate title.')
 428         else:
 429             self.statusBar().showMessage('Table and title generated.')
 430 
 431     def gravitationalSystemImage(self):
 432         """
 433         layout and initialization data
 434         """
 435         ##########################
 436         # layout of current page #
 437         ##########################
 438         self.currentImage = "gravitationalSystemImage"
 439         self.controlClear()
 440 
 441         layout = QGridLayout()
 442         layout.setSpacing(10)
 443 
 444         text = ['长度单位', '时间单位', '质量单位', '电量单位',
 445                 '质点类型', '质点个数', '动画时长', '总帧数', '播放速率',
 446                 '坐标轴标签', '视角', '速度矢量', '加速度矢量']
 447         position = [[0, 0, 1, 1], [0, 1, 1, 1], [0, 2, 1, 1], [0, 3, 1, 1],
 448                     [0, 4, 1, 1], [0, 5, 1, 1], [0, 6, 1, 1], [2, 0, 1, 1], [2, 1, 1, 1],
 449                     [2, 2, 1, 1], [2, 3, 1, 1], [2, 4, 1, 1], [2, 5, 1, 1]]
 450         self.controlLayout(layout=layout, name="QLabel", var={"text": text}, position=position, signal=None)
 451 
 452         itemText = [['ly', 'km', 'm', 'mm', 'nm'], ['year', 'day', 's', 'ms', 'μs'],
 453                     ['kg', '太阳(1.99+e30kg)', '质子(1.7-e27kg)', '电子(9.1-e31kg)'], ['C', 'e(1.6-e19C)'],
 454                     ['天体-天体', '电荷-电荷', '自定义-自定义'], list(map(str, range(2, 10))),
 455                     list(map(str, range(5, 65, 5))), ['100', '1000', '10000', '100000'],
 456                     ['显示', '隐藏'], ['静止', '旋转'], ['隐藏速度矢量', '显示当前速度矢量', '显示所有速度矢量'],
 457                     ['隐藏加速度矢量', '显示当前加速度矢量', '显示所有加速度矢量']]
 458         currentIndex = [2, 2, 0, 0, 2, 1, 2, 2, 0, 1, 1, 1]
 459         position = [[1, 0, 1, 1], [1, 1, 1, 1], [1, 2, 1, 1], [1, 3, 1, 1],
 460                     [1, 4, 1, 1], [1, 5, 1, 1], [1, 6, 1, 1], [3, 0, 1, 1],
 461                     [3, 2, 1, 1], [3, 3, 1, 1], [3, 4, 1, 1], [3, 5, 1, 1]]
 462         self.controlLayout(layout=layout, name="QComboBox", var={"itemText": itemText, "currentIndex": currentIndex},
 463                            position=position, signal=self.gravitationalSystemImageSignal)
 464 
 465         var = {"range": [[1, 1000]], "singleStep": [1], "prefix": ['X  '], "suffix": [""], "value": [100]}
 466         position = [[3, 1, 1, 1]]
 467         self.controlLayout(layout=layout, name="QSpinBox", var=var,
 468                            position=position, signal=self.gravitationalSystemImageSignal)
 469 
 470         text = ['启用调试单位']
 471         isChecked = [True]
 472         position = [[2, 6, 1, 1]]
 473         self.controlLayout(layout=layout, name="QRadioButton", var={"text": text, "isChecked": isChecked},
 474                            position=position, signal=self.gravitationalSystemImageSignal)
 475 
 476         text = ['播放动画']
 477         position = [[3, 6, 1, 1]]
 478         self.controlLayout(layout=layout, name="QPushButton", var={"text": text},
 479                            position=position, signal=self.gravitationalSystemImageDraw)
 480 
 481         # noinspection PyArgumentList
 482         widget = [[QWidget(), QWidget()]]
 483         name = ["QTableWidget", "QTextEdit"]
 484         var = [{"headerLabels": [["mass", "electricity", "X-coordinate", "Y-coordinate", "Z-coordinate",
 485                                   "X-velocity", "Y-velocity", "Z-velocity"]],
 486                 "data": [numpy.array([[1, 0, 1, 0, 0, 0, 1, 0],
 487                                       [1, 1, 0, 1, 0, 0, 0, 1],
 488                                       [1, -1, 0, 0, 1, 1, 0, 0]])]},
 489                {"text": [["yes", "no"]]}]
 490         for j in range(0, 2):
 491             widgetLayout = QGridLayout()
 492             position = [[0, 0, 1, 1]]
 493             self.controlLayout(layout=widgetLayout, name=name[j], var=var[j], position=position, signal=None)
 494             widget[0][j].setLayout(widgetLayout)
 495         text = [["Initial Condition", "Note"]]
 496         position = [[4, 0, 1, 7]]
 497         self.controlLayout(layout=layout, name="QTabWidget", var={"text": text, "widget": widget},
 498                            position=position, signal=None)
 499 
 500         # noinspection PyArgumentList
 501         widget = QWidget()
 502         widget.setLayout(layout)
 503         self.setCentralWidget(widget)
 504 
 505         ###############################################################################
 506         # initialization self.controlData["gravitationalSystemImage"] then refresh it #
 507         # refresh self.control["gravitationalSystemImage"]                            #
 508         ###############################################################################
 509         if "gravitationalSystemImage" not in self.controlData:
 510             self.addFrame("gravitationalSystemImage")
 511             self.gravitationalSystemImageSignal()
 512         else:
 513             for j in range(0, len(self.control["QComboBox"])):
 514                 self.control["QComboBox"][j].currentIndexChanged.disconnect(self.gravitationalSystemImageSignal)
 515             for j in range(0, len(self.control["QSpinBox"])):
 516                 self.control["QSpinBox"][j].valueChanged.disconnect(self.gravitationalSystemImageSignal)
 517             for j in range(0, len(self.control["QRadioButton"])):
 518                 self.control["QRadioButton"][j].clicked.disconnect(self.gravitationalSystemImageSignal)
 519             self.imageRead(imageName="gravitationalSystemImage")
 520             for j in range(0, len(self.control["QComboBox"])):
 521                 self.control["QComboBox"][j].currentIndexChanged.connect(self.gravitationalSystemImageSignal)
 522             for j in range(0, len(self.control["QSpinBox"])):
 523                 self.control["QSpinBox"][j].valueChanged.connect(self.gravitationalSystemImageSignal)
 524             for j in range(0, len(self.control["QRadioButton"])):
 525                 self.control["QRadioButton"][j].clicked.connect(self.gravitationalSystemImageSignal)
 526 
 527         self.statusBar().showMessage('Ready')
 528 
 529     def gravitationalSystemImageSignal(self):
 530         """
 531         respond of current page(gravitationalSystemImage), then write data into MainData.dataClasses
 532         """
 533         self.statusBar().showMessage('Saving Page data...')
 534 
 535         ###############################################################
 536         # initialization self.controlData["gravitationalSystemImage"] #
 537         ###############################################################
 538         imageName = "gravitationalSystemImage"
 539         self.controlDataClear(imageName)
 540 
 541         ########################################################
 542         # refresh self.controlData["gravitationalSystemImage"] #
 543         ########################################################
 544         for j in range(0, len(self.control["QComboBox"])):
 545             itemText = list()
 546             for k in range(0, self.control["QComboBox"][j].count()):
 547                 itemText.append(self.control["QComboBox"][j].itemText(k))
 548             self.controlData[imageName]["QComboBox"]["itemText"].append(itemText)
 549 
 550             currentIndex = self.control["QComboBox"][j].currentIndex()
 551             self.controlData[imageName]["QComboBox"]["currentIndex"].append(currentIndex)
 552 
 553         for i in range(0, len(self.control["QTableWidget"])):
 554             currentRow = self.control["QTableWidget"][i].rowCount()
 555             row = int(self.control["QComboBox"][5].currentText())
 556             column = self.control["QTableWidget"][i].columnCount()
 557             data = numpy.zeros((row, column), dtype=numpy.float64)
 558             for j in range(0, row):
 559                 for k in range(0, column):
 560                     if j < currentRow:
 561                         # noinspection PyBroadException
 562                         try:
 563                             data[j][k] = float(self.control["QTableWidget"][i].item(j, k).text())
 564                         except:
 565                             data[j][k] = 0
 566             self.controlData[imageName]["QTableWidget"]["data"].append(data)
 567 
 568         for j in range(0, len(self.control["QSpinBox"])):
 569             value = self.control["QSpinBox"][j].value()
 570             self.controlData[imageName]["QSpinBox"]["value"].append(value)
 571 
 572         for j in range(0, len(self.control["QRadioButton"])):
 573             isChecked = self.control["QRadioButton"][j].isChecked()
 574             self.controlData[imageName]["QRadioButton"]["isChecked"].append(isChecked)
 575 
 576         ####################################################
 577         # refresh self.control["gravitationalSystemImage"] #
 578         ####################################################
 579         for j in range(0, len(self.control["QComboBox"])):
 580             self.control["QComboBox"][j].currentIndexChanged.disconnect(self.gravitationalSystemImageSignal)
 581         for j in range(0, len(self.control["QSpinBox"])):
 582             self.control["QSpinBox"][j].valueChanged.disconnect(self.gravitationalSystemImageSignal)
 583         for j in range(0, len(self.control["QRadioButton"])):
 584             self.control["QRadioButton"][j].clicked.disconnect(self.gravitationalSystemImageSignal)
 585         self.imageRead(imageName="gravitationalSystemImage")
 586         for j in range(0, len(self.control["QComboBox"])):
 587             self.control["QComboBox"][j].currentIndexChanged.connect(self.gravitationalSystemImageSignal)
 588         for j in range(0, len(self.control["QSpinBox"])):
 589             self.control["QSpinBox"][j].valueChanged.connect(self.gravitationalSystemImageSignal)
 590         for j in range(0, len(self.control["QRadioButton"])):
 591             self.control["QRadioButton"][j].clicked.connect(self.gravitationalSystemImageSignal)
 592 
 593         self.statusBar().showMessage('Page data Saved.')
 594 
 595     def gravitationalSystemImageDraw(self):
 596         """
 597         Draw animation of solution of ordinary differential equations
 598         """
 599         ########################################################
 600         # refresh self.controlData["gravitationalSystemImage"] #
 601         ########################################################
 602         self.gravitationalSystemImageSignal()
 603         self.statusBar().showMessage('Start to solving the ordinary differential equations...')
 604 
 605         #####################################################
 606         # get parameters of ordinary differential equations #
 607         #####################################################
 608         imageName = "gravitationalSystemImage"
 609         aniArg = self.controlData[imageName]["QComboBox"]["currentIndex"][8:]
 610 
 611         data = self.controlData[imageName]["QTableWidget"]["data"][0]
 612         mass = data[:, 0]
 613         for j in range(0, len(mass)):
 614             if mass[j] < 0 or mass[j] == 0:
 615                 self.statusBar().showMessage('mass[%d] must be positive.' % j)
 616                 return
 617 
 618         electric = numpy.abs(data[:, 1])
 619 
 620         electricType = numpy.sign(data[:, 1])
 621 
 622         cood = data[:, 2:5]
 623         coodCheck = numpy.dot(cood, cood.T)
 624         for j in range(0, len(mass)):
 625             for k in range(j, len(mass)):
 626                 if (coodCheck[j, j] + coodCheck[k, k]) == 2 * coodCheck[j, k] and j != k:
 627                     self.statusBar().showMessage('point[%d] and point[%d] share the same coordinate.' % (j, k))
 628                     return
 629 
 630         vel = data[:, 5:]
 631 
 632         if self.controlData[imageName]["QRadioButton"]["isChecked"][0]:
 633             GUnit = 1
 634             KUnit = 1
 635         else:
 636             lenUnitMap = {0: 9.46 * 10 ** 15, 1: 1000, 2: 1, 3: 0.001, 4: 10 ** (-9)}
 637             lenUnit = lenUnitMap[self.controlData[imageName]["QComboBox"]["currentIndex"][0]]
 638 
 639             timeUnitMap = {0: 3.1536 * 10 ** 7, 1: 86400, 2: 1, 3: 0.001, 4: 10 ** (-6)}
 640             timeUnit = timeUnitMap[self.controlData[imageName]["QComboBox"]["currentIndex"][1]]
 641 
 642             massUnitMap = {0: 1, 1: 1.99 * 10 ** 30, 2: 1.7 * 10 ** (-27), 3: 9.1 * 10 ** (-31)}
 643             massUnit = massUnitMap[self.controlData[imageName]["QComboBox"]["currentIndex"][2]]
 644 
 645             electricUnitMap = {0: 1, 1: 1.6 * 10 ** (-19)}
 646             electricUnit = electricUnitMap[self.controlData[imageName]["QComboBox"]["currentIndex"][3]]
 647 
 648             GUnit = 6.67408 * 10 ** (-11) * massUnit * timeUnit ** 2 / lenUnit ** 3
 649             KUnit = 8.987 * 10 ** 9 * electricUnit ** 2 * timeUnit ** 2 / lenUnit ** 3 / massUnit
 650 
 651         timeLength = int(self.control["QComboBox"][6].currentText())
 652         nodeNumber = int(self.control["QComboBox"][7].currentText())
 653         t = numpy.arange(0, timeLength, timeLength / nodeNumber)
 654 
 655         aniSpeed = self.controlData[imageName]["QSpinBox"]["value"][0]
 656 
 657         ########################################################
 658         # draw the solution of ordinary differential equations #
 659         ########################################################
 660         self.controlClear()
 661 
 662         layout = QGridLayout()
 663         layout.setSpacing(10)
 664 
 665         # noinspection PyArgumentList
 666         widget = QWidget()
 667         self.canvas["gravitationalSystemImage"] = GravitationCanvas(aniArg, mass, electric, electricType, cood, vel,
 668                                                                     GUnit, KUnit, t, aniSpeed, parent=widget)
 669         self.controlData[imageName]["save"] = [mass, electric, electricType, cood, vel, GUnit, KUnit, t,
 670                                                self.canvas["gravitationalSystemImage"].track,
 671                                                self.canvas["gravitationalSystemImage"].vector,
 672                                                self.canvas["gravitationalSystemImage"].acc]
 673 
 674         layout.addWidget(self.canvas["gravitationalSystemImage"])
 675         widget.setLayout(layout)
 676         self.setCentralWidget(widget)
 677 
 678         self.statusBar().showMessage('Ready')
 679 
 680     def convexHullImage(self):
 681         """
 682         layout and initialization data
 683         """
 684         ##########################
 685         # layout of current page #
 686         ##########################
 687         self.currentImage = "convexHullImage"
 688         self.controlClear()
 689 
 690         layout = QGridLayout()
 691         layout.setSpacing(10)
 692 
 693         text = ['空间维数', '散点个数', '查看迭代步数']
 694         position = [[0, 0, 1, 1], [0, 2, 1, 1], [0, 4, 1, 1]]
 695         self.controlLayout(layout=layout, name="QLabel", var={"text": text}, position=position, signal=None)
 696 
 697         itemText = [list(map(str, range(2, 15))), list(map(str, range(3, 50))),
 698                     ["-complete-"] + list(map(str, range(1, 9)))]
 699         currentIndex = [1, 6, 0]
 700         position = [[0, 1, 1, 1], [0, 3, 1, 1], [0, 5, 1, 1]]
 701         self.controlLayout(layout=layout, name="QComboBox", var={"itemText": itemText, "currentIndex": currentIndex},
 702                            position=position, signal=self.convexHullImageSignal)
 703 
 704         text = ['随机生成散点集']
 705         position = [[0, 6, 1, 1]]
 706         self.controlLayout(layout=layout, name="QPushButton", var={"text": text},
 707                            position=position, signal=self.convexHullImageRandom)
 708 
 709         # noinspection PyArgumentList
 710         widget = [[QWidget(), QWidget(), QWidget()]]
 711         matrixLayout = QGridLayout()
 712         matrix = [numpy.array([[6, 0, 9, 9, 6, 6, 2, 0, 6],
 713                                [5, 7, 2, 6, 7, 3, 7, 4, 4],
 714                                [8, 3, 2, 5, 0, 0, 7, 6, 5]])]
 715         self.controlLayout(layout=matrixLayout, name="QTableWidget", var={"headerLabels": [], "data": matrix},
 716                            position=[[0, 0, 1, 1]], signal=None)
 717         widget[0][0].setLayout(matrixLayout)
 718 
 719         patches_listLayout = QGridLayout()
 720         patches_list = [numpy.array([[4, 2, 6, 0, 1, 1, 0, 0, 2, 5, 5, 5],
 721                                      [6, 4, 0, 6, 6, 7, 2, 7, 5, 2, 1, 7],
 722                                      [3, 3, 3, 7, 4, 6, 3, 2, 4, 7, 4, 1]])]
 723         self.controlLayout(layout=patches_listLayout, name="QTableWidget",
 724                            var={"headerLabels": [], "data": patches_list}, position=[[0, 0, 1, 1]], signal=None)
 725         widget[0][1].setLayout(patches_listLayout)
 726 
 727         canvasLayout = QGridLayout()
 728         self.canvas["convexHullImage"] = ConvexHullCanvas(matrix[0], patches_list, parent=widget[0][2])
 729         canvasLayout.addWidget(self.canvas["convexHullImage"])
 730         widget[0][2].setLayout(canvasLayout)
 731 
 732         text = [["Points", "Patches", "Convex Hull 3D"]]
 733         position = [[1, 0, 1, 7]]
 734         self.controlLayout(layout=layout, name="QTabWidget", var={"text": text, "widget": widget},
 735                            position=position, signal=None)
 736 
 737         # noinspection PyArgumentList
 738         widget = QWidget()
 739         widget.setLayout(layout)
 740         self.setCentralWidget(widget)
 741 
 742         ######################################################################
 743         # initialization self.controlData["convexHullImage"] then refresh it #
 744         # refresh self.control["convexHullImage"]                            #
 745         ######################################################################
 746         if "convexHullImage" not in self.controlData:
 747             self.addFrame("convexHullImage")
 748             self.convexHullImageSignal()
 749         else:
 750             for j in range(0, len(self.control["QComboBox"])):
 751                 self.control["QComboBox"][j].currentIndexChanged.disconnect(self.convexHullImageSignal)
 752             self.imageRead(imageName="convexHullImage")
 753             for j in range(0, len(self.control["QComboBox"])):
 754                 self.control["QComboBox"][j].currentIndexChanged.connect(self.convexHullImageSignal)
 755 
 756         self.statusBar().showMessage('Ready')
 757 
 758     def convexHullImageSignal(self):
 759         """
 760         respond of current page(convexHullImage), then write data into MainData.controlData
 761         """
 762         self.statusBar().showMessage('Setting patches...')
 763 
 764         ######################################################
 765         # initialization self.controlData["convexHullImage"] #
 766         ######################################################
 767         imageName = "convexHullImage"
 768         self.controlDataClear(imageName)
 769 
 770         ###############################################
 771         # refresh self.controlData["convexHullImage"] #
 772         ###############################################
 773         m = int(self.control["QComboBox"][0].itemText(self.control["QComboBox"][0].currentIndex()))
 774         n = int(self.control["QComboBox"][1].itemText(self.control["QComboBox"][1].currentIndex()))
 775         if m < n:
 776             pass
 777         else:
 778             self.statusBar().showMessage('The number of points should be more than dimension.')
 779             return
 780 
 781         list(map(str, range(4, 50)))
 782         for j in range(0, len(self.control["QComboBox"])):
 783             itemText = list()
 784             for k in range(0, self.control["QComboBox"][j].count()):
 785                 itemText.append(self.control["QComboBox"][j].itemText(k))
 786             self.controlData[imageName]["QComboBox"]["itemText"].append(itemText)
 787 
 788             currentIndex = self.control["QComboBox"][j].currentIndex()
 789             self.controlData[imageName]["QComboBox"]["currentIndex"].append(currentIndex)
 790 
 791         row = int(self.control["QComboBox"][0].currentText())
 792         column = int(self.control["QComboBox"][1].currentText())
 793         currentRow = self.control["QTableWidget"][0].rowCount()
 794         currentColumn = self.control["QTableWidget"][0].columnCount()
 795         matrix = numpy.zeros((row, column), dtype=numpy.float64)
 796         for j in range(0, row):
 797             for k in range(0, column):
 798                 if j < currentRow and k < currentColumn:
 799                     # noinspection PyBroadException
 800                     try:
 801                         matrix[j][k] = float(self.control["QTableWidget"][0].item(j, k).text())
 802                     except:
 803                         matrix[j][k] = 0
 804         self.controlData[imageName]["QTableWidget"]["data"].append(matrix)
 805 
 806         obj = ConvexHullMap(matrix=matrix)
 807         obj.complete()
 808         patches = numpy.array(obj.patches).T
 809         self.controlData[imageName]["QTableWidget"]["data"].append(patches)
 810 
 811         self.controlData[imageName]["save"] = [matrix, patches]
 812 
 813         ##############
 814         # draw image #
 815         ##############
 816         if int(self.control["QComboBox"][0].currentText()) == 3:
 817             self.canvas[imageName].canvasData["matrix"] = matrix
 818             if self.control["QComboBox"][2].currentIndex() == 0:
 819                 self.canvas[imageName].canvasData["patches_list"] = [obj.patches]
 820             else:
 821                 new_obj = ConvexHullMap(matrix=matrix)
 822                 self.canvas[imageName].canvasData["patches_list"] = [copy.deepcopy(new_obj.patches)]
 823                 for j in range(0, int(self.control["QComboBox"][2].currentText())):
 824                     new_obj.classify_points()
 825                     if new_obj.next_points.count(None) == len(new_obj.next_points):
 826                         break
 827                     new_obj.expand_patches()
 828                     self.canvas[imageName].canvasData["patches_list"].append(copy.deepcopy(new_obj.patches))
 829         self.canvas[imageName].fig.clf()
 830         self.canvas[imageName].axes = axes3d.Axes3D(self.canvas[imageName].fig)
 831         self.canvas[imageName].complete_draw()
 832         self.canvas[imageName].fig.canvas.draw()
 833 
 834         ###########################################
 835         # refresh self.control["convexHullImage"] #
 836         ###########################################
 837         for j in range(0, len(self.control["QComboBox"])):
 838             self.control["QComboBox"][j].currentIndexChanged.disconnect(self.convexHullImageSignal)
 839         self.imageRead(imageName=imageName)
 840         for j in range(0, len(self.control["QComboBox"])):
 841             self.control["QComboBox"][j].currentIndexChanged.connect(self.convexHullImageSignal)
 842 
 843         self.statusBar().showMessage('End of setting title.')
 844 
 845     def convexHullImageRandom(self):
 846         """
 847         Reset coordinates of scattered point set
 848         """
 849         ###############################################
 850         # refresh self.controlData["convexHullImage"] #
 851         ###############################################
 852         self.statusBar().showMessage('Start to resetting coordinates of scattered points...')
 853 
 854         #########################################
 855         # get parameters of scattered point set #
 856         #########################################
 857         imageName = "convexHullImage"
 858 
 859         n = int(self.control["QComboBox"][0].currentText())
 860         m = int(self.control["QComboBox"][1].currentText())
 861         matrix = numpy.random.random_integers(low=0, high=10, size=(n, m))
 862         self.controlData[imageName]["QTableWidget"]["data"][0] = matrix
 863         self.controlData[imageName]["save"][0] = matrix
 864 
 865         self.imageRead(imageName=imageName)
 866 
 867         self.convexHullImageSignal()
 868 
 869         self.statusBar().showMessage('End of resetting coordinates of scattered points.')
 870 
 871     def analyticFunctionImage(self):
 872         """
 873         layout and initialization data
 874         """
 875         ##########################
 876         # layout of current page #
 877         ##########################
 878         self.currentImage = "analyticFunctionImage"
 879         self.controlClear()
 880 
 881         layout = QGridLayout()
 882         layout.setSpacing(10)
 883 
 884         text = ['次方数', '拉伸系数', '辐角']
 885         position = [[0, 0, 1, 1], [0, 2, 1, 1], [0, 4, 1, 1]]
 886         self.controlLayout(layout=layout, name="QLabel", var={"text": text}, position=position, signal=None)
 887 
 888         itemText = [list(map(str, range(1, 20)))]
 889         position = [[0, 1, 1, 1]]
 890         self.controlLayout(layout=layout, name="QComboBox", var={"itemText": itemText, "currentIndex": []},
 891                            position=position, signal=self.analyticFunctionImageSignal)
 892 
 893         var = {"range": [[1, 100], [-180, 180]], "singleStep": [1, 1],
 894                "prefix": [], "suffix": ['*0.1', '*pi/180'], "value": [10, 0]}
 895         position = [[0, 3, 1, 1], [0, 5, 1, 1]]
 896         self.controlLayout(layout=layout, name="QSpinBox", var=var,
 897                            position=position, signal=self.analyticFunctionImageSignal)
 898 
 899         text = [['%f*e**(i*%f)*z**%d + z = 1' % (1, 1, 0)]]
 900         # noinspection PyArgumentList
 901         widget = [[QWidget()]]
 902         position = [[1, 0, 1, 6]]
 903         widgetLayout = QGridLayout()
 904         self.canvas["analyticFunctionImage"] = AnalyticFunctionCanvas(1, 1, 0, parent=widget[0][0])
 905         widgetLayout.addWidget(self.canvas["analyticFunctionImage"])
 906         widget[0][0].setLayout(widgetLayout)
 907         self.controlLayout(layout=layout, name="QTabWidget", var={"text": text, "widget": widget},
 908                            position=position, signal=None)
 909 
 910         # noinspection PyArgumentList
 911         widget = QWidget()
 912         widget.setLayout(layout)
 913         self.setCentralWidget(widget)
 914 
 915         ############################################################################
 916         # initialization self.controlData["analyticFunctionImage"] then refresh it #
 917         # refresh self.control["analyticFunctionImage"]                            #
 918         ############################################################################
 919         if "analyticFunctionImage" not in self.controlData:
 920             self.addFrame("analyticFunctionImage")
 921             self.analyticFunctionImageSignal()
 922         else:
 923             for j in range(0, len(self.control["QComboBox"])):
 924                 self.control["QComboBox"][j].currentIndexChanged.disconnect(self.analyticFunctionImageSignal)
 925             for j in range(0, len(self.control["QSpinBox"])):
 926                 self.control["QSpinBox"][j].valueChanged.disconnect(self.analyticFunctionImageSignal)
 927             self.imageRead(imageName="analyticFunctionImage")
 928             for j in range(0, len(self.control["QComboBox"])):
 929                 self.control["QComboBox"][j].currentIndexChanged.connect(self.analyticFunctionImageSignal)
 930             for j in range(0, len(self.control["QSpinBox"])):
 931                 self.control["QSpinBox"][j].valueChanged.disconnect(self.analyticFunctionImageSignal)
 932 
 933         self.statusBar().showMessage('Ready')
 934 
 935     def analyticFunctionImageSignal(self):
 936         """
 937         respond of current page(analyticFunctionImage), then write data into MainData.controlData
 938         """
 939         self.statusBar().showMessage('Starting draw image...')
 940 
 941         ############################################################
 942         # initialization self.controlData["analyticFunctionImage"] #
 943         ############################################################
 944         imageName = "analyticFunctionImage"
 945         self.controlDataClear(imageName)
 946 
 947         #####################################################
 948         # refresh self.controlData["analyticFunctionImage"] #
 949         #####################################################
 950         for j in range(0, len(self.control["QComboBox"])):
 951             itemText = list()
 952             for k in range(0, self.control["QComboBox"][j].count()):
 953                 itemText.append(self.control["QComboBox"][j].itemText(k))
 954             self.controlData[imageName]["QComboBox"]["itemText"].append(itemText)
 955 
 956             currentIndex = self.control["QComboBox"][j].currentIndex()
 957             self.controlData[imageName]["QComboBox"]["currentIndex"].append(currentIndex)
 958 
 959         for j in range(0, len(self.control["QSpinBox"])):
 960             value = self.control["QSpinBox"][j].value()
 961             self.controlData[imageName]["QSpinBox"]["value"].append(value)
 962 
 963         ##############
 964         # draw image #
 965         ##############
 966         self.canvas[imageName].n = self.controlData[imageName]["QComboBox"]["currentIndex"][0] + 1
 967         self.canvas[imageName].r = self.controlData[imageName]["QSpinBox"]["value"][0] * 0.1
 968         self.canvas[imageName].t = self.controlData[imageName]["QSpinBox"]["value"][1] * math.pi / 180
 969         text = '%f*e**(i*%f)*z**%d + z = 1' % (self.canvas[imageName].n, self.canvas[imageName].r,
 970                                                self.canvas[imageName].t)
 971         self.control["QTabWidget"][0].setTabText(0, text)
 972         self.canvas[imageName].fig.clf()
 973         self.canvas[imageName].axes = self.canvas[imageName].fig.add_subplot(111)
 974         self.canvas[imageName].axes.grid(True)
 975         self.canvas[imageName].complete_draw()
 976         self.canvas[imageName].fig.canvas.draw()
 977 
 978         ################################################
 979         # refresh self.control["analyticFunctionImage"] #
 980         ################################################
 981         for j in range(0, len(self.control["QComboBox"])):
 982             self.control["QComboBox"][j].currentIndexChanged.disconnect(self.analyticFunctionImageSignal)
 983         self.imageRead(imageName=imageName)
 984         for j in range(0, len(self.control["QComboBox"])):
 985             self.control["QComboBox"][j].currentIndexChanged.connect(self.analyticFunctionImageSignal)
 986 
 987         self.statusBar().showMessage('Image is drawn.')
 988 
 989     @staticmethod
 990     def sourceCodeImage():
 991         """
 992         @
 993         """
 994         pass
 995 
 996     def keyPressEvent(self, event):
 997         """
 998         :param event:
 999         :return:
1000         """
1001         if event.key() == Qt.Key_Escape:
1002             try:
1003                 if self.currentImage == "rainImage":
1004                     self.orthogonalTableImage()
1005                 elif self.currentImage == "orthogonalTableImage":
1006                     pass
1007                 elif self.currentImage == "convexHullImage":
1008                     pass
1009                 elif self.currentImage == "gravitationalSystemImage":
1010                     self.gravitationalSystemImage()
1011                 elif self.currentImage == "analyticFunctionImage":
1012                     pass
1013             except KeyError:
1014                 self.startImage()
1015             self.statusBar().showMessage('Esc is pressed!')
1016 
1017     def showOpenDialog(self):
1018         """
1019         @
1020         """
1021         # noinspection PyCallByClass,SpellCheckingInspection
1022         fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
1023 
1024         # if fname[0]:
1025         #     # noinspection PyArgumentEqualDefault
1026         #     f = open(fname[0], 'r')
1027         #     with f:
1028         #         data = f.read()
1029         #         self.textEdit.setText(data)
1030 
1031     def buttonClicked(self):
1032         """
1033         @
1034         """
1035         sender = self.sender()
1036         self.statusBar().showMessage(sender.text() + ' was pressed')
1037         # noinspection PyCallByClass,PyTypeChecker
1038         QInputDialog.getText(self, 'Input Dialog', 'Enter your name:')
1039 
1040     def closeEvent(self, event):
1041         """
1042         @
1043         """
1044         # noinspection PyCallByClass,PyTypeChecker
1045         reply = QMessageBox.question(self, 'Message', "Are you sure to quit?",
1046                                      QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
1047         if reply == QMessageBox.Yes:
1048             event.accept()
1049         else:
1050             event.ignore()
MainWindow

功能展示

开始界面:

 正交试验表页面:

凸包页面:

常微分方程组页面:

目前为止只制作了4个模块,后续我在博客里每多写一篇理论性的文章的时候,都会添加图形演示至本文章。

声明

本文由Hamilton算符”原创,未经博主允许不得转载!

原文地址:https://www.cnblogs.com/Hamilton-Operator/p/6507820.html