简体   繁体   中英

Creating a class signal with pyqt4

Is there a way to create a signal from a class method in pyqt4 rather than always using instance methods?

I have a wrapper class that wraps and stores state between a QLineEdit and QCheckBox combination. The class sums all of the values in the QLineEdit in a class variable. If the QCheckBox is unchecked, the value of the associated line edit is deducted from the total. If the user edits the QLineEdit, the old value is deducted and the new value added. I want to emit the updated value everytime it changes from the class level.

Right now what I'm doing is passing in the QLineEdit instance that I'm dumping the value into and connecting that through all the wrapper instances.

What I'd love to do is have the following code snippet work.

QtCore.QObject.connect(Wrapper,Wrapper.sum_values_signal, line_edit_instance.setText)

It doesn't though. Here's my wrapper class for reference:

class Wrapper(QtCore.QObject):
    sum_values = 0
    sum_values_signal = QtCore.pyqtSignal(str)

    def __init__(self, line_edit, check_box):
        super(QtCore.QObject, self).__init__()
        self.check_box = check_box
        self.line_edit = line_edit

        Wrapper.sum_values += float(line_edit.text())
        self.previous_value = float(line_edit.text())

        QtCore.QObject.connect(self.check_box,
                               QtCore.SIGNAL(_fromUtf8("toggled(bool)")),
                               self.update_sum_values_wrt_check_box)

        QtCore.QObject.connect(self.line_edit,
                               QtCore.SIGNAL(_fromUtf8("textChanged(QString)")),
                               self.update_sum_values_wrt_line_edit)

    def update_sum_values_wrt_check_box(self, toggled):
        if toggled is False:
            Wrapper.sum_values -= self.previous_value
        else:
            Wrapper.sum_values += self.previous_value

        self.sum_values_signal.emit(text(Wrapper.sum_values))

    def update_sum_values_wrt_line_edit(self, string):
        Wrapper.sum_values -= self.previous_value
        Wrapper.sum_values += float(string)
        self.previous_value = float(string)
        self.sum_values_signal.emit(text(Wrapper.sum_values))

In order to define a custom signal in a class, you need to use the pyqtSignal factory. Here is a simple example:

class CustomWidget(QtGui.QWidget):

    # No argument signal
    custom_signal = QtCore.pyqtSignal()

    # Signal with int argument and a custom name
    custom_signal_int = QtCore.pyqtSignal(int, name='integerSignal')

    def atSomePointEvent(self, event):
        value = event.someValue()
        if isinstance(value, int):
            self.custom_signal_int.emit(value)
        else:
            self.custom_signal.emit()

Note that it uses new style signals that make the implementation really nice and straightforward.

EDIT: This is how you're supposed to connect the signals:

self.check_box.toggled.connect(self.check_box_toggled)
self.line_edit.textChanged.connect(self.line_edit_changed)  

Then your code will probably fail because you don't handle the ValueError on float(line_edit.text()) when the QLineEdit is empty.

Moreover, there is definitely some functional problems in your program, essentially linked to the way you handle sum_values , and previous_value . You could also consider getting rid of the sum_value class attribute, since it seems like wrong design choice.

EDIT: Is this what you're trying to do by the way?

from PyQt4 import QtCore, QtGui

class CustomLabel(QtGui.QLabel):

    def __init__(self, line_edit_lst):
        super(CustomLabel, self).__init__("0")
        self.line_edit_lst = line_edit_lst
        for line_edit in self.line_edit_lst:
            line_edit.textChanged.connect(self.update)

    def update(self, ignore):
        total = sum(self.str_to_float(line_edit.text())
                    for line_edit in self.line_edit_lst)
        self.setText(str(total))

    def str_to_float(self, string, default=0):
        try: return float(string)
        except ValueError: return default

class MyDialog(QtGui.QDialog):

    def __init__(self, parent=None):
        super(MyDialog, self).__init__(parent)
        hbox = QtGui.QVBoxLayout()
        self.lines = [QtGui.QLineEdit() for _ in range(5)]
        for line in self.lines:
            hbox.addWidget(line)
        self.label = CustomLabel(self.lines)
        hbox.addWidget(self.label)
        self.setLayout(hbox)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    w = MyDialog()
    w.show()
    sys.exit(app.exec_())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM