GUI 的程序开发人员并非需要甚至根本不需要知道所有的控件实现的底层细节,我们只需要知道当按钮按下时能够适当的相应即可。基于这一原因,Qt 和 pyqt 提供了两种通信机制:低级事件处理机制和高级事件处理机制,前者与其他 GUI 库提供的功能类似,或者被称之为 “信号与槽”。

QT 的一个关键特性是它使用信号和槽来进行对象之间的通讯。当一个组件发出一个信号时,一个可用的插槽应应该做出相应。如果一个信号连接到一个插槽,那么当信号被发射时,该插槽应该被调用。如果信号没有连接,则不会发生任何事情。

信号与槽机制的特点

信号可能连接到很多插槽

信号也可能连接到另外一个信号

信号参数可以是任何 python 类型

一个插槽可能连接到许多信号

连接可以是直接的 (同步) 也可是是排队的 (异步)

连接可以跨线程

连接可能中断

绑定和未绑定信号

信号(特别是非绑定信号)是作为 QObject 子类的类的属性。一个绑定信号具有connect(),disconnect()和emit()实现相关联的功能的方法。要截取一个信号必须把它连接到槽上。

连接信号与槽的语法形式

QtCore.QObject.connect(a, QtCore.SIGNAL('QtSig()'), pyFunction)

QtCore.QObject.connect(a, QtCore.SIGNAL('QtSig()'), pyClass.pyMethod)

QtCore.QObject.connect(a, QtCore.SIGNAL('QtSig()'), b, QtCore.SLOT('QtSlot()'))

QtCore.QObject.connect(a, QtCore.SIGNAL('PySig()'), b, QtCore.SLOT('QtSlot()'))

QtCore.QObject.connect(a, QtCore.SIGNAL('PySig'), pyFunction)

以上语法可以理解为:连接 a 对象的信号到槽函数或者某个 b 对象的某个函数。

发射信号与槽的语法

a.emit(QtCore.SIGNAL('clicked()'))

a.emit(QtCore.SIGNAL('pySig'), "Hello", "World")

发射一个信号,也可以带参数。

内置的信号与槽

大部分的窗口控件都提前预置了一些槽,所以很多时候可以直接把预置的信号和预置的槽相连接,无需做任何事情就可以得到想要的行为效果。

下面我们看两个简单的窗口部件 Dial 和 SpinBox。这两个窗口部件都有 valueChange() 信号,当这个信号触发时就会带有新值。这两个窗口部件也都有 setValue() 槽,带有整数型参数。因此可以将两个部件的信号和槽连接起来,无论用户改变哪一个窗口部件,都会让另一个值做出改变。

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'D:\pyqtSingAndSloft\SingSloftDialog.ui'

#

# Created by: PyQt4 UI code generator 4.11.4

#

# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:

_fromUtf8 = QtCore.QString.fromUtf8

except AttributeError:

def _fromUtf8(s):

return s

try:

_encoding = QtGui.QApplication.UnicodeUTF8

def _translate(context, text, disambig):

return QtGui.QApplication.translate(context, text, disambig, _encoding)

except AttributeError:

def _translate(context, text, disambig):

return QtGui.QApplication.translate(context, text, disambig)

class Ui_Dialog(object):

def setupUi(self, Dialog):

Dialog.setObjectName(_fromUtf8("Dialog"))

Dialog.resize(400, 300)

Dialog.setSizeGripEnabled(True)

self.dial = QtGui.QDial(Dialog)

self.dial.setGeometry(QtCore.QRect(60, 100, 50, 64))

self.dial.setObjectName(_fromUtf8("dial"))

self.spinBox = QtGui.QSpinBox(Dialog)

self.spinBox.setGeometry(QtCore.QRect(190, 120, 54, 25))

self.spinBox.setObjectName(_fromUtf8("spinBox"))

self.retranslateUi(Dialog)

QtCore.QMetaObject.connectSlotsByName(Dialog)

def retranslateUi(self, Dialog):

Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))

if __name__ == "__main__":

import sys

app = QtGui.QApplication(sys.argv)

Dialog = QtGui.QDialog()

ui = Ui_Dialog()

ui.setupUi(Dialog)

Dialog.show()

sys.exit(app.exec_())

继承上面的窗口来编写我们的信号与槽:

# -*- coding: utf-8 -*-

"""

Module implementing Dialog.

"""

from PyQt4 import QtGui

from PyQt4.QtGui import *

from PyQt4.QtCore import *

from Ui_SingSloftDialog import Ui_Dialog

class Dialog(QDialog, Ui_Dialog):

"""

Class documentation goes here.

"""

def __init__(self, parent=None):

"""

Constructor

@param parent reference to the parent widget

@type QWidget

"""

QDialog.__init__(self, parent)

self.setupUi(self)

# 连接信号与槽

