PyQt5中的信号我的理解就像饭店出菜口的那个铃,➡️
需要的时候就是“叮”一下.然后厨师会叫出菜名或者桌号,服务员就会把菜送到正确的顾客桌上.
下面说正体:(此处不讲什么信号与槽,single与slot,我觉得太复杂)
关于自定义信号,你需要掌握以下几个点:
下面我们要实现这样一个例子:有一个QTableView控件(3*3大小),无论我们单击哪个单元格,都会在控制台输出该行的第一列的内容.
需要自定义某个控件的信号,你需要创建一个新类继承原来的类,比如:
class MyTableView(QTableView):
def __init__(self, parent = None):
super(MyTableView,self).__init__(parent)
这里我们就创建了一个自己的MyTableView类,继承于QTableView.
他的用法跟正常的QTableView用法一毛一样,然后我们就要来对信号进行声明
class MyTableView(QTableView):
doubleClickedItem = pyqtSignal(str)
def __init__(self, parent = None):
super(MyTableView,self).__init__(parent)
在初始化函数__init__ 之前加入的就是自定义信号的申明,这个声明只能在初始化函数外面,pyqtSignal这个类是在PyQt5.QtCore里面.
参数(str),这个参数只能是数据类型,不能是变量名,表示这个信号发送的是一个字符串,你也可以发送任何你需要的类型,比如:
信号名 = pyqtSignal(类型)
mySignal = pyqtSignal(int) #发送int型数据
mySignal = pyqtSignal(float) #发送float型数据
mySignal = pyqtSignal(str, int) #发送的信号第一个是str,第二个是int
mySignal = pyqtSignal(int, int, int, ...) #发送几个都可以
mySignal = pyqtSignal(list) #发送list,如[1,2,3]['a','b','c']等
声明完了,就需要决定什么时候来触发他.
需要双击来触发这个信号,我们要先看看官方有没有给出什么方法,通过官方文档找到一个差不多的:
不断的查他的定义,发现这个也是个信号,发送的是QModelIndex类型的index,可以告诉我们是哪个位置的单元格被双击了,有点接近但也不是我们需要的[该行第一列]的内容,所以需要借助这个信号来处理以下:
class MyTableView(QTableView):
doubleClickedItem = pyqtSignal(str)
def __init__(self, parent = None):
super(MyTableView,self).__init__(parent)
self.doubleClicked.connect(self.doubleClickedHandle)
def doubleClickedHandle(self, index):
text = self.model().item(index.row(),0).text()
self.doubleClickedItem.emit(text)
__init__中的self.doubleClicked.connect(self.doubleClickedHandle)表示把自己创建的类的doubleClicked信号连接到doubleClickedHandle函数,注意这个参数中的函数只有名字,没有括号,连接信号的格式为:
某个类.某个信号.connect(接收函数)
然后再来doubleClickedHandle中处理接收的函数.详细内容将在下一节讲解
函数中的text就是获取了被双击的单元格所在行的第一列内容.
然后通过emit方法发送出去.格式为:
某个信号.emit(信号内容)
信号内容的类型必须和声明时定义的类型一致
处理完以后我们我们要来处理如何接收这个信号.
在发送我们自己的信号时已经进行了一次信号的接收处理,只不过这个信号的定义和触发都是PyQt自己定义好的,我们只是完成接收处理:
从文档中可以看到这个信号有一个QModelIndex类型的index参数,这里我们必须要得到这个参数才能知道点击了哪一个单元格,所以处理函数doubleClickedHandle必须有一个在同位置同类型的参数:
def doubleClicked(self, QModelIndex): #信号的定义
pass
def doubleClickedHandle(self, index): #接收函数的定义
pass
QModelIndex与index是同一个类型,而且必须在同一个位置:
mySignal = pyqtSignal(str, float, int) #定义一个信号发送三个值
def mySignalHandle(par1, par2, par3): #接收函数
pass #par1收到的是str,par2收到的是float,par3收到的是int
def doubleClickedHandle(self, index):
text = self.model().item(index.row(),0).text()
self.doubleClickedItem.emit(text)
第二行中,index.row()获取被双击的行号(int型)
self.model().item(row, column),通过设置row和column值来定位单元格,最后的.text()获取文本内容,
详细不多做解释官方文档里面都有,这里只重点讲解信号.
最后一行:就是把获取到的第一列的单元格内容通过信号doubleClickedItem发送出去.
在外的话我们也要接收doubleClickedItem这个信号,接收函数就是print:
myTable是上面MyTableView的一个实例,在某个地方我可以这样来接收信号:
myTable.doubleClickedItem.connect(print)
实现的效果就是双击任意单元格可以打印出该行第一列的单元格内容
关于自定义信号,你需要掌握以下几个点:
信号的声明: 信号名 = pyqtSignal(类型)
信号的触发: 信号名.emit(信号内容)
信号的接收: 信号所在类实例.信号名.connect(接收函数)
完整代码
from PyQt5.QtWidgets import QApplication
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtCore import pyqtSignal
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('')
self.initUI()
self.show()
def initUI(self):
table = MyTableView(self)
model = QStandardItemModel()
model.setColumnCount(3)
[model.appendRow([QStandardItem(str(i + j)) for i in [0,1,2]])for j in [1,2,3]]
table.setModel(model)
table.doubleClickedItem.connect(print)
self.setCentralWidget(table)
class MyTableView(QTableView):
doubleClickedItem = pyqtSignal(str)
def __init__(self, parent = None):
super(MyTableView,self).__init__(parent)
self.doubleClicked.connect(self.doubleClickedHandle)
def doubleClickedHandle(self, index):
text = self.model().item(index.row(),0).text()
#单元格没有值时会出错,None type没有text()这个方法,如有需要自己catch
self.doubleClickedItem.emit(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec_())