Event Mouse Button

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
ich versuche einen Event bei der linken Maustaste zu erhalten.
Leider funktioniert es mit dem Code nicht.

Code: Alles auswählen

def eventFilter(self, widget, event):
	if event.type() == QMouseEvent.MouseButtonPress:
		print('MouseButtonPress')
		if event.button() == Qt.LeftButton:
			print('LeftButton')
	return QWidget.eventFilter(self, widget, event)
Bräuchte da Eure Hilfe!

Grüße Nobuddy
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ich habe mal die Werte von event.type() und QEvent.MouseButtonPress, beim klicken mit der linken Maustaste abgefangen.
event.type(): 12 ## QEvent.Paint > QPaintEvent
QEvent.MouseButtonPress: 2
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann scheint es so zu sein, dass jemand in deiner Widget-Hierarchy das schon vorher irgendwie verschluckt, und du bekommst das mouse-event gar nicht mehr.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hallo __deets__,
Deine Vermutung trifft voll ins Schwarze.

beschreibe mal kurz mein Vorhaben.
In der Tabelle kann ich mit den Tasten Up und Down, Tabellenzeilen ansteuern, was gut funktioniert. Mit der Maus, habe ich eine vorübergehende Lösung, die ich gerne ersetzen möchte.

Ich poste hier mal den abgespeckten Code, der lauffähig ist.
Hier sind die Buttons Up und Down nicht integriert, um den Code nicht größer zu machen.
Hoffe, Du kannst dadurch das Problem eingrenzen.

Code: Alles auswählen

import sys
from PyQt5.QtCore import (
	Qt,
	QEvent,
	QAbstractTableModel,
	)
from PyQt5.QtWidgets import (
	QApplication,
	QMainWindow,
	QTableView,
	QAbstractItemView,
	QSizePolicy,
	QGridLayout,
	QMdiArea,
	QWidget,
	)
from PyQt5.QtGui import  (
	QStandardItem,
	QStandardItemModel,
	)

class TableWindow(QMainWindow):

	def __init__(self, filename, header, data):
		super(TableWindow, self).__init__()

		self.installEventFilter(self)
		self.mdi = QMdiArea()
		self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
		self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
		self.setCentralWidget(self.mdi)
		self.setGeometry(0, 0, 500, 500)
		self.setWindowTitle(filename)
		obj = Table(filename, header, data)
		self.printObject = obj
		self.mdi.addSubWindow(obj)
		self.show()
		self.mdi.activeSubWindow().showMaximized()


class Table(QTableView):

	def __init__(self, filename, header, data):
		QWidget.__init__(self)

		self.old_data = self.mylist = self.data = sorted(data)
		self.header = header
		if not self.header:
			self.header = ['col_{}'.format(i)
				for i in range(len(self.data[0]))]
		self.rowCounter = len(self.data) - 1
		self.index = self.rowIndex = 0
		self.viewport().installEventFilter(self)
		self.view = QTableView(self)
		grid = QGridLayout()
		grid.addWidget(self.view, 0, 0)
		self.setLayout(grid)
		self.model = TableModel(self.data, self.header)
		self.update_table()
		self.headerSize()

	def updateGeometryAsync(self):
		QTimer.singleShot(0, self.updateGeometry)

	def headerSize(self):
		"""
		Build header- and columnsize
		"""
		self.view.setModel(self.model)
		self.view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		self.view.resizeColumnsToContents()
		self.view.resizeRowsToContents()
		self.view.setWordWrap(True)

	def update_table(self):
		# ... when a row header label changes and makes the
		# width of the vertical header change too
		self.model.headerDataChanged.connect(self.updateGeometryAsync)
		self.view.setModel(self.model)
		# enable sorting
		self.view.setSortingEnabled(True)
		self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
		self.view.setSelectionMode(QAbstractItemView.SingleSelection)
		self.view.setFocus()
		self.view.selectRow(self.rowIndex)
		self.adjustSize()

	def controlBackNext(self):
		print('rowIndex: ',self.index)

	def eventFilter(self, widget, event):
		try:
			if self.view.selectedIndexes()[0].row() != self.index:
				print('eventTyp, QEvent.MouseButtonPress: ',
					event.type(), QEvent.MouseButtonPress)
				self.index = self.view.selectedIndexes()[0].row()
				self.controlBackNext()
		except (AttributeError, IndexError):
			pass
		return QWidget.eventFilter(self, widget, event)


class TableModel(QAbstractTableModel):

	def __init__(self, mylist, header, *args):
		QAbstractTableModel.__init__(self, *args)
		self.mylist = mylist
		self.header = header

	def rowCount(self, widget):
		return len(self.mylist)

	def columnCount(self, widget):
		return len(self.mylist[0])

	def data(self, index, role):
		if not index.isValid() or role != Qt.DisplayRole:
			return None
		return self.mylist[index.row()][index.column()]

	def headerData(self, col, orientation, role):
		if (orientation == Qt.Horizontal
				and role == Qt.DisplayRole):
			return self.header[col]
		elif (orientation == Qt.Vertical
				and role == Qt.DisplayRole):
			return col
		return None

	def output_list(self):
		return self.mylist


