PyQt学习Ⅲ(事件,信号和对话框)

Events and signals in PyQt5(PyQt5中的事件和信号)

在PyQt5编程教程的这一部分中,我们将探索应用程序中发生的事件和信号。

Events(事件)

GUI应用程序是事件驱动的。事件主要由应用程序的用户生成。但它们也可以通过其他方式产生; 例如,互联网连接,窗口管理器或计时器。当我们调用应用程序的exec_()方法时,应用程序进入主循环。主循环获取事件并将它们发送到对象。

在事件模型中,有三个参与者:

  • 事件来源

  • 事件对象

  • 事件目标

The event source is the object whose state changes. It generates events. The event object(event) encapsulates the state changes in the event source. The event target is the object that wants to be notified. Event source object delegates the task of handling an event to the event target.(事件来源是状态发生变化的对象,它产生事件,事件对象封装了在事件来源里的状态变化。事件目标是需要被通知的对象。事件源对象将处理事件的任务委托给事件目标。)

PyQt5 has a unique signal and slot mechanism to deal with events. Signals and slots are used for communication between objects. A signal is emitted when a particular event occurs. A slot can be any Python callable. A slot is called when its connected signal is emitted.(PyQt5具有独特的信号和插槽机制来处理事件。信号和插槽用于对象之间的通信。当一个特定事件时,信号被发射。一个槽可以是任何Python可调用的对象,比如说函数。发射连接信号时调用一个插槽。)

信号和slot

扫描二维码关注公众号,回复: 2731820 查看本文章

 

