精华内容
下载资源
问答
  • 我发射一个自定义的信号,但是与其连接的函数却没有被执行 这个 不是QpushButton那种连接,而是从Qobject发送信号,在QWidget上进行connnect虽然Qwidget也是基于Qobject的基类,理论上可以直接使用信号和曹机制,...

    我发射一个自定义的信号,但是与其连接的槽函数却没有被执行
    这个 不是QpushButton那种连接,而是从Qobject发送信号,在QWidget上进行connnect虽然Qwidget也是基于Qobject的基类,理论上可以直接使用信号和曹机制,没错!!!确实可以直接使用,,其大致过程和自定义信号和槽相似,具体原理,我还需要一段时间慢慢深挖,下面说一下坑
    先说正确的操作:
    1.在信号函数.h
    建立信号

    #ifndef SIGNAL_H
    #define SIGNAL_H
    
    #include <QObject>
    
    class signal : public QObject
    {
        Q_OBJECT
    public:
         signal(QObject *parent = nullptr);
    
        void fashe();
    
    signals:
        void signal_back();//信号
    
    public slots:
    };
    
    #endif // SIGNAL_H
    

    在这里插入图片描述
    在.cpp文件建立发送信号执行命令

    #include "signal.h"
    #include <QDebug>
    signal::signal(QObject *parent) : QObject(parent)
    {
    //初始化函数
    }
    void signal::fashe()
    {
        emit signal_back();
        qDebug()<<"fashe....emit signal_back()";
    }
    
    

    2.在执行文件下也就是曹函数下
    在这里插入图片描述

    首先是.h里建立新的对象和槽函数声明

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include "signal.h"
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
        signal *m_MyThread;//定义对象指针
        
    private slots://槽函数
        void test();
        void btnclied();
    private:
        Ui::Widget *ui;
    };
    
    #endif // WIDGET_H```.cpp文件下写connnect和槽函数内容
    
    ```cpp
    #include "widget.h"
    #include "ui_widget.h"
    #include <QDebug>
    #include "signal.h"
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        m_MyThread = new signal;//创建一个新的object一定要new 一块内存下来
      
       connect(m_MyThread,SIGNAL(signal_back()),this,SLOT(test()));//连接到object里的信号
        connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(btnclied()));
        
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    void Widget::test()
    {
        qDebug()<<"TEST";
    }
    void Widget::btnclied(){
    m_MyThread->fashe();
    }
    
    

    以上就可以正常使用了

    下面是不可以的
    在这里插入图片描述
    用上面这种方式去调用,信号发射命令的函数,目前不明白为啥不行,个人感觉这样调用之后,好像函数和connect连钱的第一个发射者不在一个作用域里了。

    下面说一下 在学习C++的过程中我们经常会用到.和::和:和->,在此整理一下这些常用符号的区别。

    1、A.B则A为对象或者结构体;
    2、A->B则A为指针,->是成员提取,A->B是提取A中的成员B,A只能是指向类、结构、联合的指针;
    3::是作用域运算符,A::B表示作用域A中的名称B,A可以是名字空间、类、结构;
    4、:一般用来表示继承;
    
    展开全文
  • 系统地讲解信号与(✘),系统过一遍信号与(✔)(狗头)这可以说是Qt中最核心的概念之一了。一个小的Demo信号与是Qt中的核心概念,有了信号与,我们就可以通过在UI上点击、输入等操作触发程序内部的函数发挥作用...

    系统地讲解信号与槽(✘),系统过一遍信号与槽(✔)(狗头)

    这可以说是Qt中最核心的概念之一了。

    一个小的Demo

    信号与槽是Qt中的核心概念,有了信号与槽,我们就可以通过在UI上点击、输入等操作触发程序内部的函数发挥作用,比如在控制台上打印一段文本,比如将用户在QTextEdit中输入的文本读入程序做后续处理。因此想要真正做到通过UI让用户和内部程序进行交互,信号与槽是必不可少的(在Qt的框架下)。

    信号(signal)是由事件(event)发生,进而引起控件发出,只要信号发出,那么与信号绑定(connect)的槽函数(slot)就会被执行。比如最简单的信号就是clicked,如果用户在UI上点击了按钮之类的控件,那么这个点击事件就会使得这些被点击的控件发出clicked信号,这些信号会被与控件绑定的若干个槽函数捕获,然后这些槽函数就会被执行。大致的逻辑如此。

    import sys

    from PyQt5.QtWidgets import *

    from PyQt5.QtCore import *

    from PyQt5.QtGui import *

    class SignalSlotDemo(QWidget):

    def __init__(self):

    super(SignalSlotDemo, self).__init__()

    self.initUI()

    def initUI(self):

    self.setWindowTitle("")

    self.resize(400, 300)

    self.btn = QPushButton("我的按钮", self)

    self.btn.clicked.connect(self.onClick)

    def onClick(self):

    print("信号已发出")

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = SignalSlotDemo()

    main.show()

    sys.exit(app.exec_())

    运行效果:

    需要说明的是,一个控件发出的信号可以与多个槽函数绑定,多个控件发出的信号也可以与同一个槽函数绑定。

    自定义信号

    之前用到过了自定义信号(内嵌信号),PyQt5提供了信号对象pyqtSignal来允许用户创建自定义信号,从而使得系统处理事件更加灵活。

    import sys

    from PyQt5.QtGui import *

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    # 自定义信号

    class MyTypeSignal(QObject):

    # 定义一个信号

    sendmsg = pyqtSignal(object)

    # 发出信号的函数

    def run(self):

    self.sendmsg.emit("Hello PyQt5")

    # 自定义的槽

    class MySlot(QObject):

    def get(self, msg):

    print("信息" + msg)

    if __name__ == '__main__':

    send = MyTypeSignal()

    slot = MySlot()

    # 直接把信号和槽绑定

    send.sendmsg.connect(slot.get)

    # 发出信号

    send.run()

    运行效果:

    信息Hello PyQt5

    需要注意自定义的信号和槽都是继承自QObject对象。将信号和槽绑定后,只要信号发出(即我们使用了send.run()来发送信号),那么我们绑定的槽的函数就会被触发。

    我们还可以通过disconnect()来让原本已经绑定的信号和槽解除绑定:

    import sys

    from PyQt5.QtGui import *

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    class MyTypeSignal(QObject):

    # 定义一个信号

    sendmsg = pyqtSignal(object)

    # 发出信号的函数,这个信号只传递一个参数,即字符串"Hello PyQt5"

    def run(self):

    self.sendmsg.emit("Hello PyQt5")

    class MySlot(QObject):

    def get(self, msg):

    print("信息" + msg)

    if __name__ == '__main__':

    send = MyTypeSignal()

    slot = MySlot()

    # 直接把信号和槽绑定

    send.sendmsg.connect(slot.get)

    send.sendmsg.disconnect(slot.get)

    # 发送信号

    send.run()

    运行结果:

    ​不打印任何信息,也就是说槽函数没有被触发

    可以传递多个参数的信号

    在使用pyqtSignal()时,可以通过设置参数来制定该信号所能传送的参数的个数

    import sys

    from PyQt5.QtGui import *

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    class MyTypeSignal(QObject):

    # 定义一个信号

    sendmsg = pyqtSignal(object)

    # 发送3个参数的信号,参数类型分别为str,int,int

    sendmsg1 = pyqtSignal(str, int, int)

    # 发出信号的函数

    def run(self):

    self.sendmsg.emit("Hello PyQt5")

    # 发送传送三个参数的信号

    def run1(self):

    self.sendmsg1.emit("Hello", 3, 4)

    class MySlot(QObject):

    def get(self, msg):

    print("信息" + msg)

    def get1(self, msg, a, b):

    print(msg)

    print(a + b)

    if __name__ == '__main__':

    send = MyTypeSignal()

    slot = MySlot()

    # 直接把信号和槽绑定

    send.sendmsg.connect(slot.get)

    send.sendmsg1.connect(slot.get1)

    # 发送信号

    send.run()

    send.run1()

    运行结果:

    信息Hello PyQt5

    Hello

    7

    为类添加多个信号

    可以往类中添加任意数量的信号,而且信号传递的参数的类型可以是任意类型

    import sys

    from PyQt5.QtGui import *

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    class MultiSignal(QObject):

    signal1 = pyqtSignal()

    signal2 = pyqtSignal(int)

    signal3 = pyqtSignal(int, str)

    signal4 = pyqtSignal(list)

    signal5 = pyqtSignal(dict)

    # 申明一个重载版本的信号

    # 也就是说槽函数接受的参数可以是int和str类型的,也可以是只有一个str类型的参数

    # 具体是哪一个视传入的参数情况而定

    signal6 = pyqtSignal([int, str], [str])

    def __init__(self):

    super(MultiSignal, self).__init__()

    self.signal1.connect(self.signalCall1)

    self.signal2.connect(self.signalCall2)

    self.signal3.connect(self.signalCall3)

    self.signal4.connect(self.signalCall4)

    self.signal5.connect(self.signalCall5)

    self.signal6[int, str].connect(self.signalCall6)

    self.signal6[str].connect(self.signalCall6Overload)

    # 让所有信号都发送

    self.signal1.emit()

    self.signal2.emit(10)

    self.signal3.emit(1, "hello world")

    self.signal4.emit([1,2,3,4,5,6])

    self.signal5.emit({"name":"Bill", "age":30})

    self.signal6[int, str].emit(100, "test")

    self.signal6[str].emit("test")

    # 我们直接在这个类里面定义槽函数

    def signalCall1(self):

    print("信号1被触发")

    def signalCall2(self, num):

    print("信号2被触发,值为:{}".format(num))

    def signalCall3(self, num, string):

    print("信号3被触发,值为:{} {}".format(num, string))

    def signalCall4(self, List):

    print("信号4被触发,值为:{}".format(List))

    def signalCall5(self, Dict):

    print("信号5被触发,值为:{}".format(Dict))

    def signalCall6(self, num, string):

    print("信号6被触发,值为:{} {}".format(num, string))

    def signalCall6Overload(self, string):

    print("信号6被触发,值为:{}".format(string))

    if __name__ == '__main__':

    signal = MultiSignal()

    运行结果:

    信号1被触发

    信号2被触发,值为:10

    信号3被触发,值为:1 hello world

    信号4被触发,值为:[1, 2, 3, 4, 5, 6]

    信号5被触发,值为:{'name': 'Bill', 'age': 30}

    信号6被触发,值为:100 test

    信号6被触发,值为:test

    其中1-5都好理解,signal6看起来很特殊,这是因为,我们使用了信号的重载(其实我感觉这更像是信号数组)。大致用法如上,在创建信号对象时,以列表包装多组参数,这几组参数之间形成了或与或的关系。需要绑定槽函数和发送信号时,需要在signal6后面加上[]操作符,里面填上定义时的某一组参数(这就有点类似索引了),来指定这个信号传递的参数到底是哪一组。

    信号与槽多对多连接与断开连接

    from PyQt5.QtCore import *

    class NNSignal(QObject):

    signal1 = pyqtSignal()

    signal2 = pyqtSignal(int)

    def __init__(self):

    super(NNSignal, self).__init__()

    self.signal1.connect(self.call1)

    self.signal1.connect(self.call2)

    print("signal1 发送信号")

    self.signal1.emit() # 发送信号

    self.signal2.connect(self.call1)

    self.signal2.connect(self.call2)

    print("signal2 发送信号")

    self.signal2.emit(2) # 发送信号

    self.signal1.disconnect(self.call1)

    self.signal1.disconnect(self.call2)

    self.signal2.disconnect(self.call1)

    self.signal2.disconnect(self.call2)

    print("再次发送信号")

    # 再次发送信号,就应该不会再触发任何槽函数了

    self.signal1.emit()

    self.signal2.emit(2)

    def call1(self):

    print("call1 emit")

    def call2(self):

    print("call2 emit")

    if __name__ == '__main__':

    signal = NNSignal()

    运行结果:

    signal1 发送信号

    call1 emit

    call2 emit

    signal2 发送信号

    call1 emit

    call2 emit

    再次发送信号

    我们还可以将信号与信号绑定,比如我们使用信号二的connect()将信号二和信号一绑定,那么信号二发送信号时,与信号一连接的所有槽函数都会被触发

    from PyQt5.QtCore import *

    class NNSignal(QObject):

    signal1 = pyqtSignal()

    signal2 = pyqtSignal(int)

    def __init__(self):

    super(NNSignal, self).__init__()

    self.signal1.connect(self.call1)

    self.signal1.connect(self.call2)

    self.signal2.connect(self.signal1)

    print("signal2 发送信号")

    self.signal2.emit(2) # 发送信号

    def call1(self):

    print("call1 emit")

    def call2(self):

    print("call2 emit")

    if __name__ == '__main__':

    signal = NNSignal()

    运行结果:

    signal2 发送信号

    call1 emit

    call2 emit

    为窗口添加信号

    为窗口添加信号本质上和为类添加信号是一样的,因为窗口本质就是一个窗口类。

    import sys

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    class WinSignal(QWidget):

    button_clicked_signal = pyqtSignal()

    def __init__(self):

    super().__init__()

    self.setWindowTitle("为窗口类添加信号")

    self.resize(300, 100)

    btn = QPushButton("关闭窗口", self)

    btn.clicked.connect(self.btn_clicked)

    self.button_clicked_signal.connect(self.close)

    def btn_clicked(self):

    self.button_clicked_signal.emit()

    def btn_close(self):

    self.close()

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = WinSignal()

    main.show()

    sys.exit(app.exec_())

    运行结果:

    这里有点小绕,请务必理清逻辑关系:用户点击按钮->clicked信号发送->btn_clicked()槽函数被触发,函数执行内容为让button_clicked_signal信号发送->btn_close()槽函数被触发,函数执行内容为让窗体关闭->窗口关闭。只是单纯地演示窗口中自定义信号的使用,禁止套娃

    多线程更新UI数据

    PyQt5中最常用、最好的在子线程中完成工作并返回值的方式就是使用信号和槽。要做的很简单,就是将子线程(我们定义和创建的)中的信号和主线程中的槽函数绑定。那么我们需要完成的工作就交给子线程完成,待完成后,子线程中的数据再通过信号传递到主线程的槽函数中。

    import sys

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    # 定义一个线程类

    class BackendThread(QThread):

    update_date = pyqtSignal(str)

    # 该线程做的事就是每隔一秒就让update_date信号发送一次,信号传递的参数是当地时间的格式化字符串

    def run(self):

    while True:

    data = QDateTime.currentDateTime()

    currentTime = data.toString("yyyy-MM-dd hh:mm:ss")

    self.update_date.emit(str(currentTime))

    self.sleep(1)

    class ThreadUpdateUI(QDialog):

    def __init__(self):

    super(ThreadUpdateUI, self).__init__()

    self.setWindowTitle("多线程更新UI数据")

    self.resize(400, 100)

    self.input = QLineEdit(self)

    self.input.resize(400, 100)

    self.initUI()

    def initUI(self):

    # 创建线程对象

    self.backend = BackendThread()

    # 将线程对象中的update_date对象和下面要写得handleDisplay函数绑定

    self.backend.update_date.connect(self.handleDisplay)

    # 启动线程

    self.backend.start()

    def handleDisplay(self, data):

    self.input.setText(data)

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = ThreadUpdateUI()

    main.show()

    sys.exit(app.exec_())

    运行效果:

    总结:子线程中的信号和主线程中的槽函数绑定。

    还有就是。。。看不懂BackendThread这个我们定义的线程类的同学,不妨去看看之前多线程那一章的内容。

    信号与槽自动连接

    我们之前连接信号和槽都是使用connect()函数一个一个手动连接的,但是如果需要连接的信号和槽很多的话,那么使用connect()去一个一个连接会显得很麻烦。

    我们可以通过装饰器和设置控件的内部引用名的方式来让控件和被装饰器增强的槽函数自动绑定

    import sys

    from PyQt5.QtCore import *

    from PyQt5.QtWidgets import *

    from PyQt5 import QtCore

    class AutoSignalSlot(QWidget):

    def __init__(self):

    super(AutoSignalSlot, self).__init__()

    self.setWindowTitle("信号与槽自动连接")

    self.resize(400, 100)

    layout = QHBoxLayout()

    self.okButton = QPushButton("OK")

    self.cancelButton = QPushButton("CANCEL")

    # 设置button的内部引用名

    self.okButton.setObjectName("okButton")

    self.cancelButton.setObjectName("cancelButton")

    layout.addWidget(self.okButton)

    layout.addWidget(self.cancelButton)

    self.setLayout(layout)

    # 规定按照内部引用名字(ObjectName)自动绑定信号和槽

    QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot()

    def on_okButton_clicked(self): # 槽函数的名字必须是这个,不能改成别的,下面的也一样

    print("点击了ok按钮")

    @QtCore.pyqtSlot()

    def on_cancelButton_clicked(self):

    print("点击了cancel按钮")

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = AutoSignalSlot()

    main.show()

    sys.exit(app.exec_())

    运行结果:

    QtCore.QMetaObject.connectSlotsByName(self)的意思就是在主窗口下开启信号和槽的自动匹配。

    如希望信号和槽自动匹配,除了写下QtCore.QMetaObject.connectSlotsByName(self)这一句以外还需要做两件事:通过控件对象的setObjectName()方法设置控件的内部引用名。

    在槽函数上使用@QtCore.pyqtSlot()进行功能增强。

    需要说明的是自动匹配的规则。之所以能自动匹配,关键在于你希望自动匹配在一起的控件的内部引用名、发送的信号名和槽函数之间的名字关系。

    除了使用装饰器增强外,槽函数的名字在控件的内部引用名设置完成后就是固定的了,规则为:

    on_ObjectName-signal

    比如我们将一个QPushButton通过setObjectName()方法将内部引用名设置为open,希望将这个按钮的clicked信号和一个槽函数自动绑定,那么这个槽函数的名字必须是on_open_clicked

    使用lambda表达式为槽函数传递参数

    在讲使用lambda表达式为槽函数传递参数之前,有必要学习或者复习一下lambda表达式(熟悉lambda表达式的同学可以直接跳过)

    lambda表达式实际上就是匿名函数,也就是没有名字的函数。分为无参数的lambda表达式和带参数的lambda表达式,被lambda表达式赋予的那个变量就可以当做函数来使用,例如:

    fun1 = lambda :print("hello") # 无参数的lambda表达式

    fun1()

    fun2 = lambda x,y:print(x,y) # 带参数的lambda表达式

    fun2("a", "b")

    运行结果:

    hello

    a b

    容易观察到,无参数的lambda表达式应该为lambda : 函数体这样的形式;带参数的lambda表达式应该为lambda 参数1,参数2,... : 函数体这样的形式。

    函数体不一定得是像print一样的内置函数,也可以是表达式,例如:

    plus = lambda a,b : a + b

    print(plus(3, 4))

    运行结果:

    7

    有了lambda表达式,我们就可以干预信号往槽函数传递参数的过程,来让信号传递的参数以我们自定义的组织结构传入槽函数中。

    from PyQt5.QtWidgets import *

    import sys

    class LambdaSlotArg(QWidget):

    def __init__(self):

    super().__init__()

    self.setWindowTitle("使用Lambda表达式为槽函数传递参数")

    self.resize(400, 200)

    layout = QHBoxLayout()

    button1 = QPushButton("按钮1")

    button2 = QPushButton("按钮2")

    this_is_a_param = 100

    button1.clicked.connect(lambda : self.onButtonClick(10, 20))

    button2.clicked.connect(lambda : self.onButtonClick(this_is_a_param, -20))

    layout.addWidget(button1)

    layout.addWidget(button2)

    self.setLayout(layout)

    def onButtonClick(self, m, n):

    print("m + n = {}".format(m + n))

    QMessageBox.information(self, "结果", str(m + n))

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = LambdaSlotArg()

    main.show()

    sys.exit(app.exec_())

    运行结果:

    使用Partial对象为槽函数传递参数

    除了使用lambda表达式之外,还可以通过Python的functool库中的partial方法来直接封装。效果和lambda是一样的:

    from PyQt5.QtWidgets import *

    from functools import partial

    import sys

    class PartialSlotArg(QWidget):

    def __init__(self):

    super().__init__()

    self.setWindowTitle("使用Partial对象为槽函数传递参数")

    self.resize(400, 200)

    layout = QHBoxLayout()

    button1 = QPushButton("按钮1")

    button2 = QPushButton("按钮2")

    button1.clicked.connect(partial(self.onButtonClick, 10, 20))

    button2.clicked.connect(partial(self.onButtonClick, 123, 20))

    layout.addWidget(button1)

    layout.addWidget(button2)

    self.setLayout(layout)

    def onButtonClick(self, m, n):

    print("m + n = {}".format(m + n))

    QMessageBox.information(self, "结果", str(m + n))

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = PartialSlotArg()

    main.show()

    sys.exit(app.exec_())

    运行效果:

    Override(覆盖)槽函数

    或许系统或者我们自己已经写好了许多信号,在PyQt5中,我们可以通过直接定义同名信号来覆盖这些已经定义好的信号,来改变信号原本的行为。

    比如PyQt5中有一个信号是keyPressEvent,当键盘上的按键按下时,这个信号会发送,传递的参数是代表按下按键的一个对象。我们可以直接def 它,让keyPressEvent发送信号时还能做一些别的事情,比如改变窗口的标题:

    from PyQt5.QtWidgets import *

    from PyQt5.QtCore import *

    from functools import partial

    import sys

    class OverrideSlot(QWidget):

    def __init__(self):

    super().__init__()

    self.setWindowTitle("Override(覆盖)槽函数")

    self.resize(400, 200)

    def keyPressEvent(self, e):

    # 按下Esc键就退出窗口

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

    self.close()

    # 按下Alt键就改变窗口的标题

    elif e.key() == Qt.Key_Alt:

    self.setWindowTitle("按下Alt键")

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = OverrideSlot()

    main.show()

    sys.exit(app.exec_())

    运行效果:按下Esc键窗口退出;按下Alt键,标题改为“按下Alt键”

    多窗口交互(1):不使用信号与槽

    所谓多窗口交互就是让多个窗口进行数据传递。我们下面通过强耦合的方式让两个窗口实现交互。

    下面这个例子写成了两个文件:DateDialog.py和draft.py其中可能有一些很绕,但是这不是重点,重点在(2)

    DateDialog.py:

    from PyQt5.QtWidgets import *

    from PyQt5.QtCore import *

    from PyQt5.QtGui import *

    import sys

    class DateDialog(QDialog):

    def __init__(self, parent=None):

    super(DateDialog, self).__init__(parent)

    self.setWindowTitle("DateDialog")

    layout = QVBoxLayout(self)

    self.datetime = QDateTimeEdit(self)

    # 使得QDateTimeEdit控件可以下拉出一个日历

    self.datetime.setCalendarPopup(True)

    # 展示类型为当地的日期和时间

    self.datetime.setDateTime(QDateTime.currentDateTime())

    layout.addWidget(self.datetime)

    # 创建按钮盒子

    buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)

    # 下面的都是内置的信号和槽,直接绑定就行

    buttons.accepted.connect(self.accept)

    buttons.rejected.connect(self.reject)

    layout.addWidget(buttons)

    def dateTime(self):

    return self.datetime.dateTime()

    @staticmethod

    def getDateTime(parent=None):

    dialog = DateDialog(parent)

    # 执行该窗体

    result = dialog.exec_()

    date = dialog.dateTime()

    return (date.date(), date.time(), result == QDialog.Accepted)

    draft.py:

    from PyQt5.QtWidgets import *

    from PyQt5.QtCore import *

    from PyQt5.QtGui import *

    from DateDialog import DateDialog # 我们自己定义的类

    import sys

    class MultiWindow1(QWidget):

    def __init__(self):

    super().__init__()

    self.setWindowTitle("多窗口交互(1):不使用信号与槽")

    self.resize(400, 200)

    self.lineEdit = QLineEdit(self)

    self.button1 = QPushButton("弹出对话框1")

    self.button2 = QPushButton("弹出对话框2")

    self.button1.clicked.connect(self.onButton1Click)

    self.button2.clicked.connect(self.onButton2Click)

    gridLayout = QGridLayout()

    gridLayout.addWidget(self.lineEdit)

    gridLayout.addWidget(self.button1)

    gridLayout.addWidget(self.button2)

    self.setLayout(gridLayout)

    def onButton1Click(self):

    dialog = DateDialog(self)

    # 执行窗体二,也就是DateDialog

    result = dialog.exec_()

    date = dialog.dateTime()

    self.lineEdit.setText(date.date().toString())

    dialog.destroy()

    def onButton2Click(self):

    date, time, result = DateDialog.getDateTime()

    self.lineEdit.setText(date.toString())

    if result == QDialog.Accepted:

    print("点击确定按钮")

    else:

    print("点击取消按钮")

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = MultiWindow1()

    main.show()

    sys.exit(app.exec_())

    运行draft.py结果:

    需要注意的是,onButton1Click和onButton2Click的效果一样,只不过一个是在draft.py运行的窗体一中运行窗体二,使用DateDialog里的方法获得对话框;一个是直接使用DateDialog里我们自己定义的静态方法,这个静态方法中包含了执行窗体二的语句。

    多窗口交互(2):使用信号与槽

    强耦合虽然简短,但是缺点很多,我们可以使用信号和槽来降低多个窗口之间的耦合度。即将控件和数据分离,这样我们设计好的窗体对象就可以在别的场合使用。

    下面我们尝试两种方式来将子窗口的数据传递到主窗口:使用子窗口的内嵌信号和自定义信号:

    还是分为了两个文件:DateDialog.py和draft.py

    DateDialog.py:

    from PyQt5.QtWidgets import *

    from PyQt5.QtCore import *

    from PyQt5.QtGui import *

    import sys

    class DateDialog(QDialog):

    # 自定义信号

    Signal_OneParameter = pyqtSignal(str)

    def __init__(self, parent=None):

    super(DateDialog, self).__init__(parent)

    self.setWindowTitle("子窗口:用来发射信号")

    # 设置布局,并在布局中添加控件

    layout = QVBoxLayout(self)

    self.label = QLabel("前者发射内置信号\n后者发射自定义信号")

    # 设置一个显示时间的文本编辑框,这个时间编辑框通过内置信号传递数据

    self.datetime_inner = QDateTimeEdit()

    self.datetime_inner.setCalendarPopup(True)

    self.datetime_inner.setDateTime(QDateTime.currentDateTime())

    # 设置一个显示时间的文本编辑框,这个时间编辑框通过自定义信号传递数据

    self.datetime_emit = QDateTimeEdit()

    self.datetime_emit.setCalendarPopup(True)

    self.datetime_emit.setDateTime(QDateTime.currentDateTime())

    # 将控件放入布局中

    layout.addWidget(self.label)

    layout.addWidget(self.datetime_inner)

    layout.addWidget(self.datetime_emit)

    # 创建按钮盒子

    buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)

    # 盒子中的两个button(ok和cancel)分别连接accept()和reject()槽函数

    buttons.accepted.connect(self.accept)

    buttons.rejected.connect(self.reject)

    layout.addWidget(buttons)

    # 将datetime_emit所选时间改变的信号和槽函数绑定

    self.datetime_emit.dateTimeChanged.connect(self.emit_signal)

    def emit_signal(self):

    # 获取datetime_emit显示时间的默认格式化字符串

    date_str = self.datetime_emit.dateTime().toString()

    # 发送我们的自定义信号Signal_OneParameter,传递的参数就是date_str

    self.Signal_OneParameter.emit(date_str)

    draft.py:

    from PyQt5.QtWidgets import *

    from PyQt5.QtCore import *

    from PyQt5.QtGui import *

    from DateDialog import DateDialog # 我们自己定义的类

    import sys

    class MultiWindow2(QWidget):

    def __init__(self):

    super().__init__()

    self.setWindowTitle("多窗口交互(2):使用信号与槽")

    self.resize(400, 200)

    self.open_btn = QPushButton("获取时间")

    self.lineEdit_inner = QLineEdit("接受子窗口内置信号的时间")

    self.lineEdit_emit = QLineEdit("接受子窗口自定义信号的时间")

    self.open_btn.clicked.connect(self.openDialog)

    gridLayout = QGridLayout()

    gridLayout.addWidget(self.lineEdit_inner)

    gridLayout.addWidget(self.lineEdit_emit)

    gridLayout.addWidget(self.open_btn)

    self.setLayout(gridLayout)

    def openDialog(self):

    dialog = DateDialog(self)

    # 连接子窗口的内置信号与主窗口的槽函数

    dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)

    # 连接子窗口的自定义信号与主窗口的槽函数

    dialog.Signal_OneParameter.connect(self.deal_emit_slot)

    # 显示子窗口

    dialog.show()

    def deal_inner_slot(self, date):

    self.lineEdit_inner.setText(date.toString())

    def deal_emit_slot(self, date_str):

    self.lineEdit_emit.setText(date_str)

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    main = MultiWindow2()

    main.show()

    sys.exit(app.exec_())

    运行draft.py结果:

    可以发现我们使用两种方法传递信号,一种通过

    dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)

    在主窗口中访问子窗口中的控件datetime_inner,继而将这个控件的信号和主窗口中的槽函数deal_inner_slot函数绑定;

    第二种,通过在子窗口中创建自定义信号Signal_OneParameter,这个信号我设置它传递我们需要传递的数据(格式化的时间字符串),然后我们在主窗口中直接访问这个自定义信号,而不是任何控件。

    相比两种方法,更加推荐第二种,因为第二种方法中两个窗口的耦合度更低。灵活性更强,而且我们绑定的是自定义信号和槽,与任何控件都无关,如果我们需要改变子窗口中的控件,那么第一种方法就有可能需要修改程序,而第二种方法由于绑定的是信号,所以不需要修改。

    展开全文
  • 如果读到电平就发送信号,告知MainWindow更新控件,会导致程序崩溃。 解决方法: 限制信号发送的频率,当IO电平是持续高电平或持续低电平时,此时发送的信号都是无意义的。可以新添加一个temp变量,用来储存上一...

    问题情景:

    • 使用Qt编写运动控制上位机时,需要读取IO端口信号,并根据读取到的信号将传感器的状态显示在主界面。
    • 由于没办法读取到电平的上升沿或下降沿变化,所以只能在循环内一直读取IO的电平,而IO端口数量比较多,大概有30个。如果读到电平后就发送信号,告知MainWindow更新控件,会导致程序崩溃。

    解决方法:

    • 限制信号发送的频率,当IO电平是持续高电平或持续低电平时,此时发送的信号都是无意义的。可以新添加一个temp变量,用来储存上一个电平信号。当读取到电平时,先判断当前电平和temp是否相等,不相等时才告知MainWindow更新控件,比较完成后将读取的电平赋值给temp。
    // state读取的电平信号是[0,1],初始化为2可以保证第一次比较一定可以生效。
    int temp = 2;
    // 2张运动控制卡,每张运动控制卡有16个IO输入端口
    for(int cardNo=0; cardNo<2; cardNo++)
    {
        for(int port=0; port<16; port++)
        {
            state = dmc_read_inbit(cardNo, port);  // 所有IO低电平有效
            if(state != temp)
            {
                if(state == 0)
                {
                    emit sigIOShow(cardNo, port);  // 告诉Mainwindow,传感器灯亮
                }
                else
                {
                    emit sigIOHide(cardNo, port);  // 告诉Mainwindow,传感器灯灭
                }
                temp = state;  //更新temp
            }
            else
            {
                continue;
            }
        }
    }
    
    展开全文
  • C++信号

    2021-05-23 08:19:03
    什么是信号?简单来说,信号是观察者模式的一种实现,或者说是一种升华。一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知;一个就是一个观察者,通常就是在被观察的对象发生改变的时候...

    什么是信号槽?

    简单来说,信号槽是观察者模式的一种实现,或者说是一种升华。

    一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知;一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候——也可以说是信号发出的时候——被调用的函数;你可以将信号和槽连接起来,形成一种观察者-被观察者的关系;当事件或者状态发生改变的时候,信号就会被发出;同时,信号发出者有义务调用所有注册的对这个事件(信号)感兴趣的函数(槽)。

    信号和槽是多对多的关系。一个信号可以连接多个槽,而一个槽也可以监听多个信号。

    另外信号可以有附加信息。

    使用信号槽

    信号槽是伟大的工具,但是如何能更好的使用它?相比于直接函数调用,有三点值得我们的注意。

    一个信号槽的调用,可能会比直接函数调用耗费更多的时间/空间;

    可能不能使用 inline;

    对于代码阅读者来说可能并不友好。

    使用信号槽进行解耦,我们获得的最大的好处是,连接两端的对象不需要知道对方的任何信息。

    你可以实现一个应用程序,其中每一个函数调用都是通过信号来触发的。这在技术上说是完全没有问题的,然而却是不大可行的,因为信号槽的使用无疑会丧失一部分代码可读性和系统性能。如何在这其中做出平衡,也是你需要考虑的很重要的一点。

    sigslot库

    C++中的信号槽系统常用的有三种:boost的signals,sigslot,sigc++。其中sigslot库是比较简单好用的。

    sigslot是一个线程安全、类型安全,用C++实现的sig/slot机制(sig/slot机制就是对象之间发送和接收消息的机制)的开源代码库。只有一个头文件sigslot.h。

    基本功能有:

    connect

    disconnect

    emit

    sigslot优点

    不用担心空回调,当回调对象析构时会自动disconnect

    支持多线程,线程安全,有锁

    sigslot缺点

    只能回调void类型函数,不支持返回值。boost中的signals库架构类似,支持返回值,但引入了boost中的其他库

    slot没有优先级,不能动态调整回调队列中的先后顺序

    slot函数(被回调的函数)就是普通的成员函数,但有以下限制:

    返回值必须为void

    slot参数个数范围为0-8个

    实现slot的类必须继承自has_slots<>

    前两条是sigslot库作者的限制,作者权衡各方面因素后做出的决定,如果你觉得有必要你可以修改sigslot代码取消该限制,而最后一条是sigslot的机制基础,必须遵守,除非你自己重新写个sigslot。

    需要注意的是:sigslot库的设计,当发送一个没有连接的信号时,不做任何处理,也不会有错误发出。

    基本使用方式

    包含头文件

    #include "sigslot.h"

    改动(“typename 必须前置于嵌套依赖类型名”)

    //在sigslot.h的420,将:

    typedef sender_set::const_iterator const_iterator;

    //改为:

    typedef typename sender_set::const_iterator const_iterator;

    signal0~signal8:信号类:作为类成员

    class mySg

    {

    sigc::signal0<> sg1; // 无参数

    sigc::signal2 sg2; // 2个参数

    }

    connection(槽函数:作为类成员,类需要继承has_slots<>,且槽函数的返回值必须是void类型)

    class mySlot: public : has_slots<>

    {

    public:

    void on_func1(){} // 无参数,与信号对应

    void on_func2(char*, double)(){} // 2个参数

    };

    mySg sig;

    mySlot slt;

    sig.sg1.conncent(&slt,&mySlot::on_func1);

    sig.sg2.conncent(&slt,&mySlot::on_func2);

    disconnection(解除连接:可以使用disconnect()和disconnect_all())

    sig.sg1.disconnect(&slt);

    sig.sg1.disconnect_all();

    emiting(发送信号:可以直接使用()运算符,也可以调用signal的emit函数)

    sig.sg1.emit();

    sig.sg2("str",0.1);

    展开全文
  •   函数的执行都是需要耗费一定的时间,耗时太长则会阻塞线程,如果是界面开发,阻塞主线程时界面将会卡住,无法点击,例如在界面上有个按钮,如下图 ...这种体验很不好,好比在下载视频需要转码,
  • 密封设计标准

    千次阅读 2020-12-24 18:21:02
    2020-03-23矩形模具通常用于一些水利工程中,或者是在公路建设的时候也会用到模具进行大量矩形的加工,矩形长度基本上都是在八十公分到一米二左右,在生产的时候会在模具中浇筑大量的混凝土,在成型顺利的...
  • 内存插槽修复方法

    千次阅读 2021-07-29 06:55:26
    有些人会遇到内存插槽损坏的情况,那么遇到内存插槽损坏我们应该怎么...死机以后重新按下电源开关有时不能够正常启动,机器报警提示内存有问题,将内存重新插拔机器便能够正常启动,但使用一段时间依旧会出现蓝...
  • # 熟悉信号与的使用 # -*- coding: utf-8 -*- from PyQt5.QtWidgets import * from PyQt5.QtCore import * import sys # 创建信号类 class QTypeSigner(QObject): # 定义一个信号 sendmsg = pyqtSignal(object...
  • 信号和基本特点

    2021-03-03 14:24:11
    本文链接:https://blog.csdn.net/hhhuang1991/article/details/79829784信号和机制是 QT 的核心... 为控件添加信号和手动添加//MyDlg.h#pragma once#include #include #include #include #include #include cla...
  • 函数和普通的C++成员函数没有很大的区别。它们也可以使virtual的;可以被重写;可以使public、protected或者 private的;可以由其它的C++函数调用;参数可以是任何类型的。如果要说区别,那就是,函数可以和一个...
  • 服务器磁盘位管理

    2021-08-10 08:48:27
    服务器磁盘位管理 内容精选换一换单独购买的磁盘为数据盘,可以在磁盘列表中看到磁盘属性为“数据盘”,磁盘状态为“可用”。此时需要将该数据盘挂载给云服务器使用。本章节指导用户挂载共享磁盘,共享磁盘可以...
  • 发出QDoubleSpinBox指定温度的信号转换为常用温度单位向所有其他QDoubleSpinBox发送信号以更新它们从公共温度单位到每个QDoubleSpinBox特定温度单位的转换醇>此类收集一组无参数信号,并使用与发送信号的对象相...
  • :填指的是为了让用户意图转化为用户明确的指令而补全信息的过程。准入条件:从一个开放域转入到封闭域,或者从一个封闭域转入到另一个封闭域,中间的跳转是需要逻辑判断的,而这个逻辑判断就是准入条件。封闭...
  • Qt 信号和机制详解

    2021-02-11 07:30:34
    信号和是 Qt 独有的一种机制,他让窗口的各种消息处理简化到极致,常规情况下我们相应某窗口(控件)的点击时都需要自己投递消息到框架中,由框架的消息队列投递给不同的窗口消息处理函数来处理。如果使用信号和,...
  • Qt信号-原理分析

    2020-12-19 07:44:04
    一、问题学习Qt有一段时间了,信号用的也是666,可是对信号的机制还是一知半解,总觉着不是那么得劲儿,万一哪天面试被问到了还说不清楚,那岂不是很尴尬。最近抽空研究了下Qt的信号和进制,结果发现也不是...
  • 一开始就想到了信号机制,但是问题在于 button 是 委托中的,没法直接与主窗口进行connect。后来发现,是自己信号没学好,在这里可以使用自定义的方式。将button与委托关联,然后委托与主窗口关联。我的实现...
  • oracle事务(二)

    2021-05-06 07:41:22
    oracle数据块头部有个事务(ITL)。当多个事务同时修改数据块,而且,此时,pctfree(数据块空闲空间的比例)不足10%,则会出现ITL争用。这种现象容易发生在update和delete身上。因为,insert时,oracle会优先分散地...
  • Oracle中关于事务.ppt

    2021-05-06 08:49:13
    Oracle的每个数据块中都有一个或者多个事务,每一个对数据块的并发访 问事务都会占用一个事务。 表和索引的事务ini_trans是1、max_trans是255,在oracle10g中,不能修改 max_trans这个参数,因为oracle10g忽略...
  • 信号和 译文

    2021-02-02 19:08:23
    信号和 信号和用于对象间通信。他们的原理是Qt的主要核心特性,并且可能是Qt和其他框架产生最大不同的特性。通过Qt的原对象系统,实现了信号和的合理性。 简介 在图形化用户界面编程中,当我们修改了一个...
  • Qt5 信号-内容总结

    2021-02-05 08:29:56
    slots简介信号与信号和机制是类型安全(type-safe)的信号 Signal SlotsQObject::connect() 函数ConnectionType 参数说明字符串风格的 connect()QMetaMethod风格的 connect()仿函数风格的connect()支持为非...
  • 信号是 Qt 框架引以为豪的机制之一。当用户触发某个事件时,就会发出一个信号(signal),这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会连接(connect)绑定一个函数(称为slot)来处理...
  • 程序员神吐用户

    2020-12-30 15:05:27
    大多数程序员都喜欢吐用户,快来看看有没有你程序员甲:我们的用户可真叫人头疼,需求多的简直要命,挣他们点钱可真难。程序员乙:就是,事多不说,有些还傻得很。程序员丙:就是,特难搞,自己不会用非说是我们...
  • QT中的信号和

    2021-11-01 11:47:28
    如果存在多个与某个信号相关联,那么,当这个信号被发射时,这些将会一个接一个地 执行,但是它们执行的顺序将会是随机的、不确定的,我们不能人为地指定哪个先执行、哪 个执行。 信号的声明是在头文件中进行...
  • 基于MATLAB有限差分法中的迭代法求解接地金属内电位分布要求运用MATLAB求解接地金属内点位分布, 精度、行数M、列数N自己定义。有限差分法有限差分法是基于差分原理的一种数值计算法。其基本思想想是将场域离散...
  • QT--信号与(1)添加 1.手动关联:mywidget.h定义slots,在mywidget.cpp中定义,在mywidget的构造函数中实现connect函数 2.自动关联:设计器-转到-实现功能
  • 1.用的信号/实现在main函数中将QApplication::lastWindowClosed()信号和QApplication::quit()函数相关联a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );voidQApplication::...
  • 之前一直使用继承QThread的方法使用...类里面有一个函数,并且通过函数调用了一个私有方法 头文件中: #ifndef THREAD_TEST_H #define THREAD_TEST_H #include <QObject> #include "globle_define.h" c
  • Linux 硬盘和

    2021-08-26 15:59:35
    如在有12硬盘的服务器中,每个物理位均插一块硬盘,且没有做RAID,硬盘物理位关系如下: 0 3 6 9 1 4 7 10 2 5 8 11 那么Linux内核启动,IDR机制分配的盘符的整数为0、1、2、3、4、5、6、7、8、9、10、11,...
  • redis中的插槽

    2021-06-18 23:09:49
    正常工作的时候,Redis Cluster中的每个Master节点都会负责一部分的,当有某个key被映射到某个Master负责的,那么这个Master负责为这个key提供服务,至于哪个Master节点负责哪个,这是可以由用户指定的,也...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 221,749
精华内容 88,699
关键字:

后槽