Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 3179 razy

Zdarzenia i subklassing

Każda klasa okna czy też kontrolki ma pewien zestaw specjalnych metod, które nazywane są uchwytami zdarzeń (ang. events handlers). Metody te są automatycznie wywoływane na z góry określone zdarzenie. Oto lista kilku przykładowych metod tego typu, które są chronione:

  • mousePressEvent - wywoływana, gdy przycisk myszy zostanie wciśnięty na kontrolce lub oknie programu;
  • mouseReleaseEvent - wywoływana, gdy przycisk myszy zostaje zwolniony na kontrolce lub oknie programu;
  • mouseMoveEvent - wywoływana, gdy kursor myszy przemieszcza się nad oknem programu lub kontrolką;
  • resizeEvent - wywoływana, gdy rozmiar okna jest zmieniany;
  • paintEvent - wywoływana, gdy okno lub kontrolka ma zostać odrysowana.

Oczywiście tych metod jest więcej i wszystkie one są chronione co nie znaczy, że nie da się do nich dorwać używając subclassing-u. Takim typowym przykładem subklassing-u jest klasa MainWindow, która z kolei dziedziczy po klasie QMainWindow. Dzięki takiemu zabiegowi można nadpisać metodę z klasy bazowej, która jest odpowiedzialna za obsługę danego zdarzenia. Oto przykład zastosowania tej techniki do wykonania własnych działań na kontrolce umieszczonej w oknie głównym programu gdy ten zmieni swój rozmiar:

W pliku mainwindow.h:

#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QResizeEvent> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT void resizeEvent(QResizeEvent *event) override; public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H

I w pliku mainwindow.cpp:

#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::resizeEvent(QResizeEvent *event){ // nowa metoda, która zostanie wywołana przy zmianie rozmiarów okna QMainWindow::resizeEvent(event); // uruchamianie starej metody klasy bazowej ui->edit->setGeometry(0, 0, event->size().width(), event->size().height()); // ustawiam wymiary kontrolki za pomocą danych z klasy QResizeEvent }

Każda metoda przechwytująca zdarzenie przyjmuje jako argument wskaźnik na klasę, która zawsze dziedziczy po klasie QEvent. Warto pamiętać, że informacje związane z danym zdarzeniem powinny być pozyskiwane właśnie z odpowiedniego obiektu dziedziczącego po tejże klasie.

W przypadku zdarzeń związanych z myszką metody przechwytujące jej zdarzenia przyjmują jako argument wskaźnik na obiekt klasy QMouseEvent. Warto też pamiętać, że zdarzenie mouseMoveEvent domyślnie jest wywoływane jedynie gdy dowolny przycisk został wciśnięty i kursor myszy przesunięty, aby zmienić to zachowanie konieczne jest włączenie śledzenia kursora za pomocą metody setMouseTracking:

ui->centralWidget->setMouseTracking(true);

Filtrowanie zdarzeń

Możliwe jest również filtrowanie i przechwytywanie zdarzeń poprzez nadpisanie metody eventFilter oraz użycie metody installEventFilter. Oto przykład:

#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); this->setMouseTracking(true); // włączam śledzenie myszy dla głównego okna programu ui->centralWidget->setMouseTracking(true); // włączam śledzenie myszy dla centralWidget ui->centralWidget->installEventFilter(this); // tutaj podpinam główne okno pod zdarzenia kontrolki centralWidget ui->mainToolBar->installEventFilter(this); // tutaj podpinam główne okno pod zdarzenia kontrolki mainToolBar ui->mainToolBar->setMouseTracking(true); // włączam śledzenie myszy dla mainToolBar } MainWindow::~MainWindow() { delete ui; } void MainWindow::mouseMoveEvent(QMouseEvent *event){ QMainWindow::mouseMoveEvent(event); qDebug() << event->pos(); // wyświetlam położenie myszki w oknie głównym programu } bool MainWindow::eventFilter(QObject *watched, QEvent *event){ if(event->type() == QEvent::MouseMove){ // gdy mam do czynienia z zdarzeniem ruchu myszki qDebug() << "Przechwyciłem zdarzenie dla ruchu myszy"; return false; // zwracam false bo chcę jeszcze wywołać komunikat mouseMoveEvent z klasy MainWindow } return QMainWindow::eventFilter(watched, event); // zwracam to co funkcja filtrująca z klasy bazowej zwróci }

Wysyłanie zdarzeń

Zapewne zastanawiasz się jak zdarzenia są wywoływane? Wiele zdarzeń zaimplementowanych w kontrolkach pochodzi od systemu. Zdarzenia związane z ruchem myszki, czy zmianą rozmiaru okna należą do tej właśnie kategorii zdarzeń. Można oczywiście utworzyć swoją własną klasę dziedziczącą po klasie QEdit i utworzyć własną metodę przechwytującą zdarzenie związane z taką klasą. Nie będę omawiał jak utworzyć taką klasę i metodę bo zdaje się to oczywiste, co jest mniej oczywiste to to, jak takie zdarzenie wywołać? Odpowiedzią na to pytanie są dwie metody QApplication::sendEvent lub QApplication::postEvent. Pierwsza metoda powoduje natychmiastowe wywołanie metody przechwytującej zdarzenie, druga wysyła zdarzenie, które trafia do pętli komunikatów i co jest bardzo ważne po odebraniu obiekt zdarzenia jest niszczony co oznacza, że obiekt klasy zdarzenia musi być utworzony w sposób dynamiczny a nie statyczny. Oto przykład użycia metody QApplication::sendEvent w konstruktorze klasy MainWindow:

QMouseEvent event(QEvent::MouseMove, QPointF(100, 100), Qt::NoButton, 0, 0); QApplication::sendEvent(this, &event);

Powyższy kawałek kodu wywoła metodę przechwytującą zdarzenie ruchu myszki, czyli mouseMoveEvent, symulując niejako ruch myszki do punktu o współrzędnych x = 100; y = 100.

Podobny efekt można uzyskać za pomocą takiego kodu:

auto *eventPost = new QMouseEvent(QEvent::MouseMove, QPointF(200, 200), Qt::NoButton, 0, 0); QApplication::postEvent(this, eventPost);
Strony powiązane
strony powiązane
  1. doc.qt.io/archives/qt-4.8/eventsandfilters.html - opis zagadnień związanych z zdarzeniami i filtrowaniem zdarzeń na stronie dokumentacji Qt
  2. doc.qt.io/qt-5/qevent.html - opis klasy QEvent na stronie dokumentacji Qt
  3. doc.qt.io/archives/qt-4.8/qcoreapplication.html#sendEvent - opis metody QApplication::sendEvent na stronie dokumentacji Qt
  4. doc.qt.io/archives/qt-4.8/qcoreapplication.html#postEvent - opis metody QApplication::postEvent na stronie dokumentacji Qt
Layout wykonany przez autora strony, wszelkie prawa zastrzeżone. Jakiekolwiek użycie części lub całości grafik znajdujących się na tej stronie bez pisemnej zgody jej autora surowo zabronione.