webentwicklung-frage-antwort-db.com.de

Wie rufen Sie die Funktion auf, nachdem das Fenster angezeigt wurde?

Mit Qt erstelle ich ein QMainWindow und möchte eine Funktion aufrufen, NACHDEM das Fenster angezeigt wird. Beim Aufruf der Funktion im Konstruktor wird die Funktion (eigentlich ein Dialog) aufgerufen, bevor das Fenster angezeigt wird.

29
HWende

Wenn Sie etwas tun möchten, während das Widget sichtbar ist, können Sie QWidget :: showEvent wie folgt überschreiben:

class YourWidget : public QWidget { ...

void YourWidget::showEvent( QShowEvent* event ) {
    QWidget::showEvent( event );
    //your code here
} 
31
Frank Osterfeld

Folgen Sie dem Beispiel von Reza Ebrahimi, aber denken Sie daran:

Lassen Sie den fünften Parameter der Funktion connect() nicht aus, der den Verbindungstyp angibt. Stellen Sie sicher, dass es QueuedConnection ist.

I. E., 

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

Ich glaube, dass Sie das erreichen, was Sie brauchen, wenn Sie es auf diese Weise tun.

  • Es gibt verschiedene Arten von Signalschlitzverbindungen: AutoConnection, DirectConnection, QueuedConnection, BlockingQueuedConnection (+ optional UniqueConnection). Lesen Sie das Handbuch für Details. :)
13
Kieung Kim

versuche dies:

im Hauptfenster.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;
}

in 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
}
12
Reza Ebrahimi

Ich habe es ohne Timer mit Paint Event gelöst. Funktioniert bei mir zumindest unter 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;
}
1
RuslanK

Die beste Lösung für mich ist, einmal Paint-Ereignis zu zählen:

.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++;
  }
}
1
hexadecimal

Ich habe eine schöne Antwort in diese Frage gefunden, die gut funktioniert, auch wenn Sie eine Sleep () - Funktion verwenden.

Also probiert es aus:

//- 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
1
Michael Sasser

Angenommen, Sie möchten Ihren Code im UI-Thread des Fensters ausführen nachdem das Fenster angezeigt wurde, können Sie den folgenden relativ kompakten Code verwenden. 

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
    }
};

Es ruft afterWindowShown zwar mit dem Namen auf, aber in Qt ist dies ziemlich üblich. Es gibt Möglichkeiten, dies zu vermeiden, aber sie sind etwas ausführlicher.

Beachten Sie, dass dieser Code für jede abgeleitete QWidget-Klasse und nicht nur für von QMainWindow abgeleitete Klassen funktionieren sollte.

Theoretisch kann es für einen sehr schnellen Benutzer möglich sein, eine Aktion auf der Benutzeroberfläche des angezeigten Fensters aufzurufen, bevor afterWindowShown aufgerufen werden kann, was jedoch unwahrscheinlich erscheint. Etwas, an das man denken und sich vielleicht wehren muss.

0
persiflage

Nach der Analyse der obigen Lösungen hat sich herausgestellt, dass die meisten von ihnen, einschließlich der stark überstimmten, fehlerhaft sind.

Viele empfehlen so etwas:

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

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

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

Dies funktioniert solange es keine QCoreApplication::processEvents(); in DoSomething gibt. Wenn es eines gibt, verarbeitet es alle Ereignisse in der Warteschlange einschließlich des QShowEvent, das an erster Stelle MyWidget :: showEvent aufgerufen hat. Wenn es zum ursprünglichen QShowEvent kommt, ruft es MyWidget :: showEvent erneut auf und verursacht eine Endlosschleife.

In diesem Fall gibt es drei Lösungen:

Lösung 1. Vermeiden Sie es, processEvents in MyWidget::DoSomething Aufzurufen, und rufen Sie stattdessen update oder repaint auf, wenn dies erforderlich ist. Wenn DoSomething etwas anderes aufruft, sollten diese Funktionen auch processEvents vermeiden.

Lösung 2. Machen Sie DoSomething zu einem Slot und ersetzen Sie den direkten Aufruf von DoSomething () durch

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

Da der Nullintervall-Timer nur ausgelöst wird, wenn alle Ereignisse in der Warteschlange verarbeitet wurden, werden alle Ereignisse, einschließlich des ursprünglichen QShowEvent, verarbeitet, aus der Warteschlange entfernt und erst dann DoSomething aufgerufen. Ich mag es am meisten.

Da nur der Nullintervall-Timer ausgelöst wird, wenn alle Ereignisse in der Warteschlange verarbeitet wurden, sollten Sie nicht versuchen, ihn zu "verbessern", indem Sie beispielsweise das Intervall verlängern

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

Da 50 ms normalerweise genug Zeit für die Verarbeitung von Ereignissen in der Warteschlange sind, würde normalerweise ein schwer reproduzierbarer Fehler auftreten.

Lösung 3. Erstellen Sie ein Flag, das den zweiten Aufruf von DoSomething verhindert:

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() {
    // ...
}

Hier ist is_opening ein Boolesches Flag, das im Konstruktor als false initialisiert werden sollte.

0
user31264

Reimplement-Methode void show() wie folgt

void MainWindow::show()
{
    QMainWindow::show();
    // Call your special function here.
}
0
klasyc