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
    import sys

    class MainWindow(QtGui.QMainWindow):
    def init(self):
    self.app = QtGui.QApplication(sys.argv)
    QtGui.QMainWindow.init(self)

        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
    

    class MyScene(QtGui.QGraphicsScene):

    def __init__(self):
        QtGui.QGraphicsScene.__init__(self)
        rect = QtCore.QRectF(-50,-50,50,50)
        self.shapes = [None,None]
        self.shapes[0] = QtGui.QGraphicsEllipseItem(rect,None,self)
        self.shapes[0].setBrush(QtCore.Qt.red)
        self.shapes[0].setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
        self.shapes[0].setPos(120,120)
        self.shapes[1] = QtGui.QGraphicsEllipseItem(rect,None,self)
        self.shapes[1].setBrush(QtCore.Qt.blue)
        self.shapes[1].setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
        self.shapes[1].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()
    app.show()
    app.app.exec_()
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.