self.connect(self.dial, SIGNAL('valueChanged(int)'), self.spinBox.setValue)

self.connect(self.spinBox, SIGNAL('valueChanged(int)'), self.dial.setValue)

if __name__ == "__main__":

import sys

app = QtGui.QApplication(sys.argv)

ui = Dialog()

ui.show()

sys.exit(app.exec_())

运行结果:

如果用户拖动拨号盘为 20,此时拨号盘就会发射一个 valueChange(20) 的信号,相应的就会对输入框的 setValue() 槽进行调整,并将 20 作为参数传递进去。相反输入框的值发生改变拨号盘的槽函数也会触发。貌似会发生死循环,其实不用担心,如果传递额值并未发生改变 valueChange() 就不会再次发射信号。

第二种写法

在上边的拨号盘例子中我们用的是 instance.metnodName() 的语法。但是当槽函数实际上是个 Qt 槽而不是 Python 方法时,用 SLOT() 语法可能会更高效。

self.connect(dial,SIGNAL("valueChanged(int)"),spinbox,SLOT("setValue(int)"))

self.connect(spinbox,SIGNAL("valueChanged(int)"),dial,SLOT("setValue(int)"))

使用 QObject.connect() 可以建立各类连接,也可以使用 QObject.disconnect() 来取消这些连接。实际应用中我们并不需要自己去取消这些连接,这是因为,当删除一个对象后,PyQt 就会自动断开改对象的所有连接。

发射自定义信号的组件

我们已经知道如何连接信号与槽函数,这些槽就是一些常规的函数或者方法。但是如果我们想创建一个可以发射自定义信号的组件该怎么办呢?使用 QObject.emit() 就可以轻松的实现这一点。

class ZeroSpinBox(QSpinBox):

zeros =0

def __init__(self, parent=None):

super(ZeroSpinBox, self).__init__(parent)

# 首先是把 valueChange 信号连接到 checkzeor() 函数

self.connect(self, SIGNAL('valueChanged(int)'),self.checkzeor )

def checkzeor(self):

if self.value() ==0:

self.zeros += 1

# 发射一个名为 amout 的信号,并且带上参数

self.emit(SIGNAL('amount'), self.zeros)

继续修改刚才的例子:

class Dialog(QDialog, Ui_Dialog):

"""

Class documentation goes here.

"""

def __init__(self, parent=None):

"""

Constructor

@param parent reference to the parent widget

@type QWidget

"""

QDialog.__init__(self, parent)

# 初始化刚刚自定义的控件

zerospinbox = ZeroSpinBox()

layout = QHBoxLayout()

layout.addWidget(zerospinbox)

self.setLayout(layout)

self.setupUi(self)

self.connect(self.dial, SIGNAL('valueChanged(int)'), self.spinBox.setValue)

self.connect(self.spinBox, SIGNAL('valueChanged(int)'), self.dial.setValue)

# 把控件里边定义的 amount 信号绑定到 announce 函数

self.connect(zerospinbox, SIGNAL('amount'), self.announce)

def announce(self, zeros):

print '等于0的次数' + str(zeros)

if __name__ == "__main__":

import sys

app = QtGui.QApplication(sys.argv)

ui = Dialog()

ui.show()

sys.exit(app.exec_())

执行结果:

不同信号连接到同一个槽上

我们之前的例子把不同的信号连接到同一个槽上,也不关心是谁发射了这个信号。有时候我们需要将两个或者更多的信号连接到同一个槽上,并需要根据连接的不同信号做出不同的反应。

如图我们有 5 个按钮和 1 个标签:

定义不同的槽

先说最简单的连接,这个连接用在 button1 中。下面是 button1 的连接方式:

self.connect(button1, SIGNAL("clicked()"), self.one)

我们定义一个 one() 方法去改变标签的值:

def one(self):

self.label.setText("You clicked button 'One'")

使用 Python2.5 之后的高阶函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

def partial(func, arg):

def callme():

return func(arg)

return callme

使用这个高阶函数作为槽函数:

self.button2callback = partial(self.anyButton, "Two")

self.connect(button2, SIGNAL("clicked()"),self.button2callback)

在我们的定义函数里边改变标签的值:

def anyButton(self, who):

self.label.setText("You clicked button '%s'" % who)

连接到同一个槽函数

如果将不同的槽连接到同一个槽函数我们使用 self.sender() 来发现信号是来自哪个 QObject 对象。

绑定信号:

self.connect(button4, SIGNAL("clicked()"), self.clicked)

self.connect(button5, SIGNAL("clicked()"), self.clicked)

定义函数:

def clicked(self):

button = self.sender()

if button is None or not isinstance(button, QPushButton):

return

self.label.setText("You clicked button '%s'" % button.text())

总结

PyQt 信号与槽的机制需要好好的理解,更重要的是需要大量的实践才能理解。

