Filterfunktion mittels QSortFilterProxyModel in ein QTableWidget

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

Hallo Forum,

ich habe per Qt Designer eine Form, die dann direkt geladen wird, mit einem QTableWidget mit mehreren Spalten erstellt, in welchem Daten aufgelistet werden und würde gerne einen Filter einfügen, um diese Daten durch Eingabe in ein QLineEdit filtern zu können.

Leider erhalte ich beim Starten der Anwendung immer folgende Fehlermeldung:
File "D:\__Sicherungsdaten\_Programmiersprachen\PycharmProjects\MovieMusicList\CodeFilesMovies\setup_gui_movies.py", line 22, in connect_actions
self.lineEdit_Jahr.textChanged.connect(self.proxy_model.setFilterFixedString)
^^^^^^^^^^^^^^^^
AttributeError: 'ListMovies' object has no attribute 'proxy_model'
Deaktiviere ich diese Zeile, funktioniert alles, allerdings ohne gewünschte Filterung.

Betroffene Funktion:

Code: Alles auswählen

def connect_actions(self):
    self.moviesTable.itemDoubleClicked.connect(self.OpenLink)  # Doppelklick-Ereignis
    self.moviesTable.setEditTriggers(QAbstractItemView.NoEditTriggers)  # Tabelle nicht editierbar

    self.lineEdit_Titel.textChanged.connect(partial(self.sort, 1))
    self.lineEdit_Jahr.textChanged.connect(self.proxy_model.setFilterFixedString)
Sonstiger Code:

Code: Alles auswählen

class ListMovies(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        uic.loadUi(r"GUI\GUI_Movies.ui", self)

        sup.connect_actions(self)
        sup.filterboxes(self)

        self.progressBar.hide()

        ui_width = self.width()
        ui_height = self.height()

        xy = center_window(self, ui_width, ui_height)
        self.move(int(xy[0]), int(xy[1]))

        self.show()

        self.showdialogNeuEinlesen()

    def closeEvent(self, event):
        try:
            cf.save_csv(self, r"doks\movies.csv")
        except Exception as e:
            print(e)

    def sort(self, col):
        print(col)

    def column_from_label(self, label):
        model = self.moviesTable.horizontalHeader().model()

        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setFilterKeyColumn(-1)  # Search all columns.
        self.proxy_model.setSourceModel(model)

        self.proxy_model.sort(0, Qt.AscendingOrder)

        model.setModel(self.proxy_model)

        for column in range(model.columnCount()):
            if model.headerData(column, QtCore.Qt.Horizontal) == label:
                return column
        return -1

    def format_table_widget(self):
        self.moviesTable.resizeColumnsToContents()
        self.moviesTable.resizeRowsToContents()

        # self.moviesTable.sortItems(0)  # teilweise fehlende Infos dadurch ???


if __name__ == '__main__':
    app = QtWidgets.QApplication([])

    window = ListMovies()

    sys.exit(app.exec_())
Was mache ich falsch bzw. wo muss dieser Code zur Implementierung der Filterfunktion hin?

Viele Grüße aus Süd-BW
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

`proxy_model` existiert offensichtlich nicht, und aus den Codefragmenten kann man das nur bestätigen. Es gibt ein `proxy_model` in `column_from_label`, aber das wird ja nirgends benutzt.
Alle Attribute sollten, zumindest mit None, in __init__ definiert werden.
Relative Pfade sollten in Programmen nicht vorkommen, weil ja nicht definiert ist, was das aktuelle Arbeitsverzeichnis ist. Normalerweise will man Pfade zu ui-Dateien relativ zu __file__ angeben.
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

Eigentlich wird das doch mittels »self.lineEdit_Jahr.textChanged.connect(self.proxy_model.setFilterFixedString)« benutzt. Oder nicht?
Falls nicht, wie muss das sonst eingebunden werden?

Welche Attribute meinst Du?
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es wird benutz. Aber es existiert nicht, also kracht es. Es muss eben vorher angelegt werden. Also kann der Code, der das getan hat, noch nicht gelaufen sein.
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

__deets__ hat geschrieben: Samstag 9. März 2024, 13:57 Es wird benutz. Aber es existiert nicht, also kracht es. Es muss eben vorher angelegt werden. Also kann der Code, der das getan hat, noch nicht gelaufen sein.
Wo muss es denn angelegt werden?
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@KlaRo: Bevor es benutzt werden kann. 😇
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

__blackjack__ hat geschrieben: Samstag 9. März 2024, 14:31 @KlaRo: Bevor es benutzt werden kann. 😇
Was heißt das genau?
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

Kann / will mir denn keiner mitteilen, wo genau und wie das im Code oben angelegt werden muss, dass es funktioniert?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Du mußt Dir doch irgendetwas gedacht haben, das so zu schreiben.
Man fügt doch nicht irgendwo ein `proxy_model` ein, ohne zu wissen, warum.
Und dann sollte es doch trivial sein, das proxy_model schon in __init__ zu erzeugen.
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

Sirius3 hat geschrieben: Samstag 9. März 2024, 16:47 Du mußt Dir doch irgendetwas gedacht haben, das so zu schreiben.
Man fügt doch nicht irgendwo ein `proxy_model` ein, ohne zu wissen, warum.
Und dann sollte es doch trivial sein, das proxy_model schon in __init__ zu erzeugen.
Auch im __init__ habe ich es schon versucht → funktioniert leider ebenfalls nicht
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

@KlaRo: Leider ist meine Glaskugel heute beschlagen, deshalb kann ich den Code, mit dem du das versucht hast, nicht so richtig erkennen.
Denn wenn du das korrekt in __init__ anlegst und die identische Fehlermeldung bekommst, wäre das schon sehr außergewöhnlich. Ich wäre sogar geneigt zu sagen, das wäre unmöglich.

Oder um es mit deinen Worten zu sagen:
Kannst / willst du uns denn nicht zeigen, was du versucht hast? Und das mit der passenden Fehlermeldung?
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

Ich habe nur gesagt, dass es nicht funktioniert. Von gleicher Fehlermeldung war nie die Rede ;)

