Qt:在构造函数内部连接-在初始化对象之前会调用插槽吗? [英] Qt: Connect inside constructor - Will slot be invoked before object is initialized?

查看:273
本文介绍了Qt:在构造函数内部连接-在初始化对象之前会调用插槽吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Qt框架(C ++),想知道QT是否有任何机制可以防止在对象完全初始化之前调用插槽.

I am learning Qt framework (C++) and was wondering if QT has any mechanisms to protect slots from being called before an object is fully initialized.

考虑A类构造函数:

A::A() {
    mTreeView = new QTreeView();
    ...
    connect(mTreeView, &QTreeView::customContextMenuRequested,
        this, &A::OnContextMenuRequested);
    ...
}

我担心的是,用户将能够在A的构造函数完成之前右键单击树视图.另一个上下文如下:

My worry is the user would be able to right-click on the tree-view before A's constructor has finished. Another context is as follows:

A::A() {
    mQObj = new MyQObject();
    connect(mQObj, &MyQObject::SomeEvent, this, &A::OnEvent);
}

A::InitB() { mB = new B(); }

A::OnEvent() { mB.doSomething(); }

在这里,可以在InitB()运行之前调用doSomething()方法.

Here, the doSomething() method can be called before InitB() runs.

我是否需要担心这种情况?如果是这样,有没有一种方法可以避免这些问题,而不必先初始化所有对象,然后再返回并分别连接事件?

Do I have to worry about such scenarios? And if so, is there a way to avoid these issues without having to initialize all your objects first, then going back and connecting the events afterwards separately?

推荐答案

在大多数情况下,您不必担心此类情况,因为事件是在同一线程中传递的.您不必在意隐藏的多线程".如果您没有在A的构造函数中显式调用导致事件被处理的函数,那么您是安全的,当前的方法,插槽等的执行将在处理下一个事件之前完成.

You don't have to worry about such scenarios in most cases, because events are delivered in the same thread. There's no "hidden multithreading" going on you have to care about. If you don't explicitly call a function in the constructor of A that causes events to be processed, you're safe and your current method, slot etc.'s execution is completed before the next event is processed.

也就是说,处理新事件并因此执行其他代码(事件处理程序,插槽)的情况是:

That said, the cases where a new event is processed and thus other code (event handlers, slots) is executed, are:

  1. 当前事件处理程序,插槽等的执行完成(您创建A的代码),并且Qt返回事件循环以等待下一个事件.就您而言,那是在A实例完全构建之后.
  2. 您启动本地事件循环(创建 QEventLoop 对象并调用exec ())
  3. 您调用 QCoreApplication :: processEvents()
  4. 您在QDialog上调用 exec()
  1. the execution of the current event handler, slot etc. is finished (the code where you create A) and Qt returns to the event loop to wait for the next event. In your case, that's after the A instance is fully constructed.
  2. you start a local event loop (Create a QEventLoop object and call exec())
  3. you call QCoreApplication::processEvents()
  4. you call exec() on a QDialog

1)是Qt运行的常规模式:启动app.exec(),这将启动事件循环.之后的所有事件都直接或间接地由事件(用户输入,计时器,I/O)触发.事件发生并被添加到事件循环的事件队列中.事件循环调用事件的事件处理程序.事件处理程序完成后,事件循环将选择下一个事件并为其调用处理程序.

1) is the normal mode Qt operates in: You start app.exec(), which starts the event loop. Everything after that is directly or indirectly triggered by an event (user input, timer, I/O). Event happens and is added to the event loop's event queue. The event loop calls the event handlers for the event. When the event handlers are completed, the event loop picks the next event and calls the handlers for it.

因此,一切都会以一种有序的方式发生,一个接一个的事件发生,除非其中一个事件处理程序(例如,监听按钮的clicked()信号的插槽)执行2、3或4之一.然后Qt处理下一个事件事件就地,即调用exec()或processEvents()的位置.事件处理程序/插槽将相应执行. 然后 exec()/processEvents()返回.现在,不幸的是,不用调用exec()/processEvents()就可以拥有的所有确定性都消失了:用户可以做随机的事情,可以任意更改或删除事物(即使this指针,如果用户关闭了窗口也可以) , 例如).因此,特别是2)和3)容易出错,通常会导致严重的头痛,因此我会尽可能避免它们,或者至少要意识到潜在的问题.

So everything happens in an orderly fashion, one event after another, unless one of the event handlers (say, a slot listening to a button's clicked() signal) does one of 2, 3 or 4. Then Qt processes the next event in-place, .i.e. where exec() or processEvents() is called. The event handlers/slots are executed accordingly. Then exec()/processEvents() returns. Now all the certainties one would have without calling exec()/processEvents() are gone, unfortunately: The user could have done random stuff, things could be arbitrarily changed or deleted (even the this pointer, if the user closed the window, for example). Thus especially 2) and 3) are error-prone and usually lead to major headaches, so I would avoid them whenever possible, or at least be aware of the potential issues.

现在,您需要自己使用多线程.由于所有实际的UI和相关用户事件都是在单个主线程中处理的,因此这里的多线程通常意味着您具有执行非UI工作的线程,并且通过调用位于UI线程中的对象上的函数并修改数据来与UI线程进行交互由两个线程共享,或使用跨线程信号/插槽连接.

Now there's the case that you use multithreading yourself. As all the actual UI and related user events is handled in a single main thread, multithreading here usually means that you have threads doing non-UI work and that interacts with your UI thread by calling functions on objects living in the UI thread, modifying data shared by both threads, or using cross-thread signal/slot connections.

  • 如果您不使用信号/插槽,而是将方法从辅助线程直接调用到UI线程或修改共享数据,则适用通常的多线程规则:除非您知道自己在做什么和使用,否则事情将大为错误.相应地进行同步. Qt的UI类不是线程安全的.
  • 如果您使用信号/插槽,则调用/排队/,即,如果线程B发出信号并且您在主线程的插槽中接收到信号,则该插槽的调用以与用户相同的方式进行传递事件:适用与用户事件相同的规则.除非您执行2、3、4之一,否则在事件处理程序/插槽返回之前不会调用该插槽.因此,跨线程信号/插槽连接是/message Passing/传递消息/通过事件循环传递消息的一种方式.

这篇关于Qt:在构造函数内部连接-在初始化对象之前会调用插槽吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