使用Qt我创建一个 QMainWindow ,并希望在显示窗口后调用一个函数。当我在构造函数中调用该函数时,在显示窗口之前调用函数(实际上是一个对话框)。
答案 0 :(得分:32)
如果您希望在窗口小部件可见时执行某些操作,则可以覆盖QWidget::showEvent,如下所示:
class YourWidget : public QWidget { ...
void YourWidget::showEvent( QShowEvent* event ) {
QWidget::showEvent( event );
//your code here
}
答案 1 :(得分:13)
试试这个:
在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;
}
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
}
答案 2 :(得分:13)
关注Reza Ebrahimi的例子,但要牢记这一点:
不要省略指定连接类型的connect()
函数的第5个参数;确保它是QueuedConnection
。
I.E。,
connect(this, SIGNAL(window_loaded), this, SLOT(your_function()), Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
我相信如果你这样做,你就能达到你的需要。
AutoConnection
,DirectConnection
,QueuedConnection
,BlockingQueuedConnection
(+可选UniqueConnection
)。阅读手册了解详情。 :)答案 3 :(得分:1)
我在this question找到了一个很好的答案,即使你使用Sleep()函数也能很好地运作。
试过这个:
//- cpp-file ----------------------------------------
#include "myapp.h"
#include <time.h>
#include <iosteream>
MyApp::MyApp(QWidget *parent)
: QMainWindow(parent, Qt::FramelessWindowHint)
{
ui.setupUi(this);
}
MyApp::~MyApp()
{
}
void MyApp::showEvent(QShowEvent *event) {
QMainWindow::showEvent(event);
QTimer::singleShot(50, this, SLOT(window_shown()));
return;
}
void MyApp::window_shown() {
std::cout << "Running" << std::endl;
Sleep(10000);
std::cout << "Delayed" << std::endl;
return;
}
//- h-file ----------------------------------------
#ifndef MYAPP_H
#define MYAPP_H
#include <QtWidgets/QMainWindow>
#include <qtimer.h>
#include <time.h>
#include "ui_myapp.h"
class MyApp : public QMainWindow
{
Q_OBJECT
public:
MyApp(QWidget *parent = 0);
~MyApp();
protected:
void showEvent(QShowEvent *event);
private slots:
void window_shown();
private:
Ui::MyAppClass ui;
};
#endif // MYAPP_H
答案 4 :(得分:1)
我使用Paint事件在没有计时器的情况下解决了它。至少在Windows上适用于我。
// MainWindow.h
class MainWindow : public QMainWindow
{
...
bool event(QEvent *event) override;
void functionAfterShown();
...
bool functionAfterShownCalled = false;
...
}
// MainWindow.cpp
bool MainWindow::event(QEvent *event)
{
const bool ret_val = QMainWindow::event(event);
if(!functionAfterShownCalled && event->type() == QEvent::Paint)
{
functionAfterShown();
functionAfterShownCalled = true;
}
return ret_val;
}
答案 5 :(得分:1)
对我来说最好的解决方案是计算一次油漆事件:
<强>·H 强>
public:
void paintEvent(QPaintEvent *event);
<强> .CPP 强>
#include "qpainter.h"
#include <QMessageBox> // example
int contPaintEvent= 0;
void Form2::paintEvent(QPaintEvent* event)
{
if (contPaintEvent ==0 )
{
QPainter painter(this);
QMessageBox::information(this, "title", "1 event paint"); // example
// actions
contPaintEvent++;
}
}
答案 6 :(得分:0)
重新实现方法void show()
,如下所示:
void MainWindow::show()
{
QMainWindow::show();
// Call your special function here.
}
答案 7 :(得分:0)
假设您要在窗口 之后的窗口的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
}
};
它确实通过名称调用afterWindowShown,但是这种事情在Qt中是相当普遍的做法。有一些避免这种情况的方法,但是它们有些冗长。
请注意,此代码应适用于任何QWidget派生类,而不仅仅是QMainWindow派生类。
理论上,非常快的用户可能会在调用afterWindowShown之前在显示的窗口的UI上调用某种动作,但这似乎不太可能。可能需要记住一些东西并可能防御性地编写代码。
答案 8 :(得分:0)
对上述解决方案进行分析后,发现其中大多数(包括遭到严重抨击的解决方案)都是错误的。
许多推荐这样的东西:
class MyWidget : public QWidget {
// ...
};
void MyWidget::showEvent(QShowEvent* event) {
QWidget::showEvent(event);
DoSomething();
}
void MyWidget::DoSomething() {
// ...
}
只要QCoreApplication::processEvents();
中没有DoSomething
,此方法就起作用。如果有一个事件,它将处理队列中的所有事件,包括QShowEvent
,该事件首先调用MyWidget :: showEvent 。当到达原始QShowEvent时,它将再次调用MyWidget :: showEvent,从而导致无限循环。
如果发生这种情况,有三种解决方法:
解决方案1.避免在processEvents
中调用MyWidget::DoSomething
,而是在必要时调用update
或repaint
。如果DoSomething
调用了其他内容,这些函数也应避免使用processEvents
。
解决方案2.将DoSomething放入插槽,并用
替换对DoSomething()的直接调用QTimer::singleShot(0, this, SLOT(DoSomething()));
由于零间隔计时器仅在处理完队列中的所有事件后才会触发,因此它将处理所有事件,包括原始QShowEvent,将其从队列中删除,然后才调用DoSomething。我最喜欢它。
由于只有零间隔计时器才在队列中的所有事件都处理完后才触发,因此您不应该尝试通过延长间隔来“改善”它
QTimer::singleShot(50, this, SLOT(DoSomething())); // WRONG!
由于通常 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() {
// ...
}
这里,is_opening是一个布尔型标志,应在构造函数中初始化为false。