zoukankan      html  css  js  c++  java
  • PyQt5 signal and slot

    PyQt5 的 signal 与 slot 有所改变,例如,先定义一个 ZeroSignal 类:

    class ZeroSignal(QObject):
        atzero = pyqtSignal(int)

    使用时,一是绑定 slot 如下:

        self.zerosig = ZeroSignal()
           self.zerosig.atzero[int].connect(self.countZero)

    然后是找个机会发动之:

    def checkZero(self):
            if self.value() == 0:
                self.zerosig.atzero.emit(self.value())

    大约如此,完整代码如下:

    import os
    import sys
    
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    
    class ZeroSignal(QObject):
        atzero = pyqtSignal(int)
    
    class ZeroSpinBox(QSpinBox):
        def __init__(self, parent=None):
            super(ZeroSpinBox, self).__init__(parent)
            self.zeros = 0
            self.valueChanged[int].connect(self.checkZero)
            self.zerosig = ZeroSignal()
            self.zerosig.atzero[int].connect(self.countZero)
    
        def countZero(self, v):
            if v == 0:
                self.zeros += 1
                print(self.zeros)
    
        def checkZero(self):
            if self.value() == 0:
                self.zerosig.atzero.emit(self.value())
                
    
    
    
    class Form(QDialog):
        def __init__(self, parent=None):
            super(Form, self).__init__(parent)
            
            dial = QDial()
            dial.setNotchesVisible(True)
            spin = ZeroSpinBox()
            layout = QHBoxLayout()
            layout.addWidget(dial)
            layout.addWidget(spin)
            self.setLayout(layout)
            dial.valueChanged.connect(spin.setValue)
            spin.valueChanged.connect(dial.setValue)
            spin.valueChanged.connect(self.emitZero)
            self.setWindowTitle("Sinal and Solt")
            
            self.zerobox = spin 
            self.zerobox.zerosig.atzero[int].connect(self.annouce)
    
        def emitZero(self, v):
            if v == 0:
                self.zerobox.zerosig.atzero.emit(self.zerobox.zeros)
    
        def annouce(self, v):
            print("zero count: %d" % v)  # print two times because add ZeroSpinBox emit once
    
    def run():
        app = QApplication(sys.argv)
        form = Form()
        form.show()
        app.exec_()
    
    if __name__ == '__main__':
        run()

    关于对话框的代码如下,尤其 NumberLiveDialog 值得推荐:

    import sys,math,random,string
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    
    class NumberDialog(QDialog):
        def __init__(self, format, parent=None):
            super(NumberDialog, self).__init__(parent)
    
            thousandsLabel = QLabel("&Thousands separator:")
            self.thousandsEdit = QLineEdit(format["thousandsseparator"])
            thousandsLabel.setBuddy(self.thousandsEdit)
            decimalMarkerLabel = QLabel("Decimal $marker:")
            self.decimalMarkerEdit = QLineEdit(format["decimalmarker"])
            decimalMarkerLabel.setBuddy(self.decimalMarkerEdit)
            decimalPlacesLabel = QLabel("&Decimal places:")
            self.decimalPlacesSpinBox = QSpinBox()
            decimalPlacesLabel.setBuddy(self.decimalPlacesSpinBox)
            self.decimalPlacesSpinBox.setRange(0, 6)
            self.decimalPlacesSpinBox.setValue(format["decimalplaces"])
            self.redNegativesCheckBox = QCheckBox("&Red negative numbers")
            self.redNegativesCheckBox.setChecked(format["rednegatives"])
    
            buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
            self.format = format.copy()
    
            grid = QGridLayout()
            grid.addWidget(thousandsLabel, 0, 0)
            grid.addWidget(self.thousandsEdit, 0, 1)
            grid.addWidget(decimalMarkerLabel, 1, 0)
            grid.addWidget(self.decimalMarkerEdit, 1, 1)
            grid.addWidget(decimalPlacesLabel, 2, 0)
            grid.addWidget(self.decimalPlacesSpinBox, 2, 1)
            grid.addWidget(self.redNegativesCheckBox, 3, 0, 1, 2)
            grid.addWidget(buttonBox, 4, 0, 1, 2)
            self.setLayout(grid)
    
            buttonBox.accepted.connect(self.accept)
            buttonBox.rejected.connect(self.reject)
            self.setWindowTitle("Number format")
    
        def accept(self):
            class ThousandsError(Exception): pass 
            class DecimalError(Exception): pass 
            Punctuation = frozenset(" ,;:.")
    
            thousands = str(self.thousandsEdit.text())
            decimal = str(self.decimalMarkerEdit.text())
            try:
                if len(decimal) == 0:
                    raise DecimalError("The decimal marker may not be empty.")
                if len(thousands) > 1:
                    raise ThousandsError("The thousands separator may only be empty or one charactor.")
                if len(decimal) > 1:
                    raise DecimalError("The decimal marker must be one character.")
                if thousands == decimal:
                    raise ThousandsError("The thousands separator and decimal marker must be different.")
                if thousands and thousands not in Punctuation:
                    raise ThousandsError("The thousands separator must be in Punctuation.")
                if decimal and decimal not in Punctuation:
                    raise DecimalError("The decimal marker must be a punctuation symbol.")
            except ThousandsError as e:
                QMessageBox.warning(self, "Thousands separator error:", str(e))
                self.thousandsEdit.selectAll()
                self.thousandsEdit.setFocus()
                return 
            except DecimalError as e:
                QMessageBox.warning(self, "Decimal marker error:", str(e))
                self.decimalMarkerEdit.selectAll()
                self.decimalMarkerEdit.setFocus()
                return
    
            self.format["thousandsseparator"] = thousands
            self.format["decimalmarker"] = decimal
            self.format["decimalplaces"] = self.decimalPlacesSpinBox.value()
            self.format["rednegatives"] = self.redNegativesCheckBox.isChecked()
    
            QDialog.accept(self)
    
        def numberFormat(self):
            return self.format
    
    class NumberModelessDialog(QDialog):
        changed = pyqtSignal()
    
        def __init__(self, format, parent=None):
            super(NumberModelessDialog, self).__init__(parent)
            self.setAttribute(Qt.WA_DeleteOnClose)
            punctuationRe = QRegularExpression(r"[ ,;:.]")
    
            thousandsLabel = QLabel("&Thousands separator:")
            self.thousandsEdit = QLineEdit(format["thousandsseparator"])
            thousandsLabel.setBuddy(self.thousandsEdit)
            self.thousandsEdit.setMaxLength(1)
            self.thousandsEdit.setValidator(QRegularExpressionValidator(punctuationRe, self))
    
            decimalMarkerLabel = QLabel("Decimal $marker:")
            self.decimalMarkerEdit = QLineEdit(format["decimalmarker"])
            decimalMarkerLabel.setBuddy(self.decimalMarkerEdit)
            self.decimalMarkerEdit.setMaxLength(1)
            self.decimalMarkerEdit.setValidator(QRegularExpressionValidator(punctuationRe, self))
    
            decimalPlacesLabel = QLabel("&Decimal places:")
            self.decimalPlacesSpinBox = QSpinBox()
            decimalPlacesLabel.setBuddy(self.decimalPlacesSpinBox)
            self.decimalPlacesSpinBox.setRange(0, 6)
            self.decimalPlacesSpinBox.setValue(format["decimalplaces"])
            
            self.redNegativesCheckBox = QCheckBox("&Red negative numbers")
            self.redNegativesCheckBox.setChecked(format["rednegatives"])
    
            buttonBox = QDialogButtonBox(QDialogButtonBox.Apply | QDialogButtonBox.Close)
            self.format = format
    
            grid = QGridLayout()
            grid.addWidget(thousandsLabel, 0, 0)
            grid.addWidget(self.thousandsEdit, 0, 1)
            grid.addWidget(decimalMarkerLabel, 1, 0)
            grid.addWidget(self.decimalMarkerEdit, 1, 1)
            grid.addWidget(decimalPlacesLabel, 2, 0)
            grid.addWidget(self.decimalPlacesSpinBox, 2, 1)
            grid.addWidget(self.redNegativesCheckBox, 3, 0, 1, 2)
            grid.addWidget(buttonBox, 4, 0, 1, 2)
            self.setLayout(grid)
            
            buttonBox.button(QDialogButtonBox.Apply).clicked.connect(self.apply)
            buttonBox.rejected.connect(self.reject)
            self.setWindowTitle("Number format")
    
        def apply(self):
            thousands = str(self.thousandsEdit.text())
            decimal = str(self.decimalMarkerEdit.text())
            if thousands == decimal:
                QMessageBox.warning(self, "Thousands separator error")
                self.thousandsEdit.selectAll()
                self.thousandsEdit.setFocus()
                return 
            if len(decimal) == 0:
                QMessageBox.warning(self, "Decimal marker cannot is empty.")
                self.decimalMarkerEdit.selectAll()
                self.decimalMarkerEdit.setFocus()
                return
    
            self.format["thousandsseparator"] = thousands
            self.format["decimalmarker"] = decimal
            self.format["decimalplaces"] = self.decimalPlacesSpinBox.value()
            self.format["rednegatives"] = self.redNegativesCheckBox.isChecked()
    
            self.changed.emit()
    
    class NumberLiveDialog(QDialog):
        changed = pyqtSignal()
    
        def __init__(self, format, callback, parent=None):
            super(NumberLiveDialog, self).__init__(parent)
            self.format = format
            self.callback = callback
            
            self.setAttribute(Qt.WA_DeleteOnClose)
            punctuationRe = QRegularExpression(r"[ ,;:.]")
    
            thousandsLabel = QLabel("&Thousands separator:")
            self.thousandsEdit = QLineEdit(format["thousandsseparator"])
            thousandsLabel.setBuddy(self.thousandsEdit)
            self.thousandsEdit.setMaxLength(1)
            self.thousandsEdit.setValidator(QRegularExpressionValidator(punctuationRe, self))
    
            decimalMarkerLabel = QLabel("Decimal $marker:")
            self.decimalMarkerEdit = QLineEdit(format["decimalmarker"])
            decimalMarkerLabel.setBuddy(self.decimalMarkerEdit)
            self.decimalMarkerEdit.setMaxLength(1)
            self.decimalMarkerEdit.setValidator(QRegularExpressionValidator(punctuationRe, self))
    
            decimalPlacesLabel = QLabel("&Decimal places:")
            self.decimalPlacesSpinBox = QSpinBox()
            decimalPlacesLabel.setBuddy(self.decimalPlacesSpinBox)
            self.decimalPlacesSpinBox.setRange(0, 6)
            self.decimalPlacesSpinBox.setValue(format["decimalplaces"])
            
            self.redNegativesCheckBox = QCheckBox("&Red negative numbers")
            self.redNegativesCheckBox.setChecked(format["rednegatives"])
    
            grid = QGridLayout()
            grid.addWidget(thousandsLabel, 0, 0)
            grid.addWidget(self.thousandsEdit, 0, 1)
            grid.addWidget(decimalMarkerLabel, 1, 0)
            grid.addWidget(self.decimalMarkerEdit, 1, 1)
            grid.addWidget(decimalPlacesLabel, 2, 0)
            grid.addWidget(self.decimalPlacesSpinBox, 2, 1)
            grid.addWidget(self.redNegativesCheckBox, 3, 0, 1, 2)
            self.setLayout(grid)
            
            self.thousandsEdit.textEdited.connect(self.checkAndFix)
            self.decimalMarkerEdit.textEdited.connect(self.checkAndFix)
            self.decimalPlacesSpinBox.valueChanged.connect(self.apply)
            self.redNegativesCheckBox.toggled.connect(self.apply)
    
            self.setWindowTitle("Number format")
    
        def checkAndFix(self):
            thousands = self.thousandsEdit.text()
            decimal = self.decimalMarkerEdit.text()
            if thousands == decimal:
                self.thousandsEdit.clear()
                self.thousandsEdit.setFocus()
            if len(decimal) == 0:
                self.decimalMarkerEdit.setText(".")
                self.decimalMarkerEdit.selectAll()
                self.decimalMarkerEdit.setFocus()
            self.apply()
    
        def apply(self):
            thousands = self.thousandsEdit.text()
            decimal = self.decimalMarkerEdit.text()
    
            self.format["thousandsseparator"] = thousands
            self.format["decimalmarker"] = decimal
            self.format["decimalplaces"] = self.decimalPlacesSpinBox.value()
            self.format["rednegatives"] = self.redNegativesCheckBox.isChecked()
    
            self.callback()
    
    class Form(QDialog):
        X_MAX = 26
        Y_MAX = 60
    
        def __init__(self, parent=None):
            super(Form, self).__init__(parent)
    
            self.numberDlg = None
            self.format = { "thousandsseparator":",", "decimalmarker":".", 
                "decimalplaces":2, "rednegatives": False } 
            self.numbers = {}
            for x in range(self.X_MAX):
                for y in range(self.Y_MAX):
                    self.numbers[(x,y)] = 10000 * random.random() - 5000
    
            self.table = QTableWidget()
            modalButton = QPushButton("Set numbe format...(&Modal)")
            modelessButton = QPushButton("Set number format...(M&odeless)")
            liveButton = QPushButton("Set number format...(&Live)")
    
            buttonLayout = QHBoxLayout()
            buttonLayout.addStretch()
            buttonLayout.addWidget(modalButton)
            buttonLayout.addWidget(modelessButton)
            buttonLayout.addWidget(liveButton)
            layout = QVBoxLayout()
            layout.addWidget(self.table)
            layout.addLayout(buttonLayout)
            self.setLayout(layout)
    
            modalButton.clicked.connect(self.setNumberFormatByModal)
            modelessButton.clicked.connect(self.setNumberFormatByModeless)
            liveButton.clicked.connect(self.setNumberFormatByLive)
    
            self.setWindowTitle("Set Number Format")
            self.refreshTable()
    
        def refreshTable(self):
            self.table.clear()
            self.table.setRowCount(self.Y_MAX)
            self.table.setColumnCount(self.X_MAX)
            self.table.setHorizontalHeaderLabels(list(string.ascii_uppercase))
    
            for x in range(self.X_MAX):
                for y in range(self.Y_MAX):
                    fraction, whole = math.modf(self.numbers[(x,y)])
                    sign = "-" if whole < 0 else ""
                    whole = "{0}".format(int(math.floor(abs(whole))))
                    digits = []
                    for i, digit in enumerate(reversed(whole)):
                        if i and i % 3 == 0:
                            digits.insert(0, self.format["thousandsseparator"])
                        digits.insert(0, digit)
                    if self.format["decimalplaces"]:
                        fraction = "{0:.7f}".format(abs(fraction))
                        fraction = self.format["decimalmarker"] + fraction[2:self.format["decimalplaces"]+2]
                    else:
                        fraction = ""
                    text = "{0}{1}{2}".format(sign, "".join(digits), fraction)
                    item = QTableWidgetItem(text)
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    if sign and self.format["rednegatives"]:
                        item.setBackground(Qt.red)
                    self.table.setItem(y, x, item)
    
        def setNumberFormatByModal(self):
            dlg = NumberDialog(self.format, self)
            if dlg.exec_():
                self.format = dlg.numberFormat()
                self.refreshTable()
    
        def setNumberFormatByModeless(self):
            dlg = NumberModelessDialog(self.format, self)
            dlg.show()
            dlg.changed.connect(self.refreshTable)
    
        def setNumberFormatByLive(self):
            if self.numberDlg is None:
                self.numberDlg = NumberLiveDialog(self.format, self.refreshTable, self)
            self.numberDlg.show()
            self.numberDlg.raise_()
            self.numberDlg.activateWindow()
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        form = Form()
        form.show()
        app.exec_()
    numberdlg.py

     关于主窗口 (fileload function need add a bool parameter for recentfiles) 的代码:imagechanger

     运行效果图如下:

            

     《Python GUI Qt 快速开放指南》部分例子: PyQt5-Code

  • 相关阅读:
    招财宝和余额宝哪个好?注意招财宝三大漏洞
    JavaScript eval() Function
    面向对象设计七大原则
    Web开发应该注意的问题
    表格内容排序(js实现)
    Ruby on Rails Tutorial 第六章 用户模型
    Ruby on Rails Tutorial 第五章 完善布局
    一万小时定律的数学解释
    数据抓取的艺术(三)
    数据抓取的艺术(二)
  • 原文地址:https://www.cnblogs.com/china_x01/p/7932693.html
Copyright © 2011-2022 走看看