QT events and signal / slots

W świecie Qt, jaka jest różnica między zdarzeniami a sygnałem / slotami?

Czy jedno zastępuje drugie? Czy zdarzenia są abstrakcją sygnału / slotów?

 76
Author: Peter Mortensen, 2010-09-25

9 answers

Dokumentacja Qt prawdopodobnie najlepiej to wyjaśnia:

W Qt zdarzenia są obiektami, pochodnymi z abstrakcyjnej klasy QEvent, że reprezentować rzeczy, które się wydarzyły w ramach wniosku lub jako wynik działań zewnętrznych, które aplikacja musi wiedzieć o. Wydarzenia mogą być odbierane i obsługiwane przez każda instancja podklasy QObject, ale są one szczególnie istotne dla widgety. Niniejszy dokument opisuje jak wydarzenia są dostarczane i obsługiwane w typowe zastosowanie.

Więc zdarzenia i sygnały/sloty są dwoma równoległymi mechanizmami realizującymi te same rzeczy. Ogólnie rzecz biorąc, zdarzenie zostanie wygenerowane przez obiekt zewnętrzny (na przykład koło klawiatury lub myszy) i będzie dostarczane przez pętlę zdarzeń w aplikacji QApplication. Ogólnie rzecz biorąc, jeśli nie skonfigurujesz kodu, nie będziesz generował zdarzeń. Możesz filtrować je przez QObject::installEventFilter() lub obsługiwać zdarzenia w podklasowanym obiekcie, nadpisując odpowiednie funkcje.

Sygnały i gniazda są znacznie łatwiejsze do wygenerowania i odebrania i można podłączyć dowolne dwie podklasy QObject. Są one obsługiwane przez Metaclass (spójrz na swoją moc_classname.plik cpp więcej), ale większość komunikacji międzyklasowej, którą będziesz produkować, będzie prawdopodobnie używać sygnałów i slotów. Sygnały mogą być dostarczane natychmiast lub odroczone za pośrednictwem kolejki (jeśli używasz wątków).

Można wygenerować sygnał.

 25
Author: Harald Scheirich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-24 03:08:39

W Qt sygnały i zdarzenia są implementacjami wzorca obserwatora. Są one wykorzystywane w różnych sytuacjach, ponieważ mają różne mocne i słabe strony.

Po pierwsze zdefiniujmy dokładnie to, co rozumiemy przez 'Qt event': wirtualną funkcję w klasie Qt, którą oczekujemy, że zaimplementujesz w swojej klasie bazowej, jeśli chcesz obsłużyć to zdarzenie. Jest to związane z wzorcem metody szablonowej .

Zauważ jak użyłem słowa "uchwyt ". W rzeczywistości, oto podstawowa różnica między intencją sygnałów i zdarzeń:

  • You " handle " events
  • You " get notificated of " signal emissions

Różnica polega na tym, że kiedy "zajmujesz się" wydarzeniem, bierzesz na siebie odpowiedzialność za "reagowanie" zachowaniem, które jest przydatne poza klasą. Na przykład rozważ aplikację, która ma przycisk z numerem. Aplikacja musi pozwolić użytkownikowi skupić przycisk i zmień liczbę, naciskając klawisze " up " I "down". W przeciwnym razie przycisk powinien działać jak zwykły QPushButton (można go kliknąć, itd.). W Qt odbywa się to poprzez utworzenie własnego małego "komponentu" wielokrotnego użytku (podklasa QPushButton), który ponownie implementuje metodę QWidget::keyPressEvent. Pseudocode:

class NumericButton extends QPushButton
    private void addToNumber(int value):
        // ...

    reimplement base.keyPressEvent(QKeyEvent event):
        if(event.key == up)
            this.addToNumber(1)
        else if(event.key == down)
            this.addToNumber(-1)
        else
            base.keyPressEvent(event)
Widzisz? Ten kod przedstawia nową abstrakcję: widżet, który działa jak przycisk, ale z pewną dodatkową funkcjonalnością. Dodaliśmy tę funkcjonalność bardzo wygodnie:

