42

Qt を使用してQMainWindowを作成し、ウィンドウが表示された後に関数を呼び出したいと考えています。コンストラクターで関数を呼び出すと、ウィンドウが表示される前に関数 (実際にはダイアログ) が呼び出されます。

4

9 に答える 9

38

ウィジェットが表示されている間に何かをしたい場合は、次のようにQWidget::showEventをオーバーライドできます。

class YourWidget : public QWidget { ...

void YourWidget::showEvent( QShowEvent* event ) {
    QWidget::showEvent( event );
    //your code here
} 
于 2013-01-16T11:50:04.120 に答える
15

これを試して:

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
}
于 2013-01-23T16:55:41.880 に答える
13

Reza Ebrahimi の例に従いますが、次の点に注意してください。

connect()接続タイプを指定する関数の 5 番目のパラメーターを省略しないでください。であることを確認してQueuedConnectionください。

いえ、

connect(this, SIGNAL(window_loaded), this, SLOT(your_function()), Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));

このようにすれば、必要なものが得られると思います。

  • AutoConnectionシグナルスロット接続には、 、DirectConnectionQueuedConnectionBlockingQueuedConnection(+ オプション)のいくつかのタイプがありますUniqueConnection。詳細はマニュアルをお読みください。:)
于 2014-10-30T10:01:55.820 に答える
13

上記の解決策を分析した後、非常に支持されたものを含め、それらすべてに欠陥があることがわかりました.

多くの人が次のようなことを推奨しています。

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

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

void MyWidget::DoSomething() {
    // ...
}

QCoreApplication::processEvents();が存在しない限り、これは機能しDoSomethingます。存在する場合は、最初に呼び出された MyWidget::showEvent を含む、QShowEventキュー内のすべてのイベントを処理します。元の QShowEvent に到達すると、再び MyWidget::showEvent を呼び出し、無限ループを引き起こします。

この場合、次の 3 つの解決策があります。

processEvents解決策 1. を呼び出すのを避け、必要に応じてまたはMyWidget::DoSomethingを呼び出します。他の何かを呼び出す場合、これらの関数も回避する必要があります。updaterepaintDoSomethingprocessEvents

解決策 2. DoSomething をスロットにし、DoSomething() への直接呼び出しを次のように置き換えます。

QTimer::singleShot(0, this, SLOT(DoSomething()));

ゼロ間隔タイマーは、キュー内のすべてのイベントが処理された後にのみ起動するため、元の QShowEvent を含むすべてのイベントを処理し、それらをキューから削除してから DoSomething を呼び出します。私はそれが一番好きです。

キュー内のすべてのイベントが処理された後にのみゼロ間隔タイマーが起動するため、たとえば、間隔を長くして「改善」しようとしないでください。

QTimer::singleShot(50, this, SLOT(DoSomething())); // WRONG!

通常、 50 ミリ秒はキュー内のイベントを処理するのに十分な時間であるため、通常はこれでうまくいき、再現が難しいエラーが発生します。

解決策 3. DoSomething の 2 回目の呼び出しを防止するフラグを作成します。

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 として初期化する必要があります。

于 2019-07-02T12:46:55.127 に答える
4

ウィンドウが表示された後にウィンドウの 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 ではかなり一般的な方法です。これを回避する方法はありますが、もう少し冗長です。

このコードは、QMainWindow 派生クラスだけでなく、QWidget 派生クラスでも機能することに注意してください。

理論的には、afterWindowShown を呼び出す前に、非常に迅速なユーザーが表示されたウィンドウの UI で何らかのアクションを呼び出すことは可能かもしれませんが、そうは思えません。おそらく心に留めて、防御的にコーディングする何か。

于 2018-10-11T16:52:58.293 に答える
2

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
于 2016-08-03T17:14:51.883 に答える
0

void show()次のようにメソッドを再実装します。

void MainWindow::show()
{
    QMainWindow::show();
    // Call your special function here.
}
于 2016-10-24T07:49:31.147 に答える