• 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算符”原创,未经博主允许不得转载!

  • 相关阅读:
    ModuleNotFoundError: No module named '_ctypes' make: *** [install] 错误 1
    Python安装常见问题:ModuleNotFoundError: No module named '_ctypes' 解决办法
    No module named 'requests'
    python 安装bs4
    python 判断字符串中是否包含数字
    python lambda与zip 组合使用
    Python 从两个List构造Dict
    针对led显示图案的设计工具,画出图案后,可以导出点阵的16进制数组
    支付宝接口:系统有点忙,一会再试试
    urllib.error.URLError: urlopen error SSL: CERTIFICATE_VERIFY_FAILED certificate verify failed
  • 原文地址:https://www.cnblogs.com/Hamilton-Operator/p/6507820.html
Copyright © 2020-2023  润新知