Seite 3 von 4
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 14:06
von Nobuddy
Wenn ich
Code: Alles auswählen
# bind cell click to a method reference
table_view.clicked.connect(self.showSelection)
verwende, kann ich mit
Code: Alles auswählen
def showSelection(self, item):
mylist = self.table_model.sorted_list()
dataset = mylist[item.row()]
print(dataset) # test
mir den mit der Maus ausgewählten Zelle den Datensatz ausgeben lassen.
Nur wie ich das mit QAction oder mit EventFilter berwerkstelligen soll ... :K
Ein Beispiel dazu, wäre vielleicht hilfreich.
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 14:40
von __deets__
Du musst doch nur einen installieren, und wenn ein RETURN kommt in der Selection nachschauen, ob es da eine angewaehlte Zeile gibt.
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 15:36
von Nobuddy
Alles schön und gut, allerdings sehe ich den Wald vor lauter Bäumen nicht! :K
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 15:41
von __deets__
Ich habe kein fertiges Beispiel, und auch nicht die Zeit, eines zu bauen. Aber wie BlackJack nie muede wird (ich verneige mich vor seiner Geduld) zu betonen: ein grosses Problem zerlegt man in kleine, bis man welche hat, die man versteht.
Also haeng doch ersmal einen EventFilter an deinen QTableView. Dazu kannst du zB dem hier folgen:
https://stackoverflow.com/questions/330 ... ent-filter
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 15:49
von Nobuddy
Werde den Link durchgehen.
Danke und Grüße
Nobuddy
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 17:54
von Nobuddy
Mein Code sieht momentan so aus (Baustelle)
Code: Alles auswählen
import operator # used for sorting
from PyQt4.QtCore import Qt, QAbstractTableModel, SIGNAL, pyqtSignal
from PyQt4.QtGui import QWidget, QTableView, QApplication, QVBoxLayout, QTreeView, QKeyEvent
class MyTreeView(QTreeView):
enterPressed = pyqtSignal()
def __init__(self):
QTreeView.__init__(self)
def keyPressEvent(self, event): #QKeyEvent
if event.key() == Qt.Key_Enter:
self.enterPressed.emit()
print('enter key pressed')
class MyWindow(QWidget):
def __init__(self, dataList, header, *args):
QWidget.__init__(self, *args)
self.filter = MyTreeView()
self.installEventFilter(self.filter)
MyTreeView.keyPressEvent(QKeyEvent()) #<<<<<<<<<< Fehlermeldung
# setGeometry(x_pos, y_pos, width, height)
self.setGeometry(70, 150, 420, 250)
self.setWindowTitle("Click on the header to sort table")
self.table_model = MyTableModel(self, dataList, header)
table_view = QTableView()
# bind cell click to a method reference
table_view.clicked.connect(self.showSelection)
table_view.setModel(self.table_model)
# enable sorting
table_view.setSortingEnabled(True)
layout = QVBoxLayout(self)
layout.addWidget(table_view)
self.setLayout(layout)
def showSelection(self, item):
# Hole Liste
mylist = self.table_model.sorted_list()
# Ausgabe des ausgewählten Datensatzes
dataset = mylist[item.row()]
# Editiere Datensatz
dataset = list(dataset) # Test
dataset[0] = 'aaa test' # Test
dataset = tuple(dataset) # Test
# Update Liste
mylist[item.row()] = dataset
self.table_model.edit_list(mylist)
#
cellContent = item.data()
print(cellContent) # test
sf = "You clicked on {}".format(cellContent)
# display in title bar for convenience
self.setWindowTitle(sf)
class MyTableModel(QAbstractTableModel):
"""
keep the method names
they are an integral part of the model
"""
def __init__(self, parent, mylist, header, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.mylist = mylist
self.header = header
def rowCount(self, parent):
return len(self.mylist)
def columnCount(self, parent):
return len(self.mylist[0])
def data(self, index, role):
if not index.isValid():
return None
elif 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]
return None
def sort(self, col, order):
"""sort table by given column number col"""
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.mylist = sorted(self.mylist,
key=operator.itemgetter(col))
if order == Qt.DescendingOrder:
self.mylist.reverse()
self.emit(SIGNAL("layoutChanged()"))
def sorted_list(self):
return self.mylist
def edit_list(self, mylist):
self.mylist = mylist
return
# you could process a CSV file to create this data
header = ['First Name', 'Last Name', 'Age', 'Weight']
# a list of (fname, lname, age, weight) tuples
dataList = [
('Ben', 'Dover', 36, 127),
('Foster', 'Krampf', 27, 234),
('Barry', 'Chaurus', 19, 315),
('Sede', 'Anowski', 59, 147),
('Carolus', 'Gabel', 94, 102),
('Michel', 'Zittus', 21, 175),
('Annie', 'Waters', 31, 114)
]
app = QApplication([])
win = MyWindow(dataList, header)
win.show()
result = app.exec_()
print(result)
Dabei erhalte ich folgende Fehlermeldung:
Code: Alles auswählen
Traceback (most recent call last):
File "table_test.py", line 132, in <module>
win = MyWindow(dataList, header)
File "table_test.py", line 32, in __init__
MyTreeView.keyPressEvent(QKeyEvent()) #<<<<<<<<<< Fehlermeldung
TypeError: arguments did not match any overloaded call:
QKeyEvent(QEvent.Type, int, Qt.KeyboardModifiers, str text='', bool autorep=False, int count=1): not enough arguments
QKeyEvent(QKeyEvent): not enough arguments
was diese Zeile betrifft:
Code: Alles auswählen
MyTreeView.keyPressEvent(QKeyEvent()) #<<<<<<<<<< Fehlermeldung
Was mache ich falsch?
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 17:58
von __deets__
Du sollst den EventFilter *auf dem QTableView* setzen. Nicht ihn zum EventFilter eines Fensters machen. Der Filter ist nur von QObject abgeleitet (wie in meinem Beispiel vorgemacht), und er wird dann auf dem QTableView installiert. Im Beispiel ist es ein TreeView, aber das ist ja nun egal.
Und warum rufst du keyPressEvent dann auf? Das soll doch passieren, wenn du einen Key *drueckst*. Wenn du das selbst aufrufst, ist das doch sinnlos :K
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 18:00
von BlackJack
@Nobuddy: Alles. Die ganze Zeile macht keinen Sinn und Du vermischt hier jetzt auch das überschreiben der Methode und das Verwenden eines Eventfilters. Entweder das *eine* oder das *andere*. Beides macht keinen Sinn.
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 18:25
von Nobuddy
Also, dann habe ich ja die volle Punktzahl .... :K
Ich habe die zwei ersten Zeilen hier her positioniert
Code: Alles auswählen
# you could process a CSV file to create this data
header = ['First Name', 'Last Name', 'Age', 'Weight']
# a list of (fname, lname, age, weight) tuples
dataList = [
('Ben', 'Dover', 36, 127),
('Foster', 'Krampf', 27, 234),
('Barry', 'Chaurus', 19, 315),
('Sede', 'Anowski', 59, 147),
('Carolus', 'Gabel', 94, 102),
('Michel', 'Zittus', 21, 175),
('Annie', 'Waters', 31, 114)
]
app = QApplication([])
filter = MyTreeView()
app.installEventFilter(filter)
win = MyWindow(dataList, header)
win.show()
result = app.exec_()
Nur wohin mit diesem?
Re: Scallierung von QtWidgets
Verfasst: Donnerstag 29. Juni 2017, 19:44
von __deets__
Ich weiss nicht, wieviel klarer ich das ausdruecken soll: der View ist nicht der Filter. Der View HAT einen Filter. Und MyTreeView.keyPressEvent(self, QKeyEvent) muss weg, nicht wohin.
Re: Scallierung von QtWidgets
Verfasst: Freitag 30. Juni 2017, 10:38
von Nobuddy
"MyTreeView.keyPressEvent(self, QKeyEvent)" ist weg!
Ist mein zuletzt geposteter Code richtig, oder doch falsch?
Re: Scallierung von QtWidgets
Verfasst: Freitag 30. Juni 2017, 10:49
von __deets__
"Falsch". Wie ich schon sagte - der Filter ist eine Eigenschaft des TreeView, nicht der TreeView selbst ist ein Filter.
Ich lege dir
http://doc.qt.io/qt-4.8/eventsandfilters.html an's Herz - darin ist das alles schoen beschrieben.
Re: Scallierung von QtWidgets
Verfasst: Freitag 30. Juni 2017, 13:50
von Nobuddy
Bestimmt eine schöne Doku, leider hilft mir das trotz allem nicht weiter.
Ohne ein Code-Beispiel, zum besseren Verständnis, muss ich im Moment die Flügel streichen. :K
Re: Scallierung von QtWidgets
Verfasst: Samstag 1. Juli 2017, 09:42
von Nobuddy
Gibt es ausser clicked, doubleClicked und pressed noch anderes, das sich auf die Tastatur bezieht?
Re: Scallierung von QtWidgets
Verfasst: Samstag 1. Juli 2017, 11:37
von BlackJack
@Nobuddy: `clicked()` und `doubleClicked()` bezieht sich auf die Maus und nicht auf die Tastatur.
Re: Scallierung von QtWidgets
Verfasst: Samstag 1. Juli 2017, 13:16
von Nobuddy
@BlackJack, klar das weiss ich. ich wollte wissen, ob es so was auch für die Tastatur gibt?
Re: Scallierung von QtWidgets
Verfasst: Samstag 1. Juli 2017, 18:41
von BlackJack
@Nobuddy: Als Signale nicht soweit ich weiss. Es gibt eben auf `QWidget` die Methoden `keyPressEvent()` und `keyReleaseEvent()` die man bei abgeleiteten Klassen überschreiben kann, oder man leitet von `QObject` ab und implementiert die `eventFilter()`-Methode und installiert so ein Objekt dann mittels `installEventFilter()` für das Objekt wo man für Tasten etwas spezielles machen möchte. Da gibt es in der Qt-Dokumentation auch jeweils Beispiele in C++ für, die man auf Python übertragen kann/muss.
Andererseits kann man, wie schon gesagt, auch eine `QAction` um eine Tastatursequenz anreichern und die dann auch gleich für eine Schaltfläche und einen Menüpunkt in einem Kontextmenü verwenden. Das ist das was man wohl heute von einer Anwendung erwarten würde.
Re: Scallierung von QtWidgets
Verfasst: Sonntag 2. Juli 2017, 14:52
von Nobuddy
Leider komme ich trotz Bemühung nicht zum Erfolg.
Ich poste nochmals hier den aktuellen gekürzten Code.
Code: Alles auswählen
import operator # used for sorting
from PyQt4.QtCore import Qt, QAbstractTableModel, SIGNAL, pyqtSignal
from PyQt4.QtGui import QWidget, QTableView, QApplication, QVBoxLayout, QTreeView, QKeyEvent
class MyTreeView(QTreeView):
enterPressed = pyqtSignal()
def __init__(self):
QTreeView.__init__(self)
def keyPressEvent(self, event): #QKeyEvent
print('event', event)
print('Qt.Key_Enter', Qt.Key_Enter)
if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
self.enterPressed.emit()
print('enter key pressed')
class MyWindow(QWidget):
def __init__(self, dataList, header, *args):
QWidget.__init__(self, *args)
# setGeometry(x_pos, y_pos, width, height)
self.setGeometry(70, 150, 420, 250)
self.setWindowTitle("Click on the header to sort table")
self.filter = MyTreeView()
self.installEventFilter(self.filter)
self.table_model = MyTableModel(self, dataList, header)
table_view = QTableView()
# bind cell click to a method reference
table_view.clicked.connect(self.events)
table_view.setModel(self.table_model)
# enable sorting
table_view.setSortingEnabled(True)
layout = QVBoxLayout(self)
layout.addWidget(table_view)
self.setLayout(layout)
def events(self):
MyTreeView.keyPressEvent(self, self.filter)
class MyTableModel(QAbstractTableModel):
"""
keep the method names
they are an integral part of the model
"""
def __init__(self, parent, mylist, header, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.mylist = mylist
self.header = header
def rowCount(self, parent):
return len(self.mylist)
def columnCount(self, parent):
return len(self.mylist[0])
def data(self, index, role):
if not index.isValid():
return None
elif 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]
return None
def sort(self, col, order):
"""sort table by given column number col"""
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.mylist = sorted(self.mylist,
key=operator.itemgetter(col))
if order == Qt.DescendingOrder:
self.mylist.reverse()
self.emit(SIGNAL("layoutChanged()"))
def main():
# you could process a CSV file to create this data
header = ['First Name', 'Last Name', 'Age', 'Weight']
# a list of (fname, lname, age, weight) tuples
dataList = [
('Ben', 'Dover', 36, 127),
('Foster', 'Krampf', 27, 234),
('Barry', 'Chaurus', 19, 315),
('Sede', 'Anowski', 59, 147),
('Carolus', 'Gabel', 94, 102),
('Michel', 'Zittus', 21, 175),
('Annie', 'Waters', 31, 114)
]
app = QApplication([])
win = MyWindow(dataList, header)
win.show()
result = app.exec_()
print(result)
if __name__ == '__main__':
main()
Fehlermeldung zu obigem Code:
Code: Alles auswählen
Bus::open: Can not get ibus-daemon's address.
IBusInputContext::createInputContext: no connection to ibus-daemon
event <__main__.MyTreeView object at 0x7fd39c2a2af8>
Qt.Key_Enter 16777221
Traceback (most recent call last):
File "table_test2.py", line 44, in events
MyTreeView.keyPressEvent(self, self.filter)
File "table_test2.py", line 16, in keyPressEvent
if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
AttributeError: 'MyTreeView' object has no attribute 'key'
Re: Scallierung von QtWidgets
Verfasst: Sonntag 2. Juli 2017, 17:13
von __deets__
Ach du liebe Güte. Ein paar Hinweise:
- dein Filter gehört nur von Qobject abgelitten. Und besser benannt. Es ist ein Filter. Kein view.
- dein Fehler tritt auf, weil du im clicked einfach die MyTreeView keyPressEvent aufrufst. Als ob es eine classmethod wäre. Warum? Weder ist es eine solche, noch sollst DU die aufrufen, die wird schon automatisch aufgerufen.
- der Filter gehört auf den TableView, nicht aufs MainWindow
Re: Scallierung von QtWidgets
Verfasst: Montag 3. Juli 2017, 09:47
von Nobuddy
Hallo __deets__, Danke für Deine Unterstützung!
Habe versucht, nach bestem Verständnis, Deine Worte umzusetzen.
Hier die Kurzversion.
Code: Alles auswählen
class MyWindow(QWidget):
def __init__(self, dataList, header, *args):
QWidget.__init__(self, *args)
# setGeometry(x_pos, y_pos, width, height)
self.setGeometry(70, 150, 420, 250)
self.setWindowTitle("Click on the header to sort table")
self.key_control = MyTreeView()
self.installEventFilter(QObject(self.key_control))
self.table_model = MyTableModel(self, dataList, header)
table_view = QTableView()
# bind cell click to a method reference
table_view.pressed.connect(self.showSelection)
table_view.setModel(self.table_model)
# enable sorting
table_view.setSortingEnabled(True)
layout = QVBoxLayout(self)
layout.addWidget(table_view)
self.setLayout(layout)
def showSelection(self, item):
cellContent = item.data()
sf = "You clicked on {}".format(cellContent)
# display in title bar for convenience
self.setWindowTitle(sf)
Fehlermeldung, kommt nun keine mehr!
Bin für weitere Hilfe dankbar!