QKeyEvent: Leertaste u.a. werden nicht abgefangen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
sli92
User
Beiträge: 4
Registriert: Dienstag 5. April 2011, 19:41

Hallo,

ich bin schon langsam am verzweifeln, ich hab im Konstruktor meiner Klasse für den Dialog folgendes definiert:

Code: Alles auswählen

self.connect(self.textEdit, QtCore.SIGNAL("keyPressEvent()"), self.keyPressEvent)
Die Slot-Funktion sieht folgendermaßen aus:

Code: Alles auswählen

def keyPressEvent(self, event):
     key = event.key()
     print key
     print event.key() 
Das Problem ist, alle Tasten bis auf: Space, Pfeiltasten, Tab und vl noch andere lösen einfach nicht dieses Event aus. Ich hab lange gegoogelt und herausgefunden, dass es was mit setFocusPolicy, setFocus() und grabKeyboard() zu tun haben könnte, deshalb habe ich auch noch folgendes Codestück eingefügt in den Konstruktor:

Code: Alles auswählen

self.textEdit.setFocusPolicy(QtCore.Qt.StrongFocus)
self.textEdit.setFocus()
self.textEdit.grabKeyboard()
print QtGui.QWidget.keyboardGrabber()
Der letzte Befehl gibt mir aus, dass editText die Tastatur gefangen hat, was auch erwünscht war, aber die Leertaste und Co. funktionieren noch immer nicht.

Bitte um eure Hilfe!
lunar

Wie kommst Du darauf, dass "keyPressEvent()" ein Signal wäre?!
sli92
User
Beiträge: 4
Registriert: Dienstag 5. April 2011, 19:41

Ich beschäftige mich erst seit einer halben Woche mit qt und hab einen beispielcode im Netz gefunden der als Signal keypressevent hat. Ich hab das dann gleich in meinen Code eingebaut und siehe da es hat funktioniert. Leider aber nicht mit Space, Tab etc. Darf ich das so nicht verwenden? Wenn nein frag ich mich warum es funktioniert.
lunar

Das „funktioniert“, weil Du Deinen „Slot“ "keyPressEvent()" genannt und damit die Ereignismethode in einem anderen Steuerelement (wahrscheinlich Dein "QMainWindow" o.ä.) überschrieben hast. Diese Methode wird zwar niemals durch das (nicht existierende) Signal aufgerufen, wohl aber immer dann, wenn ein Tastaturereignis in dem Steuerelement auftritt, in dessen zugehöriger Klasse Du diesen „Slot“ implementiert hast. Deswegen erhältst Du auch nicht alle Tastaturereignisse, eben weil diese nicht aus dem "QTextEdit" kommen, sondern aus einem anderen Steuerelement.

Ich weiß nicht, wo Du diesen Ansatz gefunden hast, doch Du solltest davon absehen, weitere Beispiele von der betreffenden Seite zu übernehmen. Stattdessen empfiehlt sich die Lektüre der Dokumentation, insbesondere der Artikel The Event System und Signals & Slots, um den Unterschied zwischen Signalen und Ereignissen zu verstehen.

Diese Lektüre führt zur Einsicht, dass Du von "QTextEdit" ableiten, und in der abgeleiteten Klasse "keyPressEvent()" überschreiben musst, um Tastaturereignisse in einem Texteingabefeld vollständig abzufangen. (Beispiel, zwar nicht speziell für QTextEdit, aber das Prinzip ist allgemeiner Natur).
sli92
User
Beiträge: 4
Registriert: Dienstag 5. April 2011, 19:41

Ich hab es geschafft die QTextEdit Klasse zu überschreiben und das keyPressedEvent abzuändern. Jetzt funktionieren alle Tasten. Nun bin ich aber bei einem weiteren Problem. Ich will ja das Zeichen an die serielle Schnittstelle schicken und weiß nicht wie ich Zugriff auf die Attribute in der Klasse des Hauptdialogs erhalte, um das aktuelle Handle zu bekommen, dass beim Öffnen der Verbindung erstellt wurde. Ich bin Anfänger, also habt Erbarmen mit mir.
lunar

@sli92: „Zugriff“ auf die Attribute des „Hauptdialogs“ erhältst Du so ohne Weiteres gar nicht, das ist aber auch nicht nötig, Du benötigst ja schließlich nur die Verbindung zur seriellen Schnittstelle.

Da gibt es zwei Möglichkeiten. Die eine ist, der von QTextEdit abgeleiteten Klasse bei der Erzeugung das Verbindungsobjekt zu übergeben. Dazu musst Du ".__init__()" entsprechend überschreiben. Die andere, empfehlenswertere Methode ist, in der von "QTextEdit" abgeleiteten Klasse ein Signal zu definieren (e.g. "keyPressed()"), und dieses Signal in ".keyPressedEvent()" mit dem Zeichen als Argument auszulösen. Im „Hauptdialog“ kannst Du dieses Signal dann mit einem (zu implementierenden) Slot verbinden, der das Zeichen auf die serielle Schnittstelle schreibt.
sli92
User
Beiträge: 4
Registriert: Dienstag 5. April 2011, 19:41

Vielen Dank,

hat alles super geklappt hab die zweite Methode gewählt.
lunar

Ach ja, noch ein Nachtrag: Der Fehler wäre Dir sofort selbst aufgefallen, wenn Du die moderne Syntax für Signale und Slots verwendet hättest, also "self.textEdit.keyPressEvent.connect(self.keyPressEvent)" statt des Quelltexts im ersten Beitrag. Dann nämlich wäre ein "AttributeError" ausgelöst worden, weil die Methode ".keyPressEvent()" kein Attribut namens "connect" hat, da sie ja eben kein Signal ist. Neben diesem nicht zu unterschätzenden Vorteil ist diese neue Syntax auch um einiges lesbarer und schöner. Ihre Verwendung ist also zu empfehlen.
Antworten