Projekt Qt jest dobrze przemyślany - sprawili, że wpadliśmy w otchłań sukcesu , ułatwiając zrobienie dobrej rzeczy i utrudniając zrobienie złej rzeczy (czyniąc keyPressEvent wydarzeniem).

Z drugiej strony, rozważ najprostsze użycie QPushButton - po prostu inicjowanie go i otrzymywanie powiadomień po kliknięciu :

button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())

To ma być zrobione przez użytkownika klasy:

  • gdybyśmy musieli podklasa QPushButton za każdym razem, gdy chcemy, aby jakiś przycisk powiadamiał nas o kliknięciu, wymagałoby to wielu podklas bez powodu! widżet, który zawsze pokazuje messagebox "Hello world" po kliknięciu, jest przydatny tylko w jednym przypadku - więc nie nadaje się do wielokrotnego użytku. Ponownie, nie mamy wyboru, jak tylko zrobić właściwą rzecz-łącząc się z nią zewnętrznie.
  • możemy chcieć podłączyć kilka slotów do clicked() - lub podłączyć kilka sygnałów do sayHello(). Z sygnałami nie ma zamieszania. Z podklasowanie będziesz musiał usiąść i zastanowić się nad diagramami klas, dopóki nie zdecydujesz się na odpowiedni projekt.

Zauważ, że jedno z miejsc emitowanych przez QPushButton {[2] } znajduje się w jego implementacji mousePressEvent(). To nie znaczy, że clicked() i mousePressEvent() są wymienne-tylko, że są ze sobą powiązane.

Więc sygnały i wydarzenia mają różne cele (ale są powiązane w tym, że oba pozwalają "subskrybować" powiadomienie o czymś się dzieje).

 128
Author: Stefan Monov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-05 17:47:14

Jak na razie nie podobają mi się odpowiedzi. - Pozwól, że skoncentruję się na tej części Pytania:

Czy zdarzenia są abstrakcją sygnału / slotów?

Krótka odpowiedź: Nie. długa odpowiedź rodzi "lepsze" pytanie: jak są powiązane sygnały i wydarzenia?

Bezczynna pętla główna (na przykład Qt) jest zwykle "zablokowana" w wywołaniu select () systemu operacyjnego. To wywołanie sprawia, że aplikacja "uśpi", podczas gdy przekazuje kilka gniazd lub plików lub cokolwiek do kernel asking for: jeśli coś się na nich zmieni, pozwól zwracać wywołanie select (). - A jądro, jako Pan świata, wie, kiedy to się stanie.

Wynikiem tego wywołania select() może być: nowe dane na gnieździe podłączyć do X11, pakiet do portu UDP, na którym nas słuchamy, itd. - to coś nie jest ani sygnałem Qt, ani zdarzeniem Qt, a główna pętla Qt sama decyduje, czy zamienia świeże dane w jedno, drugie, czy je ignoruje.

Qt może wywołać metodę (lub kilka) jak keyPressEvent(), skutecznie zamieniając ją w Zdarzenie Qt. Lub Qt emituje sygnał, który w efekcie wyszukuje wszystkie funkcje zarejestrowane dla tego sygnału i wywołuje je jedna po drugiej.

Jedna różnica tych dwóch pojęć jest widoczna tutaj: slot nie ma głosowania na to, czy inne sloty zarejestrowane na ten sygnał zostaną wywołane, czy nie. - Zdarzenia są bardziej jak łańcuch, a obsługa zdarzeń decyduje, czy przerywa ten łańcuch, czy nie. Sygnały wyglądają jak gwiazda lub drzewo w tym szacunek.

Zdarzenie może wyzwalać lub być całkowicie zamienione w sygnał (po prostu emituj jeden i nie wywołaj "super()"). Sygnał może być zamieniony w Zdarzenie (wywołanie obsługi zdarzenia).

Co abstrakuje co zależy od przypadku: clicked () - signal abstrakuje zdarzenia myszy(przycisk przechodzi w dół i w górę bez zbytniego poruszania się). Zdarzenia klawiatury są abstrakcjami z niższych poziomów (rzeczy takie jak 果 lub é to kilka uderzeń klawiszy w moim systemie).

