如何在窗口后调用函数?

HWe*_*nde 34 c++ qt

使用Qt我创建了一个QMainWindow,并希望在显示窗口后调用一个函数.当我在构造函数中调用该函数时,在显示窗口之前调用函数(实际上是一个对话框).

Fra*_*eld 32

如果要在窗口小部件可见时执行某些操作,可以像这样覆盖QWidget :: showEvent:

class YourWidget : public QWidget { ...

void YourWidget::showEvent( QShowEvent* event ) {
    QWidget::showEvent( event );
    //your code here
} 
Run Code Online (Sandbox Code Playgroud)

  • 我推荐了四个你建议的实现,但是在显示窗口之前,对话框仍然显示出来. (6认同)
  • 我已经考虑过实现我自己的show函数了,但是我从来没有想到我可以在我自己的代码之前调用父的show函数.*facepalm* (3认同)
  • 如果您使用 exec(),那是因为 exec() 使用本地事件循环,这是 Qt 中万恶之源。您可以使用 QDialog::open 而不是 exec() 异步而不是同步打开它 (3认同)
  • 当我的 QMainWindow 继承类 get 显示时,它应该显示一个询问某些内容的对话框。但是我无法在屏幕上显示 MainWindow 后显示对话框。 (2认同)

Rez*_*imi 14

试试这个:

在mainwindow.h中:

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();  

protected:
      void showEvent(QShowEvent *ev);

private:
      void showEventHelper();
      Ui::MainWindow *ui;
}
Run Code Online (Sandbox Code Playgroud)

在mainwindow.cpp中:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

void MainWindow::showEvent(QShowEvent *ev)
{
    QMainWindow::showEvent(ev);
    showEventHelper();
}

void MainWindow::showEventHelper()
{
    // your code placed here
}
Run Code Online (Sandbox Code Playgroud)

  • 令人惊讶但有趣的同时,为什么要使用这个额外的信号和插槽.直接在void MainWindow :: showEvent()内调用函数(例如*doWork()*). (3认同)

小智 13

按照Reza Ebrahimi的例子,但记住这一点:

不要省略connect()指定连接类型的函数的第5个参数; 确保它是QueuedConnection.

IE浏览器,

connect(this, SIGNAL(window_loaded), this, SLOT(your_function()), Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
Run Code Online (Sandbox Code Playgroud)

我相信如果你这样做,你就能实现你所需要的.

  • 有几种类型的信号槽连接:AutoConnection,DirectConnection,QueuedConnection,BlockingQueuedConnection(+可选UniqueConnection).阅读手册了解详情.:)


use*_*264 12

在分析了上述解决方案后,发现所有解决方案,包括高票数的解决方案,都是错误的。

许多人推荐这样的东西:

class MyWidget : public QWidget {
    // ...
};

void MyWidget::showEvent(QShowEvent* event) {
    QWidget::showEvent(event);
    DoSomething();
}

void MyWidget::DoSomething() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

只要没有QCoreApplication::processEvents();in 就可以工作DoSomething。如果有,它会处理队列中的所有事件,包括QShowEvent首先调用 MyWidget::showEvent 的事件。当它到达原始的 QShowEvent 时,它再次调用 MyWidget::showEvent,导致无限循环。

如果发生这种情况,有以下三种解决方案:

解决方法1.避免调用processEventsMyWidget::DoSomething,而不是打电话updaterepaint在必要时。如果DoSomething调用别的东西,这些函数processEvents也应该避免。

解决方案 2. 将 DoSomething 设为插槽,并将对 DoSomething() 的直接调用替换为

QTimer::singleShot(0, this, SLOT(DoSomething()));
Run Code Online (Sandbox Code Playgroud)

由于零间隔计时器仅在队列中的所有事件都处理完后才触发,因此它将处理所有事件,包括原始 QShowEvent,将它们从队列中删除,然后才调用 DoSomething。我最喜欢它。

由于只有在处理完队列中的所有事件后才会触发零间隔计时器,因此您不应尝试通过延长间隔来“改进”它,例如

QTimer::singleShot(50, this, SLOT(DoSomething())); // WRONG!
Run Code Online (Sandbox Code Playgroud)

由于 50 毫秒通常足以处理队列中的事件,这通常会起作用,从而导致难以重现的错误。

解决方案 3. 制作一个标志,防止第二次调用 DoSomething:

class MyWidget : public QWidget {
    // ...
};

void MyWidget::showEvent(QShowEvent* event) {
    if (is_opening)
        return;
    is_opening = true;
    QWidget::showEvent(event);
    DoSomething();
    is_opening = false;
}

void MyWidget::DoSomething() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这里,is_opening 是一个布尔标志,它应该在构造函数中初始化为 false。


per*_*age 5

假设您希望在显示窗口在窗口的 UI 线程中运行代码,您可以使用以下相对紧凑的代码。

class MainWindow : public QMainWindow
{
        // constructors etc omitted.

protected:
    void showEvent(QShowEvent *ev)
    {
        QMainWindow::showEvent(ev);
        // Call slot via queued connection so it's called from the UI thread after this method has returned and the window has been shown
        QMetaObject::invokeMethod(this, "afterWindowShown", Qt::ConnectionType::QueuedConnection);
    }

private slots:
    void afterWindowShown()
    {
        // your code here
        // note this code will also be called every time the window is restored from a minimized state
    }
};
Run Code Online (Sandbox Code Playgroud)

它确实通过名称调用 afterWindowShown,但这种事情在 Qt 中相当常见。有一些方法可以避免这种情况,但它们有点冗长。

请注意,此代码应该适用于任何 QWidget 派生类,而不仅仅是 QMainWindow 派生类。

理论上,在调用 afterWindowShown 之前,非常快速的用户可能会在显示窗口的 UI 上调用某种操作,但这似乎不太可能。也许需要记住一些事情并进行防御性编码。

  • 我喜欢这个解决方案,谢谢。顺便说一句,在当前的 Qt 版本中,您可以编写 `QMetaObject::invokeMethod(this, &MainWindow::afterWindowShown, Qt::ConnectionType::QueuedConnection);` 并摆脱字符串函数名称。 (2认同)