Qt顶级父类QObject详解

继承关系及其作用

在部件类的继承关系树上,QObject与QPaintDevice两个类位于最顶端。其中,QObject的核心功能就是提供了信号和槽机制,最为主要的是使对象间能无缝通信,而且QOject还在Qt中提供了基础的定时器的支持,所有使用了信号和槽或属性的类,都需要包含Q_OBJECT这个宏(在原生C++版的QT中建议都加上,在pyqt中不需要,因所有部件类的顶级父类QWidget继承自QObject);而QPaintDevice则提供了一些绘图功能,其虚函数由QWidget、QImage、QPixmap、QGLPixelBuffer等子类各自实现。

QObject常用功能详解

此处为了调试与运行的方便,使用pyqt来进行具体功能讲解,有QT基础者阅读本文代码应该无大碍。

常用方法介绍

设置父控件对象,其函数原型如下:

	# 设置父控件
    def setParent(self, QObject): # real signature unknown; restored from __doc__
        """ setParent(self, QObject) """
        pass

其作用一是为一个Widget控件设置父控件,由于“对象树”这种内存管理机制,父控件对象销毁时,将以其为根节点的树上所有对象内存回收;作用二是,无父对象的控件,将会成为一个顶级窗口,需要调用show方法才能展示出来,有父对象的控件则不需要,示例代测试代码如下:

from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)

btn1 = QPushButton()
# 设置提示文本
btn1.setText("我是按钮一")
btn1.show()

window = QWidget()
btn2 = QPushButton("我是按钮二",window)
window.show()


sys.exit(app.exec_())

本代码运行后,将会出现两个窗口,如下所示:
在这里插入图片描述
与销毁相关的函数和信号,函数、信号原型如下:

    def deleteLater(self): # real signature unknown; restored from __doc__
        """ deleteLater(self) """
        pass
	
    def destroyed(self, p_object=None): # real signature unknown; restored from __doc__
        """ destroyed(self, object: QObject = None) [signal] """
        pass

python语法中有个删除的关键字del,在此处使用del会出现问题,并不会将del对象的子控件也删除,需要使用deleteLater,测试代码与注释如下:

    def test3(self):
        """
            对象被删除时
            会解除与父对象的关系
            删除要使用deletelater
        """
        obj1 = QObject()
        obj2 = QObject()
        obj3 = QObject()

        obj3.setParent(obj2)
        obj2.setParent(obj1)
        obj1.setParent(self)
		# 在对象销毁时会发射destroyed信号
        obj1.destroyed.connect(lambda :print("obj1被释放"))
        obj2.destroyed.connect(lambda: print("obj2被释放"))
        obj3.destroyed.connect(lambda: print("obj3被释放"))

        # 这个删除 可以将对象及其子类也删除
        # obj2.deleteLater()
        # 直接删除 并不会将子控件删除 
        # 会将obj2删除,但不会发送destroyed信号
        del obj2

定时器相关,函数原型如下:

	# 计时器每隔多少毫秒触发timerEvent函数
    def startTimer(self, p_int, timerType=None): # real signature unknown; restored from __doc__
        """ startTimer(self, int, timerType: Qt.TimerType = Qt.CoarseTimer) -> int """
        return 0
    # 一个对象可开启多个定时器 多个定时器通过ID来区别 也通过ID来关闭    
    def killTimer(self, p_int): # real signature unknown; restored from __doc__
        """ killTimer(self, int) """
        pass
	# 需要override才能有具体作用
	def timerEvent(self, QTimerEvent): # real signature unknown; restored from __doc__
        """ timerEvent(self, QTimerEvent) """
        pass

窗口中若想设置倒计时,则优先考虑到定时器,下面是简单封装的一个有倒计时效果的label与注释:

