-->

Using Qt model/view framework to notify QGraphicsI

2019-08-20 02:28发布

问题:

I am trying to design a multiview application to use Qt's model/view framework so that I can move lots of complex logic out of my QGraphicsItem classes.

As shown in the figure below, the application consists of two (or more) views each containing of an identical series of red vertical guide lines A1 , B1, C1 ... at the same horizontal positions along each view.

I'd like to ensure that when the user drags a guide line one view, say from a point A1 to A_1' as shown in the figure above, all corresponding guide lines in the other views move by the same distance and in the same direction, for example from A2 to A2'. Also it should not be possible to drag one guide line past another i.e. guide lines must retain their relative orders. This is part of the logic that I would like to move out of my GuideLine class, into the model.

I know dragging guide lines triggers QGraphicsItem::itemChange, as shown in the snippet below. What I don't know is how best to

  1. Forward the candidate value to the model for validation (and storage). I am aware that the view is the interface "standard interface for interoperating with models through the signals and slots mechanism". The big problem, as I see it, is that QGraphicsItem::itemChange must immediately return validated value it cannot rely on the asynchronous signal-slot mechanism.
  2. Notify the guide lines in the other views of the change without triggering creating a cascade of notifications, for example where A1 and B1 endlessly notify each other.

-

class GuideLine( QtGui.QGraphicsLineItem ):
    ...
    # Called when item is about to change to value
    def itemChange( self , change , value ):
        # TODO 
        #  1. validate value in model
        #  2. if change is valid notify peers in other views
        pass

回答1:

QGraphicsScene and QGraphicsView could be seen as a model/view implementation where the scene would be the model and the QGraphicsView would be the view.

Two QGraphicsView can share the same scene and when you modify the scene from one view, the second one will be also updated.

A quick example:

if __name__ == "__main__":

    app = QApplication([])
    scene = QGraphicsScene(0, 0, 1000, 1000)
    view1 = QGraphicsView()
    view2 = QGraphicsView()

    item = QGraphicsRectItem(QRectF(0, 0, 40, 40))
    item.setFlag(QGraphicsItem.ItemIsMovable)
    scene.addItem(item)

    view1.setScene(scene)
    view2.setScene(scene)

    w = QWidget()
    layout = QVBoxLayout(w)
    layout.addWidget(view1)
    layout.addWidget(view2)
    w.show()

    sys.exit(app.exec_())

The rect item is movable and will move in the two views at the same time.