请教Qt信号和槽问题

[复制链接]
查看11 | 回复5 | 2021-1-27 05:08:48 | 显示全部楼层 |阅读模式
在MainWindow中定义了一个myPushButton的指针。
classMainWindow:publicQMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget*parent=nullptr);
~MainWindow();
voidguanbi();
private:
Ui::MainWindow*ui;
myPushButton*nBtn;//
这个是myPushButton的定义
classmyPushButton:publicQPushButton
{
Q_OBJECT
public:
explicitmyPushButton(QWidget*parent=nullptr);
~myPushButton();
voidresponse();
signals:
voidmys();//
然后将其同信号mys关联起来。
MainWindow::MainWindow(QWidget*parent)
:QMainWindow(parent)
,ui(newUi::MainWindow)
{
ui->setupUi(this);
nBtn=newmyPushButton;
nBtn->move(100,200);
nBtn->resize(100,50);
nBtn->setText("nPushbutton");
nBtn->setParent(this);
setWindowTitle("testwindow");
setFixedSize(800,600);
connect(nBtn,&myPushButton::mys,this,&MainWindow::close);//mys();
}

根据打印来看,信号是正常发射了,但是MainWindow不能关闭(也就是运行后MainWindow一直显示,不会关闭)。如果将connect函数换成下面的方式,则response函数能正常运行到,这说明连接信号没有问题,但是为什么就无法执行close呢?
connect(nBtn,&myPushButton::mys,nBtn,&myPushButton::response);
请教各位,谢谢!
分 -->
回复

使用道具 举报

千问 | 2021-1-27 05:08:48 | 显示全部楼层
执行guanbi()时,MainWindow还没进入事件循环中(在MainWindow的构造函数中)
回复

使用道具 举报

千问 | 2021-1-27 05:08:48 | 显示全部楼层
引用1楼非弋的回复:执行guanbi()时,MainWindow还没进入事件循环中(在MainWindow的构造函数中)
那为什么连接换成connect(nBtn,&myPushButton::mys,nBtn,&myPushButton::response),response就能正常执行,不也还是在MainWindow的构造函数中吗,也没有进入事件循环呀?
我是新手,不是很懂,谢谢。
回复

使用道具 举报

千问 | 2021-1-27 05:08:48 | 显示全部楼层

connect的函数原型为:
QMetaObject::ConnectionQObject::connect(constQObject*sender,
constchar*signal,
constQObject*receiver,
constchar*method,
Qt::ConnectionTypetype=Qt::AutoConnection);
最后一个参数决定,这个信号槽是直接连接还是队列连接,默认值是Qt::AutoConnection
对于Qt::AutoConnection的情况:
1、sender和receiver依附线程是同一个,就是直接连接
2、sender和receiver依附线程不是同一个,就是队列连接
依附线程可以理解为:在哪个线程new的就依附哪个线程,eg:
A*a=newA;//a的依附线程为thread1
QThread*thread2=newQThread;
a->moveToThread(thread2);//a的依附线程变为thread2
直接连接:类似直接调用函数(立即执行)
队列连接:将信号放在一个队列中,等receiver有空了开始执行
connect(nBtn,
&myPushButton::mys,
nBtn,
&myPushButton::response);
是直接连接,myPushButton::mys信号发射时,会立即执行myPushButton::response
connect(nBtn,
&myPushButton::mys,
this,
&MainWindow::close);
也是直接连接,myPushButton::mys信号发射时,也会立即执行MainWindow::close
但是在MainWindow::close中,不是直接就关闭这个窗口,而是向MainWindow发送一个QCloseEvent的事件
QCloseEvent会在事件循环中分发给MainWindow,在事件分发中可以对事件进行过滤(这些都是后话了)
QApplicationa(argc,argv);
...
//开始事件循环
//在事件循环前调用close无效
a.exec();

回复

使用道具 举报

千问 | 2021-1-27 05:08:48 | 显示全部楼层
引用4楼非弋的回复:connect的函数原型为:
QMetaObject::ConnectionQObject::connect(constQObject*sender,
constchar*signal,
constQObject*receiver,
constchar*method,
Qt::ConnectionTypetype=Qt::AutoConnection);
最后一个参数决定,这个信号槽是直接连接还是队列连接,默认值是Qt::AutoConnection
对于Qt::AutoConnection的情况:
1、sender和receiver依附线程是同一个,就是直接连接
2、sender和receiver依附线程不是同一个,就是队列连接
依附线程可以理解为:在哪个线程new的就依附哪个线程,eg:
A*a=newA;//a的依附线程为thread1
QThread*thread2=newQThread;
a->moveToThread(thread2);//a的依附线程变为thread2
直接连接:类似直接调用函数(立即执行)
队列连接:将信号放在一个队列中,等receiver有空了开始执行
connect(nBtn,
&myPushButton::mys,
nBtn,
&myPushButton::response);
是直接连接,myPushButton::mys信号发射时,会立即执行myPushButton::response
connect(nBtn,
&myPushButton::mys,
this,
&MainWindow::close);
也是直接连接,myPushButton::mys信号发射时,也会立即执行MainWindow::close
但是在MainWindow::close中,不是直接就关闭这个窗口,而是向MainWindow发送一个QCloseEvent的事件
QCloseEvent会在事件循环中分发给MainWindow,在事件分发中可以对事件进行过滤(这些都是后话了)
QApplicationa(argc,argv);
...
//开始事件循环
//在事件循环前调用close无效
a.exec();

多谢您的详细解答,最后再问下:
您上面的回答最后提到“在MainWindow::close中,不是直接就关闭这个窗口,而是向MainWindow发送一个QCloseEvent的事件
QCloseEvent会在事件循环中分发给MainWindow,在事件分发中可以对事件进行过滤”
那窗口没有关闭是不是意味着这个事件被过滤掉了,因为即便不直接关闭窗口,但是程序最后总是会进入事件循环的,等到进入事件循环后不就可以关闭了?
回复

使用道具 举报

千问 | 2021-1-27 05:08:48 | 显示全部楼层
引用那窗口没有关闭是不是意味着这个事件被过滤掉了,因为即便不直接关闭窗口,但是程序最后总是会进入事件循环的,等到进入事件循环后不就可以关闭了?
这问题还真没有注意过,做了一个测试:
重载closeEvent,并在QApplication.exec()之前调用close()查看是否有运行closeEvent
voidWidget::closeEvent(QCloseEvent*event)
{
qDebug()
测试结果是有运行closeEvent,和我理解中的有点不太一样,能力有限,不敢误人
参考Qt的事件循环机制:https://blog.csdn.net/simonyucsdy/article/details/82749539
查看QWidget::close的帮助文档:
Closesthiswidget.Returnstrueifthewidgetwasclosed;otherwisereturnsfalse.
FirstitsendsthewidgetaQCloseEvent.Thewidgetishiddenifitacceptsthecloseevent.
Ifitignorestheevent,nothinghappens.ThedefaultimplementationofQWidget::closeEvent()acceptsthecloseevent.
IfthewidgethastheQt::WA_DeleteOnCloseflag,thewidgetisalsodeleted.Acloseeventsisdeliveredtothewidgetnomatterifthewidgetisvisibleornot.
TheQApplication::lastWindowClosed()signalisemittedwhenthelastvisibleprimarywindow(i.e.windowwithnoparent)withtheQt::WA_QuitOnCloseattributesetisclosed.Bydefaultthisattributeissetforallwidgetsexcepttransientwindowssuchassplashscreens,toolwindows,andpopupmenus.
大致的翻译如下:
关闭此小部件。如果小部件已关闭,则返回true;否则,返回false
首先,它向小部件发送QCloseEvent。如果小部件接受关闭事件,则将其隐藏。
如果它忽略该事件,则什么也不会发生。QWidget::closeEvent()的默认实现接受close事件。
如果该小部件具有Qt::WA_DeleteOnClose标志,则该小部件也将被删除。无论小部件是否可见,关闭事件都会传递给小部件。
关闭最后一个设置了Qt::WA_QuitOnClose属性的可见主窗口(即没有父窗口)时,将发出QApplication::lastWindowClosed()信号。
默认情况下,为所有窗口小部件设置此属性,瞬态窗口(例如初始屏幕,工具窗口和弹出菜单)除外。
说明:
QWidget::close方法只是隐藏窗口,除非设置了Qt::WA_DeleteOnClose、Qt::WA_QuitOnClose属性,详细见:
Qt对话框与窗口的关闭和隐藏(QCloseEvent、Qt::WA_DeleteOnClose属性、Qt::WA_QuitOnClose属性)
https://blog.csdn.net/hyongilfmmm/article/details/83247688
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行