使用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)
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)
小智 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.避免调用processEvents的MyWidget::DoSomething,而不是打电话update或repaint在必要时。如果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。
假设您希望在显示窗口后在窗口的 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 上调用某种操作,但这似乎不太可能。也许需要记住一些事情并进行防御性编码。
| 归档时间: |
|
| 查看次数: |
37825 次 |
| 最近记录: |