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算符”原創,未經博主允許不得轉載!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM