Seite 1 von 1
QListView signals
Verfasst: Freitag 19. April 2024, 10:44
von mechanicalStore
Hallo,
wenn ich in einer QListView einen anderen Eintrag auswähle und damit das "clicked"-Signal sende, wie komme ich an den Index des Eintrags im empfangenen Slot (z.B. im einfachsten Fall, um den Taxt eines Labels zu ändern, etc...)?
Stehe irgendwie auf dem Schlauch gerade.
Danke und Gruß.
Re: QListView signals
Verfasst: Freitag 19. April 2024, 10:47
von __deets__
Das steht doch in der Doku:
https://doc.qt.io/qt-6/qabstractitemview.html#clicked - du bekommst den Index.
Re: QListView signals
Verfasst: Freitag 19. April 2024, 12:49
von mechanicalStore
Ja, danke. Ich habe aber das Problem, dass ich an den Eintrag, den ich ausgewählt habe, nicht heran komme. D.h. dahinter liegt ja mein model, welches ist auch mit .model erreiche. Jedoch kann ich keinerlei funktionen darauf aufrufen. D.h. example_list.model.some_function() ist nicht möglich. Wie komme ich also tatsächlich an die Listeneinträge dran? Finde in der Doku auch nichts bzgl. item(index) oder sonstwas. Auch in den vererbenden Klassen nicht.
Re: QListView signals
Verfasst: Freitag 19. April 2024, 13:22
von __blackjack__
@mechanicalStore: Du suchst wohl die `data()`-Methode.
Re: QListView signals
Verfasst: Freitag 19. April 2024, 13:57
von mechanicalStore
__blackjack__ hat geschrieben: ↑Freitag 19. April 2024, 13:22
@mechanicalStore: Du suchst wohl die `data()`-Methode.
Hallo __blackjack___,
ja, die habe ich auch schon gesucht. Und nicht erreichbar über die QListView.model, sondern nur über das model selbst, das hatte ich übersehen. Funktioniert jetzt. Besten Dank.
Re: QListView signals
Verfasst: Freitag 19. April 2024, 18:20
von mechanicalStore
Hallo,
jetzt habe ich doch noch ein Problem. Da im u.g. (stark gekürzten) Beispiel
id der primary key ist, kann es natürlich beliebig viele
internal_number geben. Durch die Auswahl in der QListView gelange ich über
index und die data methode wiederum an die
id. Sind aber mehrere gleiche Einträge drin, bekomme ich wegen
.first() immer die erst gefundene id zurück. Gibt es einen Weg, über den Index der QListView auch direkt wieder an die
id zu kommen?
Code: Alles auswählen
#sqlmodel
class Part(Base):
__tablename__ = "part_basedata"
id: Mapped[int] = mapped_column(primary_key=True)
measurings: Mapped[List["Measuring"]] = relationship(back_populates="part")
internal_number: Mapped[int]
...
@classmethod
def get_all_internal_numbers(cls, session) -> int:
return session.execute(select(cls.internal_number)).scalars().all()
@classmethod
def get_id_by_internal_number(cls, session, internal_number) -> int:
return session.scalars(select(cls.id).where(cls.internal_number == internal_number)).first()
#gridmodel
class PartListModel(QAbstractListModel):
def __init__(self, session):
super().__init__()
self.session = session
self.part_data = Part.get_all_internal_numbers(self.session)
def data(self, index, role):
if role == Qt.ItemDataRole.DisplayRole or role == Qt.ItemDataRole.EditRole:
return self.part_data[index.row()]
#gridview
class MainWindow(QMainWindow):
def __init__(self, session):
self.parts_view = QListView()
self.parts_model = PartListModel(self.session)
self.parts_view.setModel(self.parts_model)
...
self.parts_view.clicked.connect(self.set_part_description_labels)
...
@Slot()
def set_part_description_labels(self, index):
internal_number = self.parts_model.data(index, Qt.ItemDataRole.DisplayRole)
part_id = Part.get_id_by_internal_number(self.session, internal_number)
...
self.part_internal_number_description.setText(f'Part-Number: = {str(internal_number)}')
...
print(part_id)
Re: QListView signals
Verfasst: Samstag 20. April 2024, 14:03
von mechanicalStore
...Gibt es einen Weg, über den Index der QListView auch direkt wieder an die id zu kommen?
Jemand eine Idee dazu?
Re: QListView signals
Verfasst: Samstag 20. April 2024, 15:06
von __blackjack__
@mechanicalStore: Ich würde da einfach beides von der Datenbank abfragen. Also eigentlich würde ich sogar einfach ganze `Part`-Objekte abfragen. Denn wozu ein ORM wenn man dann doch immer nur einzelne Werte abfragt und nicht die Objekte. Vielleicht würde es sogar Sinn machen ein Model zu erstellen das mehr als nur diese eine Spalte der Datenbank liefert. Man kann bei QListView ja festlegen welche Spalte verwendet werden soll.
Re: QListView signals
Verfasst: Samstag 20. April 2024, 20:15
von mechanicalStore
@__blackjack__: Es werden quasi die Autofilter einer Excel Liste nachgebildet (natürlich nur ,was die Auswahl betrifft). In Part gibt es Einträge, zu jedem dieser Einträge gibt es in Measuring eine Teilmenge. Ebenso gibt es zu jedem Eintrag in Measuring eine Teilmenge in MeasuringPiece. Also quasi surjektive Abbildungen. Wähle ich aus Part einen Eintrag aus, soll die entsprechende Teilmenge in Measuring (d.h. ebenfalls wieder eine QListView) aufgelistet werden (und vice versa nach Unten, wieder QListView). Da Part auch gleiche Einträge haben kann, wird eben der "Rückweg", die id anhand des (doppelt oder mehrfachen) Eintrags zu finden, nicht mehr möglich.
Du meinst also, dass für jede der 3 Tabellen jeweils alles abgefragt und nur die entsprechende Spalte angezeigt wird?!
Re: QListView signals
Verfasst: Freitag 26. April 2024, 15:25
von mechanicalStore
@__blackjack__:
stehe irgendwie auf dem Schlauch. Wie Du geschrieben hast, ist es besser, das ganze Object abzufragen, und in der QListView nur die entsprechende Spalte anzuzeigen. Das funktioniert auch, aber wie komme ich wieder an das Object selbst dran? Das muss doch über den Index gehen, aber ich habe hier offenbar nicht die Struktur, die ich brauche?!
Gekürztes Beispiel:
Code: Alles auswählen
# sqlqlchemy
class Part(Base):
__tablename__ = "part_basedata"
id: Mapped[int] = mapped_column(primary_key=True)
measurings: Mapped[List["Measuring"]] = relationship(back_populates="part")
internal_number: Mapped[int]
internal_name: Mapped[Optional[str]]
customer_number: Mapped[Optional[str]]
customer_name: Mapped[Optional[str]]
...
@classmethod
def get_all_objects(cls, session):
return session.execute(select(cls)).scalars().all()
# qt model
class PartListModel(QAbstractListModel):
def __init__(self, session):
super().__init__()
self.session = session
self.part_data = Part.get_all_objects(self.session)
...
def data(self, index, role):
if role == Qt.ItemDataRole.DisplayRole or role == Qt.ItemDataRole.EditRole:
return self.part_data[index.row()].internal_number
# qt view
...
self.parts_view = QListView()
self.parts_model = PartListModel(self.session)
self.parts_view.setModel(self.parts_model)
...
self.parts_view.clicked.connect(self.set_part_description_labels)
...
@Slot()
def set_part_description_labels(self, index):
internal_number = self.parts_model.data(index, Qt.ItemDataRole.DisplayRole)
print(type(internal_number))
print(internal_number)
print(type(self.parts_model.data))
print(self.parts_model.data)
print(self.parts_model.data[index.row()])
....
Ausgabe:
Code: Alles auswählen
<class 'int'>
80757
<class 'method'>
<bound method PartListModel.data of <gridmodel.PartListModel(0x61d86b62c240) at 0x72c01b2a9900>>
Traceback (most recent call last):
File "/home/******/develop/git/measuring/gridview.py", line 83, in set_part_description_labels
print(self.parts_model.data[index.row()])
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
TypeError: 'method' object is not subscriptable
Re: QListView signals
Verfasst: Freitag 26. April 2024, 16:05
von __deets__
Der Parameter index ist kein QIndex. Warum auch immer. Gib dir aus, was es eigentlich ist.
Re: QListView signals
Verfasst: Freitag 26. April 2024, 16:30
von __blackjack__
`data` ist eine Methode und [ ] sind die falschen Klammern für einen Methodenaufruf.
Re: QListView signals
Verfasst: Freitag 26. April 2024, 16:47
von mechanicalStore
Ja, und damit komme ich dann zu:
Ausgabe:
Code: Alles auswählen
print(self.parts_model.data())
^^^^^^^^^^^^^^^^^^^^^^^
TypeError: PartListModel.data() missing 2 required positional arguments: 'index' and 'role'
Womit ich dann wieder hier bin:
Code: Alles auswählen
internal_number = self.parts_model.data(index, Qt.ItemDataRole.DisplayRole)
Was mir nur den Integerwert der Auswahl zurück gibt. Daher war ja meine Frage, wie ich wieder an das eigentliche Object komme, denn der Weg scheint ja komplett ins Leere zu führen.
Re: QListView signals
Verfasst: Samstag 27. April 2024, 08:40
von mechanicalStore
Hallo Zusammen,
habe es jetzt mit einem Workaround lösen können...
Code: Alles auswählen
class PartListModel(QAbstractListModel):
def __init__(self, session):
super().__init__()
self.session = session
self._part_data = Part.get_all_objects(self.session)
...
def data(self, index, role):
if role == Qt.ItemDataRole.DisplayRole or role == Qt.ItemDataRole.EditRole:
return self._part_data[index.row()].internal_number
@property
def datamodel(self):
return self._part_data
class MainWindow(QMainWindow):
def __init__(self, session):
super().__init__(windowTitle = "Main Window")
self.resize(QSize(1500, 800))
self.session = session
self.setStatusBar(QStatusBar(self))
self.parts_view = QListView()
self.parts_model = PartListModel(self.session)
self.parts_view.setModel(self.parts_model)
.....
self.parts_view.clicked.connect(self.set_part_description_labels)
...
@Slot()
def set_part_description_labels(self, index):
# internal_number = self.parts_model.data(index, Qt.ItemDataRole.DisplayRole)
object_choice = self.parts_model.datamodel
part_id = object_choice[index.row()].id
internal_number = object_choice[index.row()].internal_number
internal_name = object_choice[index.row()].internal_name
customer_number = object_choice[index.row()].customer_number
customer_name = object_choice[index.row()].customer_name
Ist es legitim, nicht die data() methode des models zu benutzen (s. auskommentierte Zeile) und stattdessen das model sozusagen nochmal zuzuweisen (an object_choice)? Funktioniert so zwar, kommt mir aber immer noch umständlich vor. Der index der QLIstView lässt sich über die data() methode irgendwie nicht verwenden.
(Einrückung kommt am Schluss nicht richtig rüber)