Wenn ich das z.B. so
def __init__(self):
super().__init__()

uic.loadUi(fr"{Path(__file__).parent}\GUI\GUI_Movies.ui", self)

self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setFilterKeyColumn(-1) # Search all columns.
self.proxy_model.setSourceModel(self.moviesTable.model())

# self.proxy_model.sort(0, Qt.AscendingOrder)

self.moviesTable.setModel(self.proxy_model)

sup.connect_actions(self)
sup.filterboxes(self)

self.progressBar.hide()

ui_width = self.width()
ui_height = self.height()

xy = center_window(self, ui_width, ui_height)
self.move(int(xy[0]), int(xy[1]))

self.show()

self.showdialogNeuEinlesen()
versuche, erscheint folgende Fehlermeldung:
File "D:\__Sicherungsdaten\_Programmiersprachen\PycharmProjects\MovieMusicList\ListMovs.py", line 41, in __init__
self.moviesTable.model().setModel(self.proxy_model)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'QAbstractTableModel' object has no attribute 'setModel'
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja. Hat es ja auch nicht. Der View hat die Methode.
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

__deets__ hat geschrieben: Samstag 9. März 2024, 17:30 Ja. Hat es ja auch nicht. Der View hat die Methode.
solch kurze Antworten bringen mich als Anfänger leider nicht wirklich weiter
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schau dir deinen Code male genau an. Richtig genau. Das schaffst du auch als Anfänger.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Jetzt benutzt Du glücklicherweise Path, aber Pfade sind trotzdem keine Strings.Wie kommst Du auf die Idee, Pfade so zusammenzusetzen?

Code: Alles auswählen

Path(__file__).parent / "GUI" / "GUI_Movies.ui"
Wenn Du Fehlermeldungen zeigst, dann sollte der Code dazu auch passen, die Zeile 41 existiert so gar nicht.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@KlaRo: Für GUI-Programmierung muss man objektorientierte Programmierung beherrschen, und bei Qt die Einzelteile und ihr Zusammenspiel verstehen. Das ist bei Qt gut dokumentiert, also nicht nur die einzelnen Klassen, sondern auch Kapitel, in denen erklärt wird wie die zusammenarbeiten. Hier konkret unter der Überschrift „Model/View Programming“. Sich das zu erarbeiten kann Dir letztlich keiner abnehmen.

So rein von den Worten her macht es doch schon nicht wirklich Sinn auf einem Model ein Model setzen zu wollen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

__deets__ hat geschrieben: Samstag 9. März 2024, 17:38 Schau dir deinen Code male genau an. Richtig genau. Das schaffst du auch als Anfänger.
Gibst mir noch nen Tip, wo genau ich suchen soll? :)
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

in der Fehlermeldung wird eine Zeile angezeigt, immer im Bereich, der angezeigten Zeile, ist der Fehler, der auftritt. Kann auch etwas davor sein, aber bei dir hat der Interpreter die Zeile gut getroffen.
Dann steht doch da:
"AttributeError: 'QAbstractTableModel' object has no attribute 'setModel' "
und du schreibst `self.moviesTable.model().setModel(self.proxy_model)`

Kannst du auf das Objekt `self.moviesTable.model()` nicht `setModel` anwenden, weil es das nicht gibt.
Das es `setModel` bei QAbstractItem gibt, hat __deets__ schon genannt. Du verwendest hier QAbstractTableModel. Jetzt kannst du nachlesen, was die beiden können und was du brauchst.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
KlaRo
User
Beiträge: 32
Registriert: Samstag 27. Januar 2024, 10:38

Dennis89 hat geschrieben: Samstag 9. März 2024, 18:31 Hallo,

in der Fehlermeldung wird eine Zeile angezeigt, immer im Bereich, der angezeigten Zeile, ist der Fehler, der auftritt. Kann auch etwas davor sein, aber bei dir hat der Interpreter die Zeile gut getroffen.
Dann steht doch da:
"AttributeError: 'QAbstractTableModel' object has no attribute 'setModel' "
und du schreibst `self.moviesTable.model().setModel(self.proxy_model)`

Kannst du auf das Objekt `self.moviesTable.model()` nicht `setModel` anwenden, weil es das nicht gibt.
Das es `setModel` bei QAbstractItem gibt, hat __deets__ schon genannt. Du verwendest hier QAbstractTableModel. Jetzt kannst du nachlesen, was die beiden können und was du brauchst.

Grüße
Dennis
Guten Morgen,

ich habe den ganzen Abend hin und her versucht, darüber geschlafen und auch heute Morgen weiter versucht → ich bekomme es einfach nicht hin! :cry:
Kannst Du –oder auch ein Anderer– mir nicht den Code(schnipsel), der funktionieren sollte, am Besten mit Erklärung zur Verfügung stellen? Dann kann ich das nachvollziehen und für später merken.

VG
Antworten