python槽怎么用_PyQt4信号与槽详解相关推荐

  1. Python Qt GUI设计:信号与槽的使用方法(基础篇—7)

    目录 1.信号与槽的概念 2.信号与槽的基础函数 2.1.创建信号函数 2.2.连接信号函数 2.3.断开信号函数 2.4.发射信号函数 3.信号和槽的使用方法 3.1.内置信号与槽的使用 3.2.自 ...

  2. Python必备基本技能——命令行参数args详解

    Python必备基本技能--命令行参数args详解 1. 效果图 2. 源码 2.1 简单命令行参数 2.1 轮廓检测源代码 参考 这篇博客将介绍一项开发人员.工程师和计算机科学家必备的技能--命令行 ...

  3. python判断是否回文_对python判断是否回文数的实例详解

    设n是一任意自然数.若将n的各位数字反向排列所得自然数n1与n相等,则称n为一回文数.例如,若n=1234321,则称n为一回文数:但若n=1234567,则n不是回文数. 上面的解释就是说回文数和逆 ...

  4. python中的class怎么用_对python 中class与变量的使用方法详解

    python中的变量定义是很灵活的,很容易搞混淆,特别是对于class的变量的定义,如何定义使用类里的变量是我们维护代码和保证代码稳定性的关键. #!/usr/bin/python #encoding ...

  5. python当型循环_对python while循环和双重循环的实例详解

    废话不多说,直接上代码吧! #python中,while语句用于循环执行程序,即在某个条件下,循环执行某段程序,以处理需要重复处理的相同任务. #while是"当型"循环结构. i ...

  6. python画三维平面-Python 绘制酷炫的三维图步骤详解

    通常我们用 Python 绘制的都是二维平面图,但有时也需要绘制三维场景图,比如像下面这样的: 这些图怎么做出来呢?今天就来分享下如何一步步绘制出三维矢量(SVG)图. 八面体 我们先以下面这个八面体 ...

  7. python 制作gif-利用Python如何制作好玩的GIF动图详解

    前言 之前我们分享过用Python进行可视化的9种常见方式.其实我们还能让可视化图形逼格更高一些,今天就分享一下如何让可视化秀起来:用Python和matplotlib制作GIF图表. 假如电脑上没有 ...

  8. python的编程模式-Python设计模式之状态模式原理与用法详解

    本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...

  9. python画二维散点图-基于python 二维数组及画图的实例详解

    1.二维数组取值 注:不管是二维数组,还是一维数组,数组里的数据类型要一模一样,即若是数值型,全为数值型 #二维数组 import numpy as np list1=[[1.73,1.68,1.71 ...

最新文章

  1. 判断点是否在一个任意多边形中
  2. OC-Foundation框架
  3. java invokeall 阻塞_ExecutorService.invokeAll并关闭
  4. hadoop join之semi join
  5. C++中提高程序运行效率的方法集合
  6. eyoucms内容添加发布
  7. git branch commands
  8. Spring Boot + Web Socket 实现扫码登录,这种方式太香了!!
  9. Android 高德地图 Native method not found: com.autonavi.amap.mapcore.MapCore.nativeNewInstance:(Ljava/lan
  10. MySQL操作命令-学习笔记随时记录
  11. 明明都保意外,定期寿险和意外险到底区别在哪里?
  12. IEEE ICCSE 2022 Call for Papers (征文公告)
  13. JS下载文件|无刷新下载文件
  14. 数据库——mvcc简介
  15. CNN网络实现手写数字(MNIST)识别 代码分析
  16. android 清华镜像,清华镜像网站下载android源码并编译
  17. 达飞云贷:玩转节日,给你不一样的惊喜!
  18. matlab答案1 8章,MATLAB基础与应用教程 习题答案 作者 蔡旭晖 刘卫国 蔡立燕 第1-8章答案...
  19. 南京邮电大学计算机非全调剂,南京邮电大学2018年拟接收(非全日制)考研调剂公告...
  20. RationalDMIS 7.1 导入IGES/step数模记录DMIS语句

热门文章

  1. 自然语言处理系列二十二》词性标注》词性标注原理》词性介绍
  2. 搜狗linux输入法皮肤,linux下使用搜狗输入法皮肤(.ssf)
  3. 戴尔R730服务器增加内存,多功能存储密集型 戴尔R730xd拆解评测
  4. 【OpenCV入门到精通之五】视频固定位置叠加图片或者另一个视频
  5. 面试感悟----一名3年工作经验的程序员应该具备的技能,对于一些入门或者还在面试阶段的人有着很大的启发...
  6. android中 cdf文件的作用是什么意思,行情艰难,Android初中高级面试题,附详细答案...
  7. linux kernle 同步原语
  8. 2021年中国可见光通信(VLC)市场趋势报告、技术动态创新及2027年市场预测
  9. 成为明星程序员的独特秘密
  10. 重新认识史蒂夫·乔布斯