Methode zu QCombobox hinzufügen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Hallo zusammen,

ich habe mal eine Frage zum Hinzufügen einer Methode zu einem Qt-Control (im speziellen Fall QComboBox). Über das Event currentTextChanged wird der 'per Hand' eingegebene Text mit den Items der Combobox verglichen. Gibt es für den eingegeben Text keine Entsprechung in der Items-Liste, wird die Textfarbe auf rotgesetzt. Hier die derzeitige Implementierung (vereinfacht) :

Code: Alles auswählen

def __init__(self):
	.
	.
	setattr(self.cbx_from, "all_items", lambda: [self.cbx_from.itemText(i) for i in range(self.cbx_from.count())])
	self.cbx_from.currentTextChanged.connect(self.on_cbx_from_text_changed)
	
def on_cbx_from_text_changed(self, current_text: str):
        # if current_text not in cbx_items:
        if current_text not in self.cbx_from.all_items():
            self.cbx_from.setStyleSheet("color: rgb(255,0,0)")
        else:
            self.cbx_from.setStyleSheet("")
Da die Funktion 'all_items' bei mehreren Comboboxen hinzugefügt werden muss, nun meine Frage :

Kann ich die Funktion 'all_items' auch einmalig der Klasse QComboBox hinzufügen, so dass sie dann bei jeder Instanz zur Verfügung steht ? Habe da noch nichts Passendes gefunden.

Vielen Dank für Eure Tipps !

Grüße
Karsten Böhme
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum benutzt Du setattr? Das ist unnötig kompliziert. Dann schreibst Du keine richtige Methode, sondern eine Lambda-Funktion, deren Namensraum der selbe ist wie von __init__. Das könnte zu seltsamem Verhalten führen.
Viel besser wäre es, die Funktionalität in `on_cbx_from_text_changed` einzubauen.

Code: Alles auswählen

    def on_cbx_from_text_changed(self, current_text):
        contains_text = any(current_text == self.cbx_from.itemText(i)
            for i in range(self.cbx_from.count()))
        style = "" if contains_text else "color: rgb(255,0,0)"
        self.cbx_from.setStyleSheet(style)
Einfacher ist es mit der fertigen Funktion findText:

Code: Alles auswählen

    def on_cbx_from_text_changed(self, current_text):
        index = self.cbx_from.findText(current_text)
        style = "" if index >= 0 else "color: rgb(255,0,0)"
        self.cbx_from.setStyleSheet(style)
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Hallo Sirius3,

ich hatte am Anfang alles in der Event-Methode. Da ich aber mehrere Boxen mit dieser Funktionalität benötige, wollte ich vermeiden, mehrfach den selben Code einzugeben. Danke für Deinen Hinweis.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man die selbe Funktionalität mehrfach braucht, definiert man einfach eine Funktion, die man mit verschiedenen Parametern aufrufen kann.
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

@Sirrius3 : das zweite Beispiel gefällt mir ausnehmend gut. Die Methode .findText bietet sich geradezu an. Danke !
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

... unabhängig von dieser Lösung interessiert mich trotzdem, ob und wie man eine Methode zu einer QComboBox-Klasse hinzufügen kann. Hat jemand eine Idee ?

Grüße
Karsten Böhme
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man eine Klasse um eine Methode erweitern will, dann definiert man eine neue Klasse und leitet diese von QComboBox ab.
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Danke, allerdings verträgt sich das nicht so richtig mit den über pyuic5.exe erzeugten Dateien. Da sollte man ja nicht drin herum schreiben.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst da auch eine eigene Klasse angeben, und eignen includes, die in Python dann Importe werden sollten.

So oder so leitet man aber sowas üblicherweise nicht ab. QT’s signal slot Mechanismus erlaubt einem, ohne Ableitung zu arbeiten. Außer du willst ein echtes Widget bauen, das sich selbst malt etc.
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

@__deets__ : Danke ! Der Mensch ist ein Gewohnheitstier. Habe viele Jahre in C# programmiert. Ich fand das immer 'schick', fremde Klassen zu erweitern. ... und nicht nur ich. Aber so geht es auch. Habe ja genug hinweise bekommen.

Grüße
Karsten
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Karsten Böhme: Falls Du mit der Anmerkung mit C# meinst zu bestehenden Klassen Methoden hinzuzufügen („extension methods“), statt von bestehenden Klassen abzuleiten, das kannst Du in Python auch machen.

Allerdings fügt man die tatsächlich der Klasse hinzu, dass heisst ”alle anderen” ”sehen” diese Methode auch. Und wenn auch andere auf die Idee kommen das zu machen, und den gleichen Namen verwenden wollen, dann kollidieren die natürlich. Weshalb das keine gute Idee ist.

Du kannst sogar zu einzelnen (Nicht-Klassen-)Objekten Methoden hinzufügen wenn Du magst. Ausgenommen die ”magischen” Methoden mit den beiden führenden und folgenden Unterstrichen, die werden immer in der Klasse gesucht. Und der Autor eines Datentyps kann dafür sorgen, dass man keine neuen Attribute auf dem Datentyp selbst und/oder Objekten davon setzen kann. Zumindest für ersteres gibt es für CPython Hacks das zu umgehen und den Typen doch neue Attribute unterzuschieben, falls man da keine Attribute setzen kann weil die in C implementiert sind: https://pypi.org/project/forbiddenfruit/

Aus der Beschreibung des Packages: „This project aims to help you reach heaven while writing tests, but it may lead you to hell if used on production code.

It basically allows you to patch built-in objects, declared in C through python.“

Letztlich kannst Du Dir zur Laufzeit beliebige Klassen und auch sonstige Objekte zusammenbauen.

Das ist aber alles ziemlich Voodoo und das macht man eher nicht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Hallo blackjack,

genauso ist es, ich meine Extensions. Und ja, die werden bereits der Klasse hinzugefügt und nicht erst der Instanz. Daher nur einmal definieren ...

Auch wenn das in Python eher nicht üblich ist, ich schaue es mir trotzdem mal an !

Gruß
Karsten
Antworten