PyQt - Ereignisprogrammierung mit QEvent

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

Hallo,

Ich moechte gerne ein Ereignis programmieren und dazu QEvent Klasse benutzen.
Ich habe die Dokumentation unter
http://www.riverbankcomputing.co.uk/sta ... event.html
rauf und runter gelesen.
Leider ist mir nicht klar, wie ich diese Klasse einbinde.
Kann mir jemand ein codschnipsel zeigen, damit ich ungefair weiss wie ich diese Klasse mir zugaenglich mache und wo ich dann diese Routine hinschreibe.

Danke im Voraus

Wolf
lunar

Beschreibe doch mal das Ziel und nicht den Weg.

Wozu benötigst du eine QEvent-Klasse bzw. warum nutzt du nicht einfache Signale? Zwar ist es möglich, eigene Ereignisse zu implementieren, per "QApplication.postEvent()" in die Hauptschleife einzureihen, und im Empfänger mittels "QObject.customEvent()" zu behandeln, nur ist unüblich. Immerhin ist das nur kompliziert geschrieben, was Signale und Slots so können.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben:Beschreibe doch mal das Ziel und nicht den Weg.

Wozu benötigst du eine QEvent-Klasse bzw. warum nutzt du nicht einfache Signale? Zwar ist es möglich, eigene Ereignisse zu implementieren, per "QApplication.postEvent()" in die Hauptschleife einzureihen, und im Empfänger mittels "QObject.customEvent()" zu behandeln, nur ist unüblich. Immerhin ist das nur kompliziert geschrieben, was Signale und Slots so können.
Hallo Lunar,

ganz einfach, weil es kein Signal gibt das "gotFocus" ausgibt. Die Signale, die ich beim Qt-Designer und auch in diversen Dokus finde sind durchaus ueberschaubar. "GotFocus" ist nicht dabei. Und das z.B. brauch ich.

Also wenn ich per TAB-Taste von einem Listenfeld in ein Textfeld wechsle, bekommt normalerweise das Textfeld den Focus, was ein Ereignis ausloest. Und genau dieses Ereignis muss ich abfangen oder
als zweites Beispiel: Wenn der Cursor bereits im Textfeld ist, dann hat das Textfeld den Focus. Aber .hasFocus() funktioniert nur, wenn etwas im Textfeld passiert und nicht wenn der Cursor nur drin sitzt aber bereits den Focus hat.


Wolf
lunar

Wenn du am Focus interessiert bist, dann musst du von QLineEdit ableiten und .focusEvent() überschreiben. Aber wozu benötigst du den Focus?
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben:Wenn du am Focus interessiert bist, dann musst du von QLineEdit ableiten und .focusEvent() überschreiben. Aber wozu benötigst du den Focus?
Hallo Lunar,

Ich habe einen Dialog mit zwei Textfeldern. Beide mehrzeilig, LineEdit mir nuetzt nichts.
Dann habe ich eine Liste mit Abkuerzungen, die ich aufrufe, eine Abkuerzung auswaehle und diese ausgewaehlte Abkuerzung soll dann an der Cursorposition eingefuegt werden. Das klappt (das Einfuegen), nur muss ich entscheiden in welchem der beiden Textfenster der Cursor hockt, also ich gerade editiere und da soll dann auch meine gewaehlte Abkuerzung eingefuegt werden. Also in Abhaengigkeit des Focus. ..denke ich. Denn so ist es im VisualBasic und auch im OpenOffice. OK PyQt ist nicht Basic. 8)

Wolf
lunar

Ich werde aus deiner Beschreibung nicht so ganz schlau ;) Meinst du vielleicht sowas?

Wenn ich falsch liege, dann paste doch mal die UI Datei im NoPaste-Service oder lade einen Screenshot der UI-Datei hoch (aber bitte nicht auf imageshack.us ;) ).
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben:Ich werde aus deiner Beschreibung nicht so ganz schlau ;) Meinst du vielleicht sowas?

Wenn ich falsch liege, dann paste doch mal die UI Datei im NoPaste-Service oder lade einen Screenshot der UI-Datei hoch (aber bitte nicht auf imageshack.us ;) ).
Erst mal vielen Dank fuer den Link.
Das muss ich erst noch testen.

Aber das Problem ist doch einfach.
Ich habe in einem Dialog 2 Textfelder und ein paar Buttons.
Nun ist der Cursor in Textfeld1 und blinkt da vor sich hin.
Klicke ich auf Button1 erscheint eine Liste mit sagen wir mal 10 Eintraegen.
Ich waehle einen Eintrag aus und dann soll der Eintrag an der Cursorposition eingefuegt werden.
Das ist einfach, wenn es nur ein Textfeld gaebe, in dem das passieren soll.
Aber die gleiche Liste kann und will ich auch aufrufen, wenn ich in Textfeld2 den Cursor sitzen habe.
Nun muss der gewaehlte Eintrag aber an der Cursorposition in Textfeld2 eingetragen werden.
Mal ein Pseudocode:

Code: Alles auswählen

   def onListe(self):
      Eintrag = " "
      Eintrag = dlgListe.ListeAufruf(GlobalVar) #..Dialog "Liste" aufrufen
      if Eintrag <> "":  # .....................wurde etwas gewaehlt
         if Textfeld1.aktive == True: # merke: .aktive ist meine Erfindung, da ich noch keine Loesung habe
             cursor=self.Textfeld1.textCursor() # gewaehlten Eintrag in Textfeld1 eintragen wenn Cursor hier drin sitzt.
             cursor.insertText(Eintrag)
         elseif Textfeld2.aktive == True:
             cursor=self.Textfeld2.textCursor() # sonst hier eintragen, wenn Cursor hier sitzt.
             cursor.insertText(Eintrag)        
         
So etwas brauche ich.

Danke fuer Deine Muehe.

Wolf
lunar

Dafür benötigst du weder ein Signal noch ein Ereignis, denn du willst ja nicht auf eine Fokusänderung reagieren, sondern vielmehr nur zu einem bestimmten Zeitpunkt herausfinden, welches Widget den Focus hat. Genau das tut das gepostete Snippet, nur nutzt es keinen Button, sondern eine Aktion in der Werkzeugleiste.

Toolbar-Buttons akzeptieren keinen Fokus, daher kommt man in diesem Fall einfach per "QApplication.focusWidget()" an das entsprechende Edit-Widget heran. Für einen normalen QPushButton ist ein kleiner Trick erforderlich, da ein solches Widget den Fokus übernehmen kann, so dass "QApplication.focusWidget()" im Slot immer auf den Button selbst zeigt. Allerdings kann man einfach "QPushButton.setFocusPolicy(Qt.NoFocus)" aufrufen, dann akzeptiert der Button niemals den Fokus (Beispiel).

Allerdings kann man den Button so auch nicht mit der Tastatur markieren. Die Alternative wäre daher, das Signal "QApplication.focusChanged()" zu behandeln, dass immer dann ausgelöst wird, wenn der Focus sich ändert. Im entsprechenden Slot könnte man sich dann das zuletzt fokussierte Edit-Widget merken. Bei Bedarf kann ich dir gerne auch dafür ein Beispiel posten.

Ein Wort zum Schluss noch: Ich persönlich halte deine Vorgehensweise nicht für sinnvoll. Ein Button, der auf magische Weise vom Fokus abhängt, kann mitunter zu für den Benutzer unerwarteten Verhalten führen. Imho wäre es besser, für jedes Edit-Widget eine separate Aktion zu erzeugen, und diese in das Kontext-Menü des Widgets aufzunehmen. Dann gibt es keine Missverständnisse. Zwecks Komfort kann man ein Tastenkürzel vergeben. Bei einem solchen erwartet der Benutzer keine Änderung des Fokus, so dass es keine Überraschungen gibt. Bei einem Button aber, der mit der Maus aktiviert wird, geht der Zusammenhang zum Edit-Widget verloren. Just my 2 cents, letztlich ist das natürlich deine Entscheidung.
Zuletzt geändert von lunar am Freitag 13. März 2009, 17:08, insgesamt 1-mal geändert.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben: Toolbar-Buttons akzeptieren keinen Fokus, daher kommt man in diesem Fall einfach per "QApplication.focusWidget()" an das entsprechende Edit-Widget heran. Für einen normalen QPushButton...Button so auch nicht mit der Tastatur markieren. Die Alternative wäre daher, das Signal "QApplication.focusChanged()" zu behandeln, dass immer dann ausgelöst wird, wenn der Focus sich ändert. Im entsprechenden Slot könnte man sich dann das zuletzt fokussierte Edit-Widget merken. Bei Bedarf kann ich dir gerne auch dafür ein Beispiel posten.
Hallo,
Vielleicht hast Du da was missverstanden. Es geht nicht um Buttons. Ich will nur herausfinden, wo der Cursor sitzt, in Textfeld1 oder 2.
Da ich auf einen Button clicke, muesste ich mir also das verlassen des Focus aus dem Textfeld zum Button abfangen um mir zu merken, wo der Cursor vor dem Ausloesen des Buttons war.
Es geht hier um die Textfelder!!

Wolf
lunar

xWolf hat geschrieben:Vielleicht hast Du da was missverstanden. Es geht nicht um Buttons. Ich will nur herausfinden, wo der Cursor sitzt, in Textfeld1 oder 2.
Da ich auf einen Button clicke, muesste ich mir also das verlassen des Focus aus dem Textfeld zum Button abfangen um mir zu merken, wo der Cursor vor dem Ausloesen des Buttons war.
Doch, es geht hier um den Button, denn du benötigst die Kenntnis des fokussierten Textfelds allein im Slot, der auf den Klick auf den Button reagiert, und nicht als globalen Zustand innerhalb des Fensters. Deswegen sollte nicht von Interesse sein, wie du das Verlieren des Fokus erkennst, sondern wie du im Button das fokussierte Text-Feld erkennst.

Im Übrigen habe ich dir auch erklärt, mit welchem Signal du einen Fokuswechsel erkennen kannst. Ich wäre dir dankbar, wenn du meine Postings lesen und meine Beispiel auch ausprobieren würdest, bevor du mir antwortest. Wenn ich dich richtig verstanden habe, tun meine Beispiele nämlich schon, was du erreichen möchtest. Andernfalls wird die Sache für mich irgendwie ziemlich witzlos.

Beachte auch meine Edit im letzten Postings, bzw. das "Wort zum Schluss". Ich halte deinen Ansatz nicht für sinnvoll, und würde die Anforderung anders umsetzen.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben:
xWolf hat geschrieben:
Beachte auch meine Edit im letzten Postings, bzw. das "Wort zum Schluss". Ich halte deinen Ansatz nicht für sinnvoll, und würde die Anforderung anders umsetzen.
Sorry, wenn es unangenehm war.
Den Satz zum Schluss ich. Ich habe bereits die Tastenkuerzel eingesetzt, kann man bequem und ohne Schreiberei im Qt-Designer erledigen.

Wolf
lunar

Hast du den jetzt eine Lösung bzw. funktioniert es jetzt?
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben:Hast du den jetzt eine Lösung bzw. funktioniert es jetzt?
Hallo,

Also nach ein bischen Bastelei (QPlainTextEdit gibt es bei mir nicht sondern nur QTextEdit - warum auch immer) habe ich Dein Beispiel zum laufen gebracht.
Jetzt muss ich erst mal durchblicken wie Du das gemacht hast. Es ist aber genau so wie ich es mir vorstelle.
Danke erstmal.

Wolf
lunar

xWolf hat geschrieben:Also nach ein bischen Bastelei (QPlainTextEdit gibt es bei mir nicht sondern nur QTextEdit - warum auch immer) habe ich Dein Beispiel zum laufen gebracht.
QPlainTextEdit gibt es erst seit Qt 4.4.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben:
xWolf hat geschrieben:Also nach ein bischen Bastelei (QPlainTextEdit gibt es bei mir nicht sondern nur QTextEdit - warum auch immer) habe ich Dein Beispiel zum laufen gebracht.
QPlainTextEdit gibt es erst seit Qt 4.4.
OK, das macht aber erstmal nichts.
Ich konnte nun die Loesung bei mir einbauen.

Code: Alles auswählen

   def onKuerzelWahl(self):
      focus_widget = QtGui.QApplication.focusWidget()
      if isinstance(focus_widget, QtGui.QTextEdit):
         Kuerzel = " "
         Kuerzel = prgKuerzel.KuerzelAufruf(GlobalVar)
         if Kuerzel <> "":
            Kuerzel = "("+Kuerzel+")" # Kuerzel in Klammern setzen
            focus_widget.insertPlainText(Kuerzel)
Das lauft jetzt hervorragend. Damit ist nun auch unterbunden, dass ich die Kuerzelliste aufrufe, wenn der Focus nicht in einem Textfeld sitzt.
Da ich meine Dialoge nicht per Schreiberei erstelle, sondern mit dem Qt-Designer musste ich immer noch QtGui. voranstellen.

Ok, danke Dir. Meine Begriffsstutzigkeit bitte ich zu entschuldigen. Ich stand mittem Im Wald und habe nach Holz gesucht.

Wolf
lunar

xWolf hat geschrieben:Da ich meine Dialoge nicht per Schreiberei erstelle, sondern mit dem Qt-Designer musste ich immer noch QtGui. voranstellen.
Huch? Editierst du etwa direkt die per pyuic generierten Quellcode-Dateien?

Das sollte man nicht tun. Man sollte sogar pyuic im Allgemeinen meiden. Benutze lieber das "uic"-Modul, und erzeuge in einem separaten Modul eine Instanz der Benutzeroberfläche per "uic.loadUi":

Code: Alles auswählen

from PyQt4 import ui
from PyQt4.QtGui import QMainWindow

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.ui = loadUi('/path/to/my/file.ui')
Anschließend kannst du auf die Attribute der Benutzeroberfläche über "self.ui" zugreifen, z.B. so (angenommen, du hast im Designer ein Label namens "my_label" erzeugt):

Code: Alles auswählen

self.ui.my_label.setText('Spam with eggs, please!')
In einem eigenen Modul kannst du PyQt4 dann so importieren, wie du lustig bist, nur solltest du dabei explizite Imports anwenden, sprich keine *-Imports wie in meinem Beispiel. Ich nutze normalerweise auch explizite Imports, im Beispiel wollte ich aber Zeit sparen.
Ok,Meine Begriffsstutzigkeit bitte ich zu entschuldigen.
Nichts für ungut, ich hab auch etwas überreagiert ;)
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

lunar hat geschrieben: Huch? Editierst du etwa direkt die per pyuic generierten Quellcode-Dateien?
Auf keinen Fall, da ja alle Aenderungen verloren gehen sobald ich wieder mit Qt-Design arbeite.
Ich speichere die dialog.ui (aus Qt-Design) und dann uebersetzte ich mittels

Code: Alles auswählen

pyuic4 -o dialog.py dialog.ui
Das wars.

Aber warum pyuic meiden?

Wolf
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

xWolf hat geschrieben:Aber warum pyuic meiden?
Weil Codegenerierung unpraktisch ist. Man muss sich erinnern ihn immer neu zu generieren, man muss zwei Dateien statt einer rumschleppen, der Stil des Codes ist nicht unbedingt der, den man selbst nutzt, man (oder auch andere Contributors) wird nicht verleitet im Quellcode rumzueditieren...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

xWolf hat geschrieben:
lunar hat geschrieben:Huch? Editierst du etwa direkt die per pyuic generierten Quellcode-Dateien?
Auf keinen Fall, da ja alle Aenderungen verloren gehen sobald ich wieder mit Qt-Design arbeite.
Dann kannst du PyQt4 doch importieren, wie du willst, und bist nicht unbedingt an "from PyQt4 import QtGui" gebunden!
Aber warum pyuic meiden?
Leonidas hat gute Gründe genannt. Dazu kommt noch, dass der erzeugte Code nicht der beste ist, und innerhalb von Paketen mitunter Probleme bereitet.

Bei der Verwendung von pyuic ist es mir früher (noch unter Qt3) oft passiert, dass ich lange nach einem Fehler gesucht habe, der – wie sich dann herausstellte – nur daher rührte, dass ich zwar die UI-Datei im Designer bearbeitet, nicht aber den generierten Code neu erzeugt hatte. Sowas vermeidet man, wenn man sich nicht von der Code-Generierung abhängig macht.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

OK, ihr habt recht.

Wolf
Antworten