class MyLabel(QLabel):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        # 此处可以设定 或 改写成随输即用的形式
        self.setText("10")
        self.setStyleSheet("font-size:22px;")
        # 开启定时器 每1s触发一次event
        self.timeID = self.startTimer(1000)

    # 从10开始,减少到0为止
    def timerEvent(self, evt) -> None:
        cur = int(self.text())
        cur -=1
        if cur > 0:
            self.setText(str(cur))
        else:
            self.setText(str(0))
            # 关闭定时器
            self.killTimer(self.timeID)

信号相关的函数,函数原型与作用如下:

	# 获取阻塞状态
    def signalsBlocked(self): # real signature unknown; restored from __doc__
        """ signalsBlocked(self) -> bool """
        return False
    # 断开连接    
    def disconnect(self, QMetaObject_Connection=None): # real signature unknown; restored from __doc__ with multiple overloads
        """
        disconnect(QMetaObject.Connection) -> bool
        disconnect(self)
        """
        return False
    # 这两个函数用来追踪连接  
    def connectNotify(self, QMetaMethod): # real signature unknown; restored from __doc__
        """ connectNotify(self, QMetaMethod) """
        pass
        
    def disconnectNotify(self, QMetaMethod): # real signature unknown; restored from __doc__
        """ disconnectNotify(self, QMetaMethod) """
        pass
    # 设置暂时阻塞信号以避免无限通知循环  
    def blockSignals(self, bool): # real signature unknown; restored from __doc__
        """ blockSignals(self, bool) -> bool """
        return False

值得注意的是,原生C++QT的connect、disconnect使用方法与上述的不相同,pyqt的connect使用为:对象.信号.connect(槽方法),C++的为:connect(sender, SIGNAL(signal()), receiver, SLOT(slot()))或者connect(sender,&sender::signal,receiver,&receiver::slot),简要测试代码与注释如下:

    def test_slots1(self):
        obj = QObject()

        def slots1():
            print("有对象被释放")

        def slots2(name):
            print("对象名称发生了改变",name)
        # 信号连接槽函数 对象.信号.connect(槽方法)
        obj.destroyed.connect(slots1)
        # 有参数的信号发射时 会将参数传出来
        obj.objectNameChanged.connect(slots2)
        # 信号与槽函数断开连接
        obj.objectNameChanged.disconnect()

        # 暂时阻断连接
        print(obj.signalsBlocked(),"1")
        # 设置阻断
        obj.blockSignals(True)
        print(obj.signalsBlocked(),"2")
        obj.blockSignals(False)
        print(obj.signalsBlocked(),"3")
        # 由于本信号与槽函数已断开连接 slots2将不会被触发
        obj.setObjectName("哈哈哈")

与判定相关的函数,原型与作用如下:

	# 判断某个对象是否是 以类名为p_str的类为根节点的继承树上一个类实例 
    def inherits(self, p_str): # real signature unknown; restored from __doc__
        """ inherits(self, str) -> bool """
        return False
    # 某个信号是否连接    
    def isSignalConnected(self, QMetaMethod): # real signature unknown; restored from __doc__
        """ isSignalConnected(self, QMetaMethod) -> bool """
        return False
	# 是否是widget类型
    def isWidgetType(self): # real signature unknown; restored from __doc__
        """ isWidgetType(self) -> bool """
        return False
	# 是否是window类型
    def isWindowType(self): # real signature unknown; restored from __doc__
        """ isWindowType(self) -> bool """
        return False

简易测试代码与注释如下:

    def test1(self):
        btn = QPushButton(self)
        btn.setText("putton1")

        def slots1():
            QMessageBox.information(None,"tip","clicked button")
        btn.clicked.connect(slots1)
        # 类型判定
        # True
        print(btn.isWidgetType())
        # False
        print(btn.isWindowType())
        # 继承判定  ClassName 
        # True
        print(btn.inherits("QWidget"))

其它方法,如setProperty、setObjectName等,作用在于设置具体对象的动态属性,一般与QSS进行搭配使用来设置控件样式,由于篇幅原因,感兴趣的读者可自己进行测试,如觉得本文对你有帮助,请点赞关注一下。

猜你喜欢

转载自blog.csdn.net/weixin_45416439/article/details/125713167