PySide/PyQt Tutorial: Creating Your Own Signals and Slots

This article is part 5 of 8 in the series Python PySide/PyQt Tutorial
Published: Wednesday 6th February 2013 
Last Updated: Tuesday 9th December 2014
 
 
 
 

You don't have to rely solely on the signals that are provided by Qt widgets, however; you can create your own. Signals are created using the Signal class. A simple signal definition would be:

 
1
2
from PySide.QtCore import Signal
tapped = Signal()

Then, when the conditions for the object being tapped are satisfied, you call the signal's emit method, and the signal is emitted, calling any slots to which it is connected:

 
1
thing.tapped.emit()

This is good for two reasons; first, it allows users of your objects to interact with them in familiar ways; and second, it allows your objects to be used more flexibly, leaving the definition effects of actions on your object to the code that uses them.

A Simple PySide/PyQt Signal Emitting Example

Let's define a simple PunchingBag class that does only one thing: when its punch is called, it emits a punchedsignal:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PySide.QtCore import QObject, Signal, Slot
 
class PunchingBag(QObject):
    ''' Represents a punching bag; when you punch it, it
        emits a signal that indicates that it was punched. '''
    punched = Signal()
 
    def __init__(self):
        # Initialize the PunchingBag as a QObject
        QObject.__init__(self)
 
    def punch(self):
        ''' Punch the bag '''
        self.punched.emit()

You can easily see what we've done. The PunchingBag inherits from QObject so it can emit signals; it has a signal called punched, which carries no data; and it has a punch method which does nothing but emit the punched signal.

To make our PunchingBag useful, we need to connect its punched signal to a slot that does something. We'll define a simple one that prints, "Bag was punched" to the console, instantiate our PunchingBag, and connect its punched signal to the slot:

 
1
2
3
4
5
6
7
8
@Slot()
def say_punched():
    ''' Give evidence that a bag was punched. '''
    print('Bag was punched.')
 
bag = PunchingBag()
# Connect the bag's punched signal to the say_punched slot
bag.punched.connect(say_punched)

Then, we'll punch the bag and see what happens:

 
1
2
3
# Punch the bag 10 times
for i in range(10):
    bag.punch()

When you put it all in a script and run it, it will print:

 
1
2
3
4
5
6
7
8
9
10
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.
Bag was punched.

Effective, but not particularly impressive. However, you can see the usefulness of it: our punching bag would be a good fit anywhere you need a bag that reacts to punching, because the PunchingBag leaves implementation of a reaction to punching to the code that uses it.

Data-Carrying PySide/PyQt Signals

One of the most interesting things you can do when creating signals is to make them carry data. For example, you could make a signal carry an integer, thus:

 
1
updated = Signal(int)

or a string:

 
1
updated = Signal(str)

The datatype may be any Python type name or a string identifying a C++ datatype. Since this tutorial presupposes no C++ knowledge, we'll stick to Python types.

A PySide/PyQt Signal-Sending Circle

Let's define a Circle with properties xy, and r, denoting the x and y position of the center of the circle, and its radius, respectively. You might want to have one signal that is emitted when the circle is resized, and another that is emitted when it is moved; we'll call them resized and moved, respectively.

It would be possible to have the slots to which the resized and moved signals are connected check the new position or size of the circle and respond accordingly, but it's more convenient and requires less knowledge of circles by the slot functions if the signal that is sent can include that information.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from PySide.QtCore import QObject, Signal, Slot
 
class Circle(QObject):
    ''' Represents a circle defined by the x and y
        coordinates of its center and its radius r. '''
    # Signal emitted when the circle is resized,
    # carrying its integer radius
    resized = Signal(int)
    # Signal emitted when the circle is moved, carrying
    # the x and y coordinates of its center.
    moved = Signal(int, int)
 
    def __init__(self, x, y, r):
        # Initialize the Circle as a QObject so it can emit signals
        QObject.__init__(self)
 
        # "Hide" the values and expose them via properties
        self._x = x
        self._y = y
        self._r = r
 
    @property
    def x(self):
        return self._x
 
    @x.setter
    def x(self, new_x):
        self._x = new_x
        # After the center is moved, emit the
        # moved signal with the new coordinates
        self.moved.emit(new_x, self.y)
 
    @property
    def y(self):
        return self._y
    @y.setter
    def y(self, new_y):
        self._y = new_y
        # After the center is moved, emit the moved
        # signal with the new coordinates
        self.moved.emit(self.x, new_y)
 
    @property
    def r(self):
        return self._r
 
    @r.setter
    def r(self, new_r):
        self._r = new_r
        # After the radius is changed, emit the
        # resized signal with the new radius
        self.resized.emit(new_r)

Note these salient points:

  • The Circle inherits from QObject so it can emit signals.
  • The signals are created with the signature of the slot to which they will be connected.
  • The same signal can be emitted in multiple places.

Now, let's define some slots that can be connected to the Circle's signals. Remember last time, when we said we'd see more about the @Slot decorator? We now have signals that carry data, so we'll see how to make slots that can receive it. To make a slot accept data from a signal, we simply define it with the same signature as its signal:

 
1
2
3
4
5
6
7
8
9
# A slot for the "moved" signal, accepting the x and y coordinates
@Slot(int, int)
def on_moved(x, y):
    print('Circle was moved to (%s, %s).' % (x, y))
 
# A slot for the "resized" signal, accepting the radius
@Slot(int)
def on_resized(r):
    print('Circle was resized to radius %s.' % r)

Very simple and intuitive. For more information on Python decorators, you might want to checkout the article - Python Decorators Overview to familiarise yourself.