def main():
	filename = 'Testtabelle'
	header = False
	data = [['fritz', 'müller', 'fritz', 'müller', 'müller', 'müller'],
		['fritz', 'müller', 'fritz', 'müller', 'müller', 'müller'],
		['fritz', 'müller', 'fritz', 'müller', 'müller', 'müller'],
		['fritz', 'müller', 'fritz', 'müller', 'müller', 'müller'],
		]

	App = QApplication(sys.argv)
	ex = TableWindow(filename, header, data)
	sys.exit(App.exec())

if __name__ == '__main__':
	main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weil ich es gerade sehe: das Table von QTableView erbt, aber dann nur QWidget aufrufst, ist grober Unfug. Das darf so nicht sein. Da du einen self.view vom Typ QTableView hast, sollte das wohl QWidget sein.

Erstmal kann ich bestaetigen, dass es auch bei mir nicht wirklich diese Events gibt.

Was willst du denn ueberhaupt erreichen? Mit der Maus kann man doch Zellen anwaehlen, also was muss da anders?
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

__deets__ hat geschrieben: Mittwoch 4. Januar 2023, 17:00 Weil ich es gerade sehe: das Table von QTableView erbt, aber dann nur QWidget aufrufst, ist grober Unfug. Das darf so nicht sein. Da du einen self.view vom Typ QTableView hast, sollte das wohl QWidget sein.
Den Fehler möchte ich korrigieren, meinst Du das so:

Code: Alles auswählen

class TableWindow(QMainWindow):

	def __init__(self, filename, header, data):
		super(TableWindow, self).__init__()

ODER ???
__deets__ hat geschrieben: Mittwoch 4. Januar 2023, 17:00 Erstmal kann ich bestaetigen, dass es auch bei mir nicht wirklich diese Events gibt.
Also dann kein Fehler im Code meinerseits.
Evtl. ein Bug ...?
__deets__ hat geschrieben: Mittwoch 4. Januar 2023, 17:00 Was willst du denn ueberhaupt erreichen? Mit der Maus kann man doch Zellen anwaehlen, also was muss da anders?
War ein Gedankenfehler meinerseits und habe extra zwei Buttons (back, next) integriert, die dann die dann die Tabellenzeile selectieren und wenn sie an der obersten bzw. untersten Tabellenzeile sind den jeweiligen Button deaktivieren.
Eigentlich eine unnötige Spielerei, da ja die Tastaturbutton UP/DOWN dafür völlig ausreichen. Dies werde ich nicht weiter verfolgen, da es keinen Sinn macht.
Ja, manchmal suche ich wohl die 'eierlegende Wollmilchsau' :wink:

Allerdings ist nicht produktiv, wenn wie in diesem Beispiel, MouseEvents im eventFilter nicht abgefangen werden können.

Grüße und Danke Nobuddy
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein, es geht nicht um TableWindown. Auch wenn das super(TableWindow, ...) ueberfluessig ist in Python 3 (da reicht super()), ist das so weit ok. Das hier meine ich:

Code: Alles auswählen

class Table(QTableView):

	def __init__(self, filename, header, data):
		QWidget.__init__(self)
Nicht nur bist du inkonsistent in der Verwendung (oder nicht) von super, du machst eben dadurch auch einen Fehler, weil du QWidget statt QTableView verwendest - oder umgekehrt, je nach dem, was denn das richtige ist.

Was deine eigentliche Frage angeht: wirklich verstanden habe ich die nicht. Wenn du Buttons zur Navigation anbieten willst, warum brauchst du dafuer event-filter? Und nicht die simplen clicked-Signale?
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Sorry, habe Dir das falsche gepostet.
Das ist dann so richtig.

Code: Alles auswählen

class Table(QTableView):

	def __init__(self, filename, header, data):
		super().__init__()
Mit Deiner Frage hast Du Recht, clicked-Signale sind da das Richtige.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ob das richtig ist, weiss ich nicht. Richtiger, ja. Aber du hast ja ein Widget das seinerseits einen Tableview anlegt. Ein verschachtelter Tableview ist eigentlich nie richtig. "class Table(QWidget)" waere also eher mein Kandidat. Und dann ist da natuerlich noch die Frage nach dem parent-argument und so Dinge.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Danke, für die Info!
Mir ist es wichtig, es so richtig wie möglich zu machen und daher möchte das aufgreifen und ändern.
Wenn ich es abgeändert habe, poste ich es hier ...
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Code: Alles auswählen