In our example, we display a QtGui.QLCDNumber and a QtGui.QSlider. We change the lcd number by dragging the slider knob.(在我们的例子中,我们显示了一个QtGui.QLCDNumber 和一个 QtGui.QSlider。我们通过拖拉滑槽按钮来改变液晶显示屏上的数字。

sld.valueChanged.connect(lcd.display)

Here we connect a valueChanged signal of the slider to the display slot of the lcd number.

The sender is an object that sends a signal. The receiver is the object that receives the signal. The slot is the method that reacts to the signal.(这里,我们把滑槽的valueChanged信号和lcd显示的数字联系起来。发射器时发送信号的对象,接收器是接受信号的对象,slot是对信号做出反应的方法。)

 

这里面还用了一个QVBoxLayout,至于会产生什么效果,上一讲我们就看到过了。valueChanged没有语法高亮,但是它也是一个方法。

 

 

这个Qt.Orientation的解释参考了http://www.kuqin.com/qtdocument/qt.html

 

如果改成Vertical。滑槽变成竖着了。

 

重新实现事件处理程序

PyQt5中的事件通常通过重新实现事件处理程序来处理。

 

在我们的示例中,我们重新实现了keyPressEvent()事件处理程序。

def keyPressEvent(self,e):       

     if e.key()== Qt.Key_Escape:        

            self.close()

如果我们按下esc键,应用程序将终止。

 

 

 

这种退出方式如果开了两个窗口需要按两次esc,说明不是QApplication级别的退出。

事件对象

Event对象是一个Python对象,它包含许多描述事件的属性。特定的事件对象生成的特定事件类型。

 

 

 

 

我们先开启鼠标追踪,然后关掉。

 

关掉的时候确实是只有鼠标在点击操作时,坐标才会变化,而且显示是有延迟的。

事件发件器

有时,知道哪个小部件是信号的发送者会给我们带来便利。为此,PyQt5有这个sender() 方法。

 

 

self.sender()返回的是PyQt5.QtWidgets.QPushButton类,因为我们发信号是通过按钮发的嘛。要想得到它上面的字符串,用text方法。第一次的 self.statusBar()可以不要。

 

发射信号

从QObject创建的对象a可以发出信号。以下示例显示了我们如何发出自定义信号。

 

我们创造了一个叫做的新信号叫做closeApp。在鼠标按下事件期间发出此信号。信号连接到QMainWindow的 close()这个slot

class Communicate(QObject):       

     closeApp = pyqtSignal()    

用pyqtSignal()创造一个信号作为外部Communicate类的属性,之所以说Communicate是外部的,是因为它是我们自己创建的,这个名字可以不是Communicate,但是要和下面用到的时候匹配。

self.c = Communicate()

self.c.closeApp.connect(self.close)

自定义closeApp信号连接到的QMainWindow的close()这个slot

def mousePressEvent(self,event):       

     self.c.closeApp.emit()

当我们用鼠标指针单击窗口时,closeApp会发出信号。应用程序终止。

在PyQt5教程的这一部分中,我们介绍了信号和插槽。

首先要说明的是self.close中的close是QMainWindow的一个方法。

 

名字绝对不可以错的。

 

然后就是,其实上面的操作,我们不定义一个新的信号也是可以完成的。

 

直接把self.close写在mousePressEvent里面就可以。如果打开了两个窗口,需要点两次鼠标才能退出,左键右键都可以。这个过程中,鼠标按键是一个事件,本身可以赋予很多意义,我们这里把closeApp这个信号和mousePressEvent挂钩,就相当于是鼠标按键这个事件发出了closeApp这个signal,因为closeApp.emit(),这个信号的发射动作在mousePressEvent里面。然后接收了这个信号怎么处理呢?我们通过connect函数把信号和所谓的滑槽(slot)联系在一起,slot一定是callable的,可调用的,就像函数,所以一般别加括号,我说一般是因为可能有闭包的存在,slot一般都是函数名,当然不排除有其它可调用的对象存在,然后接受到信号以后,slot里面的函数就被调用了。整个过程就是鼠标按键事件发生,closeApp信号发出,self.close函数执行。所以我们当然也可写以直接在mousePressEvent里面直接调用self.close了,直接不要发送信号,接收信号。当然这只是mousePressEvent方法里面的代码很少,如果有一种动作对应很多事件,比如说我按鼠标和按esc都可以退出,并且假如退出的代码很长,我要在按鼠标和按esc这两个事件的方法里都写代码无疑是不好的,那么,我们自定义信号无疑可以让代码更少,不过这个例子其实举的不是很好,差点意思。

 

在这里要先吐槽一下sublime的语法高亮,一些关键字,比如说if,import,for等,还有=都是粉色的,然后class,def是蓝色的,魔法方法也是蓝色的,调用函数或者方法是,是蓝色的,像self.c.closeApp.emit()只有最后面的emit是蓝色的,c和closeApp都是白色,然后类或者方法在定义的时候或者继承的时候都是绿色的,然后函数里面的形参是黄色的。这种语法高亮是按照类型来的。还有这里面的补全其实是只针对于在文中出现过的字符,称之为上下文补全,但是这个补全还是不够用的,我们可以安装一个anaconda扩展包。然后就会出现

 

安装过程会有错误,按照错误提示来就可以解决了,它会让你在console控制台输入一段代码,然后还在anaconda的配置文件里面改一个设置。最后会出现一堆框框,看着比较烦,那么就照着https://blog.csdn.net/cds86333774/article/details/51274035这里面说的做。

 

点左下角的那个屏幕一样的图标就会出现一个console,那个就是控制台,我们可以把那一段import socket什么的输进去,回车。ctrl+f是可以调出来搜索框的,改完配置文件以后可以ctrl+S,然后方框就没有了。

虽然可以不用自定义信号就可以实现,不过我们还是学习一下自定义信号,可能还是会有用到的时候,并且上面也有叙述过自定义代码的好处。

 

这一部分自定义信号下面的讲解参考了:https://blog.csdn.net/zhulove86/article/details/52563131。

和https://zhidao.baidu.com/question/1303282159639193259.html。

要说明的是首先signal只能在QObject的子类中定义或者直接从QObject继承。

 

这当然只是一种报错方式,因为你让C继承的类不同,报的错也可能不同。上面的例子是定义无参数的信号。 定义一个有一个整数参数的signal,并且name为qtSignal2:

signal2 = QtCore.pyqtSignal(int, name='qtSignal2')

 利用pySignal物件本身提供的connect,我们可以轻易的将pySignal物件与对应的slot相连。利用pyqtSignal物件所提供的emit function,我们就可以轻易的发出signal:

self.signal2.emit(10)

我简单自定义了一个可以实现参数传递的信号signal2。

 

演示:

 

当然这个自定义看起来没有什么意义,想看更复杂的有意义的,可以去https://blog.csdn.net/zhulove86/article/details/52563131看一看,他里面写的代码比较长而已,但是都可以看懂。

PyQt5中的对话框

对话框窗口或对话框是大多数现代GUI应用程序中不可或缺的一部分。对话框被定义为两个或更多人之间的对话。在计算机应用程序中,对话框是用于与应用程序“对话”的窗口。对话框用于输入数据,修改数据,更改应用程序设置等。

QInputDialog

QInputDialog提供简单的便利对话框,以从用户获取单个值。输入值可以是字符串,数字或列表中的项目。

 

 

因为要返回文本和布尔值,所以需要text和ok两个变量接受参数。

 

值得指出的是,以前在学easygui的时候,它只会返回一个参数,如果点x号退出而不是按cancel退出一般返回的是None,我们还要专门加程序去搞定这个None,现在分成了两个参数,并且点x的时候ok也是false。你这么写也是可以的,只是想说可以实现的思路有很多,要思路开阔,不要死板。

 

QColorDialog

QColorDialog 提供用于选择颜色值的对话框小部件。

 

 

这条线(this line)翻译为这条线让人很无语,应该翻译为这一行。

参考了http://www.kuqin.com/qtdocument/qframe.html#details

 

 

 

值得指出的是这个网站有点老了。

 

 

比较奇怪的是里面用了一个QColorDialog.name,但是没找到。原因是用了函数getColor,一看果然找到了,它指向了QColor。

 

首先,补充一点RGB的知识:

在电脑中,RGB的所谓“多少”就是指亮度,并使用整数来表示。通常情况下,RGB各有256级亮度,用数字表示为从0、1、2...直到255。注意虽然数字最高是255,但0也是数值之一,因此共256级。如同2000年到2010年共是11年一样。

如果都是255,是白的。

 

000是黑的。

 

只要有一个颜色不在0-255的,都会自动置0。

 

print(col.name())打印出来的是一个六位的十六进制数,每两位对应一个颜色,最大就是#ffffff。

 

首先来演示一下整个过程。

 

按钮我们都很熟悉了,根据上面的知识,点dialog后那个选颜色的框是getColor()的结果。点X号返回的col.Valid()是false,cancel也是false,只有点ok返回的是true。那么那个颜色框式怎么来的呢?是self.frm.setStyleSheet("QWidget{ background-color: %s }" 

            % col.name())的结果,并且这里面的参数是有固定格式的,不然会出现各种各样的错误。

 

还可能会有下面的错误。

 

这种就是没办法解析。

 

只有格式正确,整个颜色矩形才会显示。这个background-color只是这个frame的一个属性。

这个前面的QWidget好像是固定的。

 

QFontDialog

QFontDialog 是一个用于选择字体的对话框小部件。

 

 

 

 

 

 

我们就直接来看看btn.setSizePolicy(QSizePolicy.Fixed,  QSizePolicy.Fixed)的效果如何?

 

效果还是很明显的,如果注释掉的话,按钮的大小会随着窗口大小发生变化,至少横向来说是的。

 

 

其实这个btn.setSizePolicy的参数必须有两个,第一个是横向,第二个是纵向,奇数表示大小会随着窗口大小变化,偶数则不会,上面的数字是我随便选的。

QFileDialog

QFileDialog是一个允许用户选择文件或目录的对话框。可以选择打开和保存文件。

 

该示例显示了菜单栏,设置为中心部件的文本编辑窗口小部件和状态栏。菜单项显示的QFileDialog 用于选择文件的项目。文件的内容将加载到文本编辑小部件中。

class Example(QMainWindow):       

     def __init __(self):       

             super().__ init __()               

              self.initUI()

该示例基于QMainWindow窗口小部件,我们设置了文本编辑窗口小部件为中心部件。

fname = QFileDialog.getOpenFileName(self,'Open file','/ home')

我们弹出了QFileDialog。getOpenFileName()方法中的第一个字符串 是标题。第二个字符串指定对话框工作目录。默认情况下,文件筛选器设置为所有文件(*)。

if fname [0]:   

         f = open(fname [0],'r')     

        with f:        

                  data = f.read()            

                   self.textEdit.setText(data)        

读取所选文件名,并将文件内容设置为文本编辑小部件的内容。

在PyQt5教程的这一部分中,我们使用了对话框。

 

 

          

 

QFileDialog.getOpenFileName返回的参数有文件路径和类型,如果点x或者cancel,这来给你个都是空的。所以才有了        if fname[0]:            f = open(fname[0], 'r')这个判断。

            f = open(fname[0], 'r')

            with f:

和with open(fname[0], 'r') as f:效果是一样的,我试过了。

截止目前,还是不需要import sys。

猜你喜欢

转载自blog.csdn.net/qq_41740705/article/details/81259670