Qt を使用してQMainWindowを作成し、ウィンドウが表示された後に関数を呼び出したいと考えています。コンストラクターで関数を呼び出すと、ウィンドウが表示される前に関数 (実際にはダイアログ) が呼び出されます。
9 に答える
ウィジェットが表示されている間に何かをしたい場合は、次のようにQWidget::showEventをオーバーライドできます。
class YourWidget : public QWidget { ...
void YourWidget::showEvent( QShowEvent* event ) {
QWidget::showEvent( event );
//your code here
}
これを試して:
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
}
Reza Ebrahimi の例に従いますが、次の点に注意してください。
connect()
接続タイプを指定する関数の 5 番目のパラメーターを省略しないでください。であることを確認してQueuedConnection
ください。
いえ、
connect(this, SIGNAL(window_loaded), this, SLOT(your_function()), Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
このようにすれば、必要なものが得られると思います。
AutoConnection
シグナルスロット接続には、 、DirectConnection
、QueuedConnection
、BlockingQueuedConnection
(+ オプション)のいくつかのタイプがありますUniqueConnection
。詳細はマニュアルをお読みください。:)
上記の解決策を分析した後、非常に支持されたものを含め、それらすべてに欠陥があることがわかりました.
多くの人が次のようなことを推奨しています。
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
を呼び出します。他の何かを呼び出す場合、これらの関数も回避する必要があります。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 の 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 として初期化する必要があります。
ウィンドウが表示された後にウィンドウの 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 で何らかのアクションを呼び出すことは可能かもしれませんが、そうは思えません。おそらく心に留めて、防御的にコーディングする何か。
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
void show()
次のようにメソッドを再実装します。
void MainWindow::show()
{
QMainWindow::show();
// Call your special function here.
}