Może focusinevent () jest przykład przeciwny: mógłby użyć (a więc abstrakcyjnego) sygnału klikniętego (), ale nie wiem, czy rzeczywiście tak jest.

 36
Author: Robert Siemer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-21 18:35:15

Zdarzenia są wywoływane przez pętlę zdarzeń. Każdy program GUI potrzebuje pętli zdarzeń, niezależnie od tego, co napiszesz w systemie Windows lub Linux, używając Qt, Win32 lub innej biblioteki GUI. Każdy wątek ma również własną pętlę zdarzeń. W Qt "pętla zdarzeń GUI" (która jest główną pętlą wszystkich aplikacji Qt) jest ukryta, ale uruchamiasz ją wywołując:

QApplication a(argc, argv);
return a.exec();

Wiadomości system operacyjny i inne aplikacje wysyłane do programu są wysyłane jako zdarzenia.

Sygnały i sloty są mechanizmami Qt. W procesie kompilacji używając moc (meta-object compiler), są one zmieniane na funkcje zwrotne.

Event powinien mieć jeden odbiornik, który powinien go wysłać. Nikt inny nie powinien mieć tego wydarzenia.

Wszystkie sloty podłączone do emitowanego sygnału zostaną wykonane.

Nie powinieneś myśleć o sygnałach jako o zdarzeniach, ponieważ jak możesz przeczytać w dokumentacji Qt:

Kiedy sygnał jest emitowany, gniazda podłączone do niego są zwykle wykonywane natychmiast, tak jak normalne wywołanie funkcji. Kiedy dzieje się tak, sygnały i mechanizm slotów jest całkowicie niezależny dowolnej pętli zdarzeń GUI.

Gdy wysyłasz zdarzenie, musi ono poczekać jakiś czas, aż pętla zdarzeń wyśle wszystkie zdarzenia, które przyszły wcześniej. Z tego powodu wykonanie kodu po wysłaniu zdarzenia lub sygnału jest inne. Kod po wysłaniu zdarzenia zostanie uruchomiony natychmiast. Z mechanizmami sygnałów i gniazd zależy to od rodzaju połączenia. Normalnie będzie on wykonywany po wszystkich slotach. Za pomocą Qt:: QueuedConnection, zostanie wykonane natychmiast, tak jak events. Sprawdź Wszystkie typy połączeń w dokumentacji Qt .

 13
Author: firescreamer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-18 16:00:43

Jest artykuł, który omawia przetwarzanie zdarzeń w jakiś sposób: http://www.packtpub.com/article/events-and-signals

Omawia różnicę między zdarzeniami a sygnałami tutaj:

Zdarzenia i sygnały są dwoma równoległymi mechanizmami stosowanymi do to samo. Jako ogólną różnicę, sygnały są przydatne podczas korzystania z widget, natomiast zdarzenia są przydatne przy implementacji widgetu. Na przykład, gdy używamy widżetu takiego jak QPushButton, are more zainteresowany sygnałem kliknięcia () niż w niskopoziomowym naciśnięciu myszy lub naciśnięcia klawiszy, które spowodowały emisję sygnału. Ale jeśli wdrażają klasę QPushButton, bardziej interesuje nas implementacja kodu dla zdarzeń myszy i klawiszy. Ponadto, zwykle obsługuj zdarzenia, ale Otrzymuj powiadomienia o emisji sygnału.

Wydaje się, że jest to powszechny sposób mówienia o tym, ponieważ przyjęta odpowiedź używa niektórych z tych samych zwrotów.


Uwaga, proszę zobacz pomocne komentarze poniżej na temat tej odpowiedzi od Kuby Obera, które sprawiają, że zastanawiam się, czy to może być trochę uproszczone.

 6
Author: neuronet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-13 16:52:16

TL; DR: sygnały i sloty to pośrednie wywołania metody. Zdarzenia są strukturami danych. Więc są to zupełnie różne zwierzęta.

