1 什么时候用信号与槽

Qt建议: 只在主线程中操作界面 。
在另外一个线程直接操作界面,可能会导致意想不到的问题,比如:输出显示不全,甚至程序崩溃。
但是,我们确实经常需要在子线程中 更新界面。比如子线程是个爬虫,爬取到数据显示在界面上。
怎么办呢?

这时,推荐的方法是使用信号。
前面我们曾经看到过 各种 Qt 控件可以发出信号,比如 被点击、被输入等。
我们也可以自定义类,只要这个类继承QObject类,就能发出自己定义的各种Qt信号

2 内置信号连接自定义槽

  1. from PySide2.QtWidgets import *
  2. import sys
  3. app = QApplication()
  4. widget = QWidget()
  5. def showMsg():
  6. QMessageBox.information(widget, "提示", "HelloWorld")
  7. btn = QPushButton("测试点击", widget)
  8. btn.clicked.connect(showMsg)
  9. widget.show()
  10. sys.exit(app.exec_())

image.png

3 自定义信号与槽

(1) 信号给槽传递一个参数

  1. from PySide2.QtCore import QObject, Signal
  2. # 要点1:自定义信号源对象类型,一定要继承自 QObject
  3. class MySignal(QObject):
  4. # 要点2:每一种信号 都要定义为 为的静态属性
  5. sig1 = Signal(object) # 只传一个参数, object表示可以传任意py类型
  6. def func(msg):
  7. print("槽函数接收到的信号为", msg)
  8. if __name__ == "__main__":
  9. # 要点3:必须实例化才能调用信号的connect和emit方法
  10. my_signal = MySignal()
  11. my_signal.sig1.connect(func)
  12. my_signal.sig1.emit("HelloWorld")

运行结果:

槽函数接收到的信号为 HelloWorld

(2) 信号给槽传递多个指定类型的参数

  1. from PySide2.QtCore import QObject, Signal
  2. class MySignal(QObject):
  3. sig1 = Signal(bool, str, list)
  4. def func(*args):
  5. print("槽函数接收到的信号为", args)
  6. if __name__ == "__main__":
  7. my_signal = MySignal()
  8. my_signal.sig1.connect(func)
  9. my_signal.sig1.emit(1, "123", [4,5,6])

运行结果:

槽函数接收到的信号为 (True, ‘123’, [4, 5, 6])

(3) 重载信号与槽

  1. # 在mf.py中定义自定义信号
  2. class MySignal(QObject):
  3. # [row, col, hwnd] 或 [int, int, info]
  4. tbe_item_set_text = Signal([int, int, int], [int, int, str])
  5. # 在自定义的ui窗口类中定义此方法
  6. def init_sig_slot(self):
  7. gv.sig = mf.MySignal()
  8. gv.sig.tbe_item_set_text[int, int, int].connect(
  9. lambda row, col, hwnd: self.tbe_console.item(row, col).setText(str(hwnd))
  10. )
  11. gv.sig.tbe_item_set_text[int, int, str].connect(
  12. lambda row, col, info: self.tbe_console.item(row, col).setText(info)
  13. )
  14. # 调用
  15. class WndWorker():
  16. ...
  17. def log_out(self, info):
  18. # type: (str) -> None
  19. row = self.row
  20. gv.sig.tbe_item_set_text[int, int, str].emit(row, gv.COL_LOG, info)

4 装饰器信号与槽

  1. import sys
  2. from PySide2.QtCore import *
  3. from PySide2.QtWidgets import QApplication, QWidget, QPushButton
  4. class MyWidget(QWidget):
  5. def __init__(self):
  6. super().__init__()
  7. # 创建对象并设置对象名
  8. self.btn_ok = QPushButton("OK", self)
  9. self.btn_ok.setObjectName("btn_ok")
  10. # 通过对象名连接槽
  11. QMetaObject.connectSlotsByName(self)
  12. @Slot()
  13. def on_btn_ok_clicked(self):
  14. print("单击了ok按钮")
  15. if __name__ == "__main__":
  16. app = QApplication()
  17. my_wgt = MyWidget()
  18. my_wgt.show()
  19. sys.exit(app.exec_())

5 常用自定义信号方式

  1. import sys
  2. from PySide2.QtCore import Signal
  3. from PySide2.QtWidgets import QApplication, QDialog, QPushButton
  4. class WndClientLogin(QDialog):
  5. logined = Signal()
  6. def __init__(self):
  7. super().__init__()
  8. self.btn = QPushButton("test", self)
  9. self.btn.clicked.connect(
  10. lambda : self.logined.emit()
  11. )
  12. self.logined.connect(self.accept)
  13. if __name__ == '__main__':
  14. app = QApplication()
  15. wnd_login = WndClientLogin()
  16. wnd_login.show()
  17. if wnd_login.exec_() == QDialog.Accepted:
  18. print("已接受")
  19. sys.exit(0)