PySide——Python图形化界面入门教程(四)
——创建自己的信号槽
——Creating Your Own Signals and Slots
原文链接:外链网址已屏蔽
你不必局限于Qt widget提供的信号,你可以使用Signal类来创建自己的信号。下面是一个定义的简单例子:
1 from PySide.QtCore importSignal2 tapped = Signal()
然后,当对象需要触发信号的条件满足时,你可以使用信号的emit方法,来发出信号调用关联的槽。
thing.tapped.emit()
这样做有两个优点:第一,允许用户和你定义的对象随意交互;第二,让你的对象使用更加灵活,让自己的代码定义动作行为的影响。
一个简单的PySide信号例子
我们来定义一个简单的PunchingBag类,它只做一件事情,当punch被调用时,发出punched信号:
1 from PySide.QtCore importQObject, Signal, Slot2
3 classPunchingBag(QObject):4 '''Represents a punching bag; when you punch it, it5 emits a signal that indicates that it was punched.'''
6 punched =Signal()7
8 def __init__(self):9 #Initialize the PunchingBag as a QObject
10 QObject.__init__(self)11
12 defpunch(self):13 '''Punch the bag'''
14 self.punched.emit()
代码非常的简单:PunchingBag继承自QObject,所以它可以发出信号;它有一个称为punched的信号,不携带任何数据;并且他有一个仅仅发出punched信号的punch方法。
为了让PunchingBag更丰富一些,我们需要将它的punched信号和一个槽连接。槽简单的输出“Bag was punched”。
1 @Slot()2 defsay_punched():3 '''Give evidence that a bag was punched.'''
4 print('Bag was punched.')5
6 bag =PunchingBag()7 #Connect the bag's punched signal to the say_punched slot
8 bag.punched.connect(say_punched)9
10 #Punch the bag 10 times
11 for i in range(10):12 bag.punch()
携带数据的PySide信号
创建信号可以完成一个非常有用的事情——携带数据。例如,你可以创建一个携带整数或者字符串的信号:
updated = Signal(int)
updated=Signal(str)
这个数据类型可以是任何Python的类型名或定义了C++类型的字符串。因为教程不假设有任何C++的知识,故我们只使用Python类型。
例子:一个发送信号的圆
我们用x,y和r定义一个圆,x、y是圆中心的坐标,r是半径。我们想要当圆被改变大小时,发送一个信号resized;当圆被移动时,也发送一个信号moved。虽然我们可以在信号的槽中检测圆的大小和位置,但是使用信号发送这些信息会更加方便。
1 from PySide.QtCore importQObject, Signal, Slot2
3 classCircle(QObject):4 '''Represents a circle defined by the x and y5 coordinates of its center and its radius r.'''
6 #Signal emitted when the circle is resized,
7 #carrying its integer radius
8 resized =Signal(int)9 #Signal emitted when the circle is moved, carrying
10 #the x and y coordinates of its center.
11 moved =Signal(int, int)12
13 def __init__(self, x, y, r):14 #Initialize the Circle as a QObject so it can emit signals
15 QObject.__init__(self)16
17 #"Hide" the values and expose them via properties
18 self._x =x19 self._y =y20 self._r =r21
22 @property23 defx(self):24 returnself._x25
26 @x.setter27 defx(self, new_x):28 self._x =new_x29 #After the center is moved, emit the
30 #moved signal with the new coordinates
31 self.moved.emit(new_x, self.y)32
33 @property34 defy(self):35 returnself._y36 @y.setter37 defy(self, new_y):38 self._y =new_y39 #After the center is moved, emit the moved
40 #signal with the new coordinates
41 self.moved.emit(self.x, new_y)42
43 @property44 defr(self):45 returnself._r46
47 @r.setter48 defr(self, new_r):49 self._r =new_r50 #After the radius is changed, emit the
51 #resized signal with the new radius
52 self.resized.emit(new_r)
View Code
注意以下几点:
Circle继承自QObject所以可以发送信号
同样的信号可以在不同地方发送
现在我们定义一些连接Circle的信号的槽。还记得我们上次提过的@Slot修饰符(decorator)吗?现在我们来看看如何接收携带了数据的信号。为了接收信号,我们简单的将其定义为与信号一样的结构。
1 #A slot for the "moved" signal, accepting the x and y coordinates
2 @Slot(int, int)3 defon_moved(x, y):4 print('Circle was moved to (%s, %s).' %(x, y))5
6 #A slot for the "resized" signal, accepting the radius
7 @Slot(int)8 defon_resized(r):9 print('Circle was resized to radius %s.' % r)
非常的简单直观。更多信息可以参考Python decorators,或者来学习这篇文章Python Decorators Overview。最后我们完成这个Circle,连接信号槽,移动并改变它的大小。
1 c = Circle(5, 5, 4)2
3 #Connect the Circle's signals to our simple slots
4 c.moved.connect(on_moved)5 c.resized.connect(on_resized)6
7 #Move the circle one unit to the right
8 c.x += 1
9
10 #Increase the circle's radius by one unit
11 c.r += 1
View Code
当运行脚本的时候,你的结果应该是:
Circle was moved to (6, 5).
Circle was resized to radius5.
View Code
现在我们对信号和槽有了更深入的了解,可以准备使用一些更高级的widgets了。下一个教程开始讨论QListWidget和QListView,两种创建表框(list box)控件的方法。
By Ascii0x03
转载请注明出处:外链网址已屏蔽