Search code examples
c++qtmodel-view-controllergraphicsrefresh

Refresh of a QGraphicsScene / QGraphicsView


I am troubled by the following:

I am working with an interactive QGraphicsScene that needs to render the graphical representation of an SQL query, based on the users' operations, such as: add something to the query (a table, a new column, something else) or remove something from the query (a keyword, a table, a column ...). The changes of the scene must be displayed after the operation, and also the "logic layer" of the application needs to track the operations the user did, since the "rendering" of the query is done by the "logic" layer (ie: the "logic layer" creates all the QGraphicsItemGroup derived objects which at a later stage, after all the logic layer components were built, are being added to the graphics scene of the query and put on the window).

The problem that occurs is the following: right now I did not manage to find any usable solution to present a query after a change in the smoothest possible way.

Allow me to link in a screenshot for further explanation:

Screenshot of the Query builder

Let's suppose the user wants to remove the PERSON.NAME column from the query. What happens in the application:

  • the user clicks on the "remove" (small red X after the column name) button of the PERSON.NAME columns' graphic item
  • the Graphics View senses this operation, sends the REMOVE column from the graphic system to the "logic layer" (the "model")
  • the logic layer on its turn removes the corresponding "logic layer" object representing the PERSON.NAME column,

And here the trouble starts:

  • the entire graphic (yes, everything) is re-rendered by the logic layer creating the graphic items for the same query, without PERSON.NAME
  • then I have to create a new window which has a new QGraphicsScene object together with a QGraphicsView
  • insert the re-rendered objects' graphic items representing the query, (but now without the PERSON.NAME column) into the new QGraphicsScene with addItem()
  • and now replace the central widget of the application with the new window.
  • and now you can see, that indeed, in the query the PERSON.NAME is not there anymore and all the graphic elements that were below PERSON.NAME were moved up on the screen.

Obviously this is not a good solution, there is an ugly flickering when I change the window, but I simply did not find a better solution to this problem till now.

So I am asking for your help in order to identify what improvements can be done to this methodology of updating the screen upon removal (addition) of a new element knowing the background information above, without a new window. Obviously other, mroe generic graphic related comments are welcome too.

Thanks,f


Solution

  • Based on the information from the question and the comments, a couple of things you could consider:

    First thing is that you need to get rid of creating a new Window and a new QGraphicsView when refreshing. I suppose this is the main reason for flickering. Keep your UI structure unmodified and only modify the scene. You could use one of these approaches:

    1. Either create a new QGraphicsScene and set it as the view's scene, or call clear() on the existing scene. Then recreate your QGraphicsItems from your native model and make sure that all your pointers and references are updated.

    2. Another approach would be to have the QGraphicsScene update your native model when something changes, to avoid the need to recreate the whole scene from scratch. For example, let the QGraphicsScene handle the deletion of the QGraphicsItem when the user clicks the delete icon, and then let the scene update your native model to reflect this change.

    3. Yet another approach would be to discard your native model, and use the QGraphicsScene with its QGraphicsItems as your model. Implement serialization etc. in the scene class. This avoids the need to synchronize the two models. The drawback is that your graphics independant logic is then much tighter coupled to the QGraphicsScene, which you might not want. Depending on your code size, this might also be a lot of work.

    I would start with 1., since it seems to be the easiest way to go based on your existing approach. If you still come across weird issues with pointers and object ownership, try to isolate them and ask on SO :)