zoukankan      html  css  js  c++  java
  • GUI学习之三——QObject学习总结

    鉴于PyQt控件的继承关系,我们先学习PyQt控件的基类——QObject。

     一.所有的QT对象的基类

    我们先看一下PyQt里空间的继承关系,稍微改一下代码,显示出继承关系

    from PyQt5.Qt import *
    import sys
    app = QApplication(sys.argv)
    class Window(QWidget):
        def test(self):
            mros = QObject.mro()
            for mro in mros:
                print(mro)
    
    window = Window()
    window.test()
    sys.exit(app.exec_())
    <class 'PyQt5.QtCore.QObject'>
    <class 'sip.wrapper'>
    <class 'sip.simplewrapper'>
    <class 'object'>

    这就表明了QWidget这个控件的继承呢个关系,可以看出来所有的类,都是基于Python的object这个类的

    二.QObject的功能作用

    由于所有的控件都是继承了QObject,所以他所有的API是各种控件都具备的,下面列举的就是他的功能作用

    1.对戏那个名称、属性的操作(API):

    window = QWidget()   
    window.setObjectName()          #给对象设定一个名称(一般这个名称在整个项目里是唯一的)
    window.objectName()             #获取这个对象的名称
    window.setProperty()            #给对象设置一个属性
    window.property()               #获取对象的某个属性
    window.dynamicPropertyNames()   #获取一个对象中通过setProperty设置的属性名名称

    这里前几个很好理解,设置属性的我们来看一下怎么用

    window = QWidget()
    label = QLabel(window)
    label.setProperty('stat','on')
    label.setProperty('color','green')
    print(label.property('stat'))
    print(label.dynamicPropertyNames())
    on
    [PyQt5.QtCore.QByteArray(b'stat'), PyQt5.QtCore.QByteArray(b'color')]
    运行结论

    特别是在结合qss的ID选择器,属性选择器统一设定样式,具体用法我们在后期再说明。

    2.父子对象操作

    先看下父子对象操作的API

    window.setParent()      #设置父对象
    window.children()       #获取所有子对象
    window.findChild()      #查询某一个子对象
    window.findChildren()   #查询多个子对象

    然后我们要构造这样的父子关系图,该怎么做呢?

    obj0 = QObject()
    obj1 = QObject()
    obj2 = QObject()
    obj3 = QObject()
    obj4 = QObject()
    obj5 = QObject()
    
    obj1.setParent(obj0)
    obj2.setParent(obj0)
    obj3.setParent(obj1)
    obj4.setParent(obj2)
    obj5.setParent(obj2)

    就是这么个结构,将这个的目的是什么呢?

    我们可以搞清这些东西:

    a.一个对象只能有一个父对象,这个父对象是最后被设置的。

    obj2.setParent(obj0)
    obj2.setParent(obj1)

    那么obj2的父对象就是obj1.

    b.用childern获取子对象只能获得直系的子对象

    print(obj0.children())
    [<PyQt5.QtCore.QObject object at 0x000001E2F4724828>, <PyQt5.QtCore.QObject object at 0x000001E2F4724798>]
    运行结论

    [<PyQt5.QtCore.QObject object at 0x000001E2F4724828>, <PyQt5.QtCore.QObject object at 0x000001E2F4724798>]分别是OBj1和OBJ2的地址

     c.findChild常规情况时递归的查找要求的子对象,比如我们把obj3的名字设定为3

    obj3.setObjectName('3')
    print(obj0.findChild(QObject,'3'))

    这样,是可以查找到对应的子对象的,然而可以要求只查询直系的子对象

    print(obj0.findChild(QObject,'3',Qt.FindDirectChildrenOnly))

    这样查询结果就是None了。

    d.如果用findChildren常规情况则返回所有的子对象(包括子对象的子对象)

    print(obj0.findChildren(QObject))

     利用上述的方式,可以批量对控件熟属性进行设置

    window = QWidget()
    label_1 = QLabel(window)
    label_1.move(100,100)
    label_1.setText('标签1')
    label_2 = QLabel(window)
    label_2.setText('标签2')
    label_2.move(200,100)
    btn = QPushButton(window)
    btn.move(200,200)
    window.show()
    for sub_widget in window.findChildren(QLabel):   #遍历对话框内的Label控件,并将其背景色设置为红色
        sub_widget.setStyleSheet('background-color:red')

    e.如果父对象被释放,则子对象被自动释放:用在平时的场景中,就是一个对话框里,包含了很多的控件,这些控件都是这个对话框的子控件。这些子控件收父控件的区域所控制,如果父控件被删除(关闭)时,子控件也相应被删除。

    也就是说,在一个GUI里的内存管理机制是QObject的继承树——所有的对象都是直接或间接的继承自QObject,当创建一个对象时,如果使用了其他的对象作为其父对象,那么他就会被追加到父对象的children列表里。当父对象被销毁是,这个QObject也会被销毁。

    3.信号——槽机制

    信号(signal)和槽(slot)是Qt中的核心机制,主要作用在于对戏那个之间进行通讯,所有继承自QWidget的控件都支持信号——槽的机制

    信号——当一个空间的状态发生改变时,想外界发出的信息

    槽——一个执行某些操作的函数或方法

    这个机制具有以下几个特点

      a.一个信号可以连接多个槽函数

      b.一个信号也可以连接另外一个信号

      c.信号的参数可以是任何Python的数据类型

      d.一个槽可以监听多个信号

    信号处理的常用API有下面几种

    object.信号.connert(槽)   #连接信号和槽
    object.disconnect()       #断开信号和所有槽的连接
    object.blockSignals(bool) #临时取消指定的信号和所有槽的连接bool为True时阻塞,False时取消阻塞
    obj.signalsBlocked()      #获取信号是否被阻塞,若阻塞返回值为True
    obj.receivers(信号)       #返回信号连接的槽个数

     下面就是一个信号与槽的案例,点击按钮,每次点击,标签显示加上‘点击’两个字

    from PyQt5.Qt import *
    import sys
    app = QApplication(sys.argv)
    window = QWidget()
    window.resize(500,500)
    btn = QPushButton(window)
    label = QLabel(window)
    btn.move(100,200)
    btn.resize(100,50)
    btn.setText('点击')
    label.resize(10,50)
    label.move(50,100)
    def test():
        data = label.text()
        data += '点击'
        label.setText(data)
        label.adjustSize() #控件自适应大小,下一章会讲
    btn.clicked.connect(test)
    window.show()
    
    sys.exit(app.exec_())
    信号——槽案例

    进阶案例——改变title后将改变的值付给title

    from PyQt5.Qt import *
    import sys
    app = QApplication(sys.argv)
    
    window = QWidget()
    window.setWindowTitle('123')
    def test(title):
        print(title)
        window.windowTitleChanged.disconnect()  #断开连接
        data = title
        data+= '更改后'
        window.setWindowTitle(data)
        window.windowTitleChanged.connect(test) #重新连接
    
    window.show()
    # btn.clicked.connect(test)
    # window.windowTitleChanged.connect(test)
    window.windowTitleChanged.connect(test)
    window.setWindowTitle('456')
    
    sys.exit(app.exec_())
    信号——槽进阶案例

    在这个案例中槽里将信号和槽做了一次断开,执行完后重新连接,因为信号是改变title后调用槽函数,槽函数是将新的字符串赋值给title。在这里如果不将信号和槽断开后会进入一个死循环。必须要分开后重新连接。

    4.类型判定

    先看一下API

    obj.inherits(父类)     #返回对象是否属于父类
    obj.isWidgetType()    #返回对象是否属于QWidget

    案例——判定控件是否为标签,将所有标签背景色设为red

    from PyQt5.Qt import *
    import sys
    app=QApplication(sys.argv)
    window = QWidget()
    a = QLabel(window)
    a.move(100,200)
    b = QPushButton(window)
    b.move(300,200)
    c = QLabel(window)
    c.move(200,200)
    for widget in window.children():
        if widget.inherits("QLabel"):
            widget.setStyleSheet('background-color:red')
    window.show()
    
    sys.exit(app.exec_())
    类型判定案例

     5.对象删除

    API

    obj.deleteLater()

    删除一个对象是,也会解除它与父对象之间的关系,deleteLater()并没有将对象立即销毁,而是想主消息循环发送一个事件,在下个消息循环时才销毁对象,这样做的好处就是可以在这些演示产出的时间内完成一些操作,坏处局势内存释放会比较不及时。

    6.事件机制

    这是个比较复杂的过程,后期再详细讲述。

    7.定时器

    API:

    obj.startTimer(1000,Qt.PreciseTimer)   #精准定时器,ms级
    obj.startTimer(1000,Qt.CoarseTimer)    #粗定时器,5%准确度
    obj.startTimer(1000,Qt.VeryCoarseTimer)#最粗的定时器,s级
    obj.kellTimer(timer_ID)                #停止定时
    timeEvent()                            #定时器执行事件,在Object内,需要重构

    每次启动一个timer时都会生成一个timer_ID ,这个ID是唯一的,停止定时时需要用到这个ID。我们看一下最简单的定时器

    from PyQt5.Qt import *
    import sys
    class MyLabel(QLabel):
        def __init__(self,*args,**kwargs):
            super().__init__(*args,**kwargs)          #重新对控件进行封装
            self.setText('10')
            self.setStyleSheet('font-size:22px;')
            self.resize(300,200)
            self.timer_id = self.startTimer(1000)     #在这里生成timer_id 
        def timerEvent(self, a0: 'QTimerEvent'):
            current_sec = int(self.text())
            current_sec -= 1
            self.setText(str(current_sec))
            if current_sec == 0:
                self.setText("stop!")
                self.killTimer(self.timer_id)
    app=QApplication(sys.argv)
    window = QWidget()
    window.resize(800,800)
    label = MyLabel(window)   #这里实例化的重构后的QObject
    label.move(200,200)
    window.show()
    sys.exit(app.exec_())
    定时器案例一

    这里由于对Label进行的高度的封装,导致这个控件不够灵活,具体的实现方法我们在后期的自定义控件里可以再聊!

    最后,QObject还有自身的两个信号,有的在上面已经讲过了

    obj.objectNameChanged()
    destroyed()

    其实上面的内容就是最开始的几点比较重要,后面的做大概的了解就可以了。

  • 相关阅读:
    QTP自动化测试项目管理最佳实践指南
    让自动化测试更“智能化”
    Selenium是否支持HTML5?
    QTP\UFT11.5破解
    亿能测试视频教程 QTP自动化测试视频系列(第26、27、28集)
    UIAutomator学习笔记V0.1
    TIB自动化测试工作室2012年资料汇总
    《Automated Software Testing》 2013年 4月 电子杂志下载
    QTP11.5全新自动化测试体验 移动终端测试
    亿能测试视频教程 QTP自动化测试视频系列(第10、11集)
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/10662434.html
Copyright © 2011-2022 走看看