Connecting selection in QTableView and QGraphicsView
I have a GUI with some objects in a QTableView and a corresponding list of objects in a QTableView. I want to make it so that any selection in one is reflected in the other.
I have this working by connecting the selectionChanged signals from the QGraphicsScene and the QSelectionModel to my own methods which set the corresponding selection in the other view.
However this loops infinitely which I have sort of kludged by adding a busy flag which I set in each of these methods and test in the other method and immediately return if it's set.
It all sort of works but it's a bit ugly. Also each method is called twice (I think once for the initial clearing of the selection and once for the setting). Also, it's a bit slow: i have a particular problem when I try to do a rubber band select in the QGraphicsView - the scene selection keeps changing and I get a lot of lag on the display.
I also tried by catching the signals when each item has its selection changed - i.e. doing it item by item rather than overall, but it didn't seem to help, though maybe I wasn't doing that one right either :-)
So the question is, is there a better way?
I have a test case which I've simplified as much as possible, but it's in PySide. But this is not really a PySide question, more a general design one so I've posted here. I'll put the code below (sorry, -it's inevitably quite long):
@# -- coding: utf-8 --
from PySide import QtCore,QtGui
self.app = QtGui.QApplication(sys.argv)
self.centralwidget = QtGui.QWidget(self) self.setCentralWidget(self.centralwidget) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.graphicsView = QtGui.QGraphicsView() self.graphicsView.setScene(MyScene()) self.verticalLayout.addWidget(self.graphicsView) self.tableView = QtGui.QTableWidget(2,1) item = QtGui.QTableWidgetItem("Item 1") item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.tableView.setItem(0,0,item) item = QtGui.QTableWidgetItem("Item 2") item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.tableView.setItem(1,0,item) self.verticalLayout.addWidget(self.tableView) self.busy = False self.tableView.selectionModel().selectionChanged.connect(self.smSelectionChanged) self.graphicsView.scene().selectionChanged.connect(self.sceneSelectionChanged) # selectionModel selection has changed def smSelectionChanged(self): print "smSelectionChanged" if not self.busy: self.busy = True selectedRows = self.tableView.selectionModel().selectedIndexes() self.graphicsView.scene().setSceneSelected(selectedRows) self.busy = False # scene selection has changed def sceneSelectionChanged(self): print "sceneSelectionChanged" if not self.busy: self.busy = True selectedShapes = self.graphicsView.scene().selectedShapes() self.tableView.selectionModel().clearSelection() for i in selectedShapes: item = self.tableView.item(i,0) index = self.tableView.indexFromItem(item) self.tableView.selectionModel().select(index,QtGui.QItemSelectionModel.Select) self.busy = False
def __init__(self): QtGui.QGraphicsScene.__init__(self) rect = QtCore.QRectF(-50,-50,50,50) self.shapes = [None,None] self.shapes = QtGui.QGraphicsEllipseItem(rect,None,self) self.shapes.setBrush(QtCore.Qt.red) self.shapes.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True) self.shapes.setPos(120,120) self.shapes = QtGui.QGraphicsEllipseItem(rect,None,self) self.shapes.setBrush(QtCore.Qt.blue) self.shapes.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True) self.shapes.setPos(200,200) def setSceneSelected(self,nolist): self.clearSelection() for no in nolist: self.shapes[no.row()].setSelected(True) def selectedShapes(self): return [ i for i in range(2) if self.shapes[i].isSelected()]
app = MainWindow()