Jedyny raz, kiedy łączą się ze sobą, to gdy połączenia wrzutowe są wykonywane poza granicami wątku. Argumenty wywołania gniazda są pakowane w strukturę danych i wysyłane jako zdarzenie do kolejki zdarzeń wątku odbierającego. W wątku odbiorczym metoda QObject::event rozpakowuje argumenty, wykonuje wywołanie i ewentualnie zwraca wynik, jeśli było to blokowanie połączenie.

Jeśli jesteśmy gotowi uogólnić do zapomnienia, można myśleć o zdarzeniach jako o sposobie przywołania metody event obiektu docelowego. To jest pośrednie wywołanie metody, po moda-ale nie sądzę, że jest to pomocny sposób myślenia o tym, nawet jeśli jest to prawdziwe stwierdzenie.

 4
Author: Kuba Ober,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-13 14:20:41

Zdarzenia (w ogólnym sensie interakcji użytkownika/sieci) są zazwyczaj obsługiwane w Qt z sygnałami / slotami, ale sygnały / sloty mogą robić wiele innych rzeczy.

QEvent i jego podklasy są w zasadzie małymi, znormalizowanymi pakietami danych dla frameworka do komunikacji z kodem. Jeśli chcesz w jakiś sposób zwrócić uwagę na mysz, wystarczy spojrzeć na API QMouseEvent, a projektanci bibliotek nie muszą odkrywać koła za każdym razem, gdy musisz dowiedzieć się, co mysz zrobiła to w jakimś rogu Qt API.

Prawdą jest, że jeśli czekasz na jakieś zdarzenia (ponownie w ogólnym przypadku), twój slot prawie na pewno zaakceptuje podklasę QEvent jako argument.

Mając to na uwadze, sygnały i sloty mogą być z pewnością używane bez QEvents, chociaż przekonasz się, że oryginalnym bodźcem do aktywacji sygnału będzie często jakaś interakcja użytkownika lub inna aktywność asynchroniczna. Czasami jednak Twój kod po prostu osiągnie punkt, w którym odpalenie określonego sygnału będzie właściwą rzeczą. Na przykład, odpalenie sygnału podłączonego do paska postępu podczas długiego procesu nie wiąże się do tego momentu z QEvent.

 3
Author: jkerian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-25 18:45:13

Kolejna drobna kwestia pragmatyczna: emitowanie lub odbieranie sygnałów wymaga dziedziczenia QObject, podczas gdy obiekt dowolnego dziedziczenia może wysyłać lub wysyłać Zdarzenie (ponieważ wywołujesz QCoreApplication.sendEvent () lub postEvent ().) Zazwyczaj nie jest to problemem, ale: aby używać sygnałów PyQt o dziwo wymaga QObject, aby była pierwszą Super klasą i możesz nie chcieć zmieniać kolejności dziedziczenia tylko po to, aby móc wysyłać sygnały.)

 1
Author: bootchk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-16 12:35:01

Moim zdaniem wydarzenia są całkowicie zbędne i można je wyrzucić. Nie ma powodu, dla którego sygnały nie mogły być zastąpione zdarzeniami lub zdarzeniami sygnałami, z wyjątkiem tego, że Qt jest już skonfigurowane tak, jak jest. Sygnały kolejki są zawijane przez zdarzenia i zdarzenia mogą być zawijane przez sygnały, na przykład:

connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});

Zastąpi funkcję convenience mouseMoveEvent () znajdującą się w QWidget (ale już nie w QQuickItem) i obsłuży sygnały mouseMove, które menedżer sceny emituje za przedmiot. Fakt, że sygnał jest emitowany w imieniu elementu przez jakąś zewnętrzną jednostkę, jest nieistotny i zdarza się dość często w świecie komponentów Qt, mimo że ma to nie być dozwolone. Ale Qt jest konglomeratem wielu różnych decyzji projektowych i w zasadzie rzuca się w wir strachu przed złamaniem starego kodu(co i tak zdarza się dość często).

 1
Author: user1095108,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-16 12:33:23