class Table(QTableView):

	def __init__(self, filename, header, data):
		super(Table, self).__init__()

		self.old_data = self.mylist = self.data = sorted(data)
		self.header = header
		if not self.header:
			self.header = ['col_{}'.format(i)
				for i in range(len(self.data[0]))]
		self.rowCounter = len(self.data) - 1
		self.index = self.rowIndex = 0
		self.viewport().installEventFilter(self)
		# self.view = QTableView(self)
		# QTableView == self == self.view old ????????
Habe das mal so verstanden, keine Fehlermeldung aber auch kein Tabellenfenster. Hoffe, Du bekommst jetzt keinen Haarausfall, wenn das komplett falsch ist.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Habe hier: https://www.pythonguis.com/tutorials/qt ... py-pandas/ dazu was gefunden, was wahrscheinlich dem entspricht, was Du mir mitteilen wolltest.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist leider komplett falsch. Da steht doch die voellig falsche Klasse im super-Statement. Und wie schon erlaeutert: das da ueberhaupt eine Klasse steht, ist doch gar nicht mehr notwendig seit Python 3.

Also alles andere als super() - gefolgt von __init__ oder was auch immer, und Argumenten natuerlich - ist *falsch*.

Das pandas-Ding sieht soweit ok aus, letztlich ist es eine Frage, was man da machen will. Willst du QTableView ableiten? Wenn ja, warum genau? Wenn nicht, dann schmeisst man das nicht einfach als Basisklasse in eine Klasse.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ob der Link das Richtige das Richtige jetzt ist ...
Besser wir nehmen meinen kleinen Beispiel Code.
Könntest Du mit dem das richtig stellen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kann ich nicht, weil ich nicht weiss, was du willst. *Willst* du QTableView ableiten? Ja oder nein? Wenn ja, *warum*? Davon haengt doch nunmal ab, was richtig ist.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ich komme nicht aus dem Bereich der Informatik und Deine Frage so leider nicht beantworten. Bin schon lange Rentner und krank. Habe früher mit Tabellen im Text- bzw. CSV-Format gearbeitet, daher interessiert mich dies auch.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das hat mit Informatik oder so doch gar nichts zu tun. Du hast folgenden Code geschrieben:

Code: Alles auswählen


class Table(QTableView):  # <- QTableView-Ableitung

	def __init__(self, filename, header, data):
		QWidget.__init__(self) # KEIN super, und QWidget als Konstruktor der super-Klasse, steht im Konflikt mit QTableView als angegebener Basisklasse!

		self.old_data = self.mylist = self.data = sorted(data)
		self.header = header
		if not self.header:
			self.header = ['col_{}'.format(i)
				for i in range(len(self.data[0]))]
		self.rowCounter = len(self.data) - 1
		self.index = self.rowIndex = 0
		self.viewport().installEventFilter(self)
		self.view = QTableView(self)   # ein TableView, der ein Attribut einer Table-Instanz ist.
Und das ist auf mehreren Ebenen konfus. Wenn du von QTableView ableiten willst, dann musst du auch dessen Konstruktor aufrufen. Was du mit super().__init__(...) tun *koenntest*, aber dann fehlt da in deinen Argumenten nunmal ein parent, der haengt ja eher nicht einfach in der Luft (als eigenes Fenster), sondern wird irgendwo in eine Hierarchie eingebaut. Und dann wiederum ist self.view = QTableView(self) quatsch, denn self *ist* dann ein TableView.

Und nur du kannst beantworten, was du mit class Table erreichen willst, und ob du wirklich eine Ableitung von QTableView haben willst. Davon haengt aber ab, wie der Code "richtig" ist. Ich kann dir sagen, das *ich* nicht von QTableView ableiten wuerde, weil ich darin keinen Mehrwert erkenne. Aber ich habe das Programm nicht geschrieben, und du magst Gruende haben. Aber die musst du schon nennen, bzw. dazu eben Stellung beziehen.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Danke für den Input, werde mich damit auseinandersetzen und melde mich dann wieder.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Nach Änderung:

Code: Alles auswählen

class Table(QTableView):

	def __init__(self, header, data):
		super().__init__()

		self.mylist = self.data = sorted(data)
		self.header = header
		if not self.header:
			self.header = ['col_{}'.format(i)
				for i in range(len(self.data[0]))]
		self.rowCounter = len(self.data) - 1
		self.rowIndex = self.rowIndex = 0
		self.viewport().installEventFilter(self)
		self.model = TableModel(self.data, self.header)
und funktioniert.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schoen, das ist konsistent bezueglich des super(), also eine Verbesserung. Aber eben kein parent per super().__init__ (und natuerlich dem eigenen __init__) anggeben, und damit ist das immer ein Toplevel Widget. Das ist eher ungewoehnlich. Das solltest du also mindestens nochmal nachruesten.
Antworten