Finally, let's instantiate a Circle, hook up the signals to the slots, and move and resize it:

 
1
2
3
4
5
6
7
8
9
10
11
c = Circle(5, 5, 4)
 
# Connect the Circle's signals to our simple slots
c.moved.connect(on_moved)
c.resized.connect(on_resized)
 
# Move the circle one unit to the right
c.x += 1
 
# Increase the circle's radius by one unit
c.r += 1

When you run the resulting script, your output should be:

 
1
2
Circle was moved to (6, 5).
Circle was resized to radius 5.

Now that we've developed a better understanding of signals and slots, we are ready to use some more advanced widgets. In our next instalment, we will begin to discuss the QListWidget and QListView, two ways of creating list box controls.

pyqt的信号槽机制(转)的更多相关文章

  1. QT信号槽机制

    信号槽 信号槽是QT中用于对象间通信的一种机制,也是QT的核心机制.在GUI编程中,我们经常需要在改变一个组件的同时,通知另一个组件做出响应.例如: 一开始我们的Find按钮是未激活的,用户输入要查找 ...

  2. C++11实现Qt的信号槽机制

    概述 Qt的信号槽机制是Qt的核心机制,按钮点击的响应.线程间通信等都是通过信号槽来实现的,boost里也有信号槽,但和Qt提供的使用接口很不一样,本文主要是用C++11来实现一个简单的信号槽,该信号 ...

  3. VJGUI消息设计-兼谈MFC、QT和信号/槽机制

    星期六下午4点,还在公司加班.终于写完了下周要交工的一个程序. 郁闷,今天这几个小时写了有上千行代码吧?虽然大部分都是Ctrl-C+Ctrl-V,但还是郁闷. 作为一个有10年经验的MFC程序员,郁闷 ...

  4. Qt学习记录--02 Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)

    一 闲谈: 熟悉Window下编程的小伙伴们,对其消息机制并不陌生, 话说:一切皆消息.它可以很方便实现不同窗体之间的通信,然而MFC库将很多底层的消息都屏蔽了,尽管使用户更加方便.简易地处理消息,但 ...

  5. Qt开发之信号槽机制

    一.信号槽机制原理 1.如何声明信号槽 Qt头文件中一段的简化版: class Example: public QObject { Q_OBJECT signals: void customSigna ...

  6. QT源码之Qt信号槽机制与事件机制的联系

    QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...

  7. QT写hello world 以及信号槽机制

    QT是一个C++的库,不仅仅有GUI的库.首先写一个hello world吧.敲代码,从hello world 写起. #include<QtGui/QApplication> #incl ...

  8. 非Qt工程使用Qt的信号槽机制

    非Qt工程,使用Qt的信号槽机制,蛋疼不?反正我现在就是要做这样一件蛋疼的事. 要使用Qt的信号槽机制,下面是从Qt Assist里面关于 signal & slots 的一句介绍: All ...

  9. QT学习记录之理解信号槽机制

    作者:朱金灿 来源:http://blog.csdn.net/clever101 QT的事件机制采用的信号槽机制.所谓信号槽机制,简而言之就是将信号和信号处理函数绑定在一起,比如一个按钮被单击是一个信 ...

随机推荐

  1. jQuery中Animate进阶用法(一)

    jQuery中animate的用法你了解多少呢?如果仅仅是简单的移动位置,显示隐藏,哦!天哪你在浪费资源!因为animate太强大了,你可以有很多意想不到的用法!让我们一起研究一下吧~~ 首先要了解j ...

  2. 数据库(Database)

    一.定义 1. 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,简单来说是本身可视为电子化的件柜--存储电子文件的处所,用户可以对文件中的数据进行新增.截取.更新.删除等操作.数 ...

  3. 【Kubernetes】K8S网络方案--最近在看的

    K8S网络-最近在看的 Create a Minikube cluster - Kubernetes Kubernetes Documentation - Kubernetes Kubernetes ...

  4. 各大浏览器内核特性及对应的Browserhacks举例

    1.浏览器内核指的是什么? 简化的浏览器=用户界面+渲染引擎+js解析引擎+数据存储+网络部件 而通常所说的浏览器内核指的是页面渲染引擎(rendering engine). 2.渲染引擎 The r ...

  5. [恶趣味]搞了下局域网内的arp网络欺骗

    挺无聊的. 扫描,伪装,抓包. 基本上搞完就失去乐趣了. 文章在这里,想搞的可以自己拿去搞下,其实很无聊,我真是个很容易无聊的人啊.

  6. mysql 命令导入导出

    导出 mysqldump -u 用户名 -p 数据库名 > 导出的文件名mysqldump -u root -p dataname >xxx.sql 导入 mysql>source ...

  7. Best code水题之路

    BestCoder 2nd Anniversary: 1001.Oracle There is once a king and queen, rulers of an unnamed city, wh ...

  8. context:component-scan标签的use-default-filters属性的作用以及原理分析

    一.背景 我们在Spring+SpringMVC+Mybatis的集成开发中,经常会遇到事务配置不起作用等问题,那么本文就来分析下出现这种问题可能的原因以及解决方式. 二.分析及原理窥探 1.项目结构 ...

  9. Jsonp调用网易云音乐API搜索播放歌曲

    效果如下图: 基本就是正常的文件播放,暂停,停止,设置循环,随机播放,加速,减速,上一曲,下一曲,再多个选择本地文件加入到播放列表的功能.然后想着给加个能搜索网络歌曲并且播放的功能,今天研究了一下,成 ...

  10. Erlang--etc结构解析

    Erlang中可以用List表达集合数据,但是如果数据量特别大的话在List中访问元素就会变慢了;这种主要是由于List的绝大部分操作都是基于遍历完成的. Erlang的设计目标是软实时(参考:htt ...