Two qGraphicsScenes Vs. one qGraphicsScene + duplicate items - c++

I have a QGraphicsScene and a QGraphiscView. I have many items in the scene, with the behavior defined for each item sets. I call this normal mode. So in normal mode I can interact and see the items in the scene from the view.
I want to create a X-ray mode, which basically means the position of all items in the scene is the same, but items and behaviors are different.
The question is which of the following is the better approach (or there is even better one) to switch between modes:
Create a new scene, add items to the new scene on the same position as the old scene. To switch to x-ray mode, put view(scene) to the new scene.
Keep only one scene, add items to the normal scene, but for switching to X-ray mode, only hide/show items.
From ease of implementation, efficiency and speed, which option is better? Is there any built-in options in Qt to do this?

Related

Is it not possible to have multiple objects in Qt being painted simultaneously?

I read the following in the Qt Documentation.
Qt documentation on QPainter
The original question on SO, that I looked into.
So, I had two classes, with their own paint() functions. The paint functions would be called upon receiving their respective paint events, that were triggered on different and independent actions by the user. This worked fine.
Now for some reason, I need to show and update both the objects at the same time.
So simply, adding both of the items to the scene does not work. Only one of them is shown and updated. Refactoring the code is not an issue for me. I can re-arrange the two classes so that they are both drawn from one paint().
But this really makes me wonder then, and this is my question (for which I've googled a bit too), how are scenes with many dozens of objects then painted simultaneously (at least they give an illusion of concurrency)? Using threads somehow or through some time-based interleaving?
Maybe it's a silly question. I dunno.
It is indeed a silly question about an imaginary problem that doesn't not exist in reality. The graphics view will schedule consecutive draws for the items in the order needed to produce the desired result. Now if your code doesn't implement the desired result, that's a whole different subject. There is no concurrency, those are consecutive operations that only take place in the main thread.
If your drawing is very complex, draw using a secondary thread on a QImage and use the QImage as cache to draw your items in their respective paint functions.
Now for some reason, I need to show and update both the objects at the
same time.
What might that reason be? What does "at the same time" mean? In a single frame? Is a millisecond apart too much to qualify for "at the same time"?
Re QWidget painting: The paint events are delivered to individual widgets by the widget compositor. The way it works with the default raster back end is as follows: The topmost widget in the hierarchy is backed by a QImage. When any of the sub-widgets are to be repainted, the compositor delivers composite paint events to the widgets that overlay the area to be repainted. This is done sequentially as the compositor traverses the widget graph.
Re QGraphicsItem painting: The paint "events" are delivered to individual items by the scene. The items to be painted are selected basing on what area needs updating, what items were explicitly marked for update, etc. The painter is set up to correctly composite the item with the rest of the scene. The calls to paint are done sequentially as the scene traverses the item graph.
It would be, in general, impossible to do these in parallel due to data dependencies, and the fact that there are no requirements for the paintEvent or paint to be thread-safe.
Your problem is not directly related to this at all, you need to show a complete code example that reproduces your issue. Most likely your implementation of the item ignores some of the requirements for the item's behavior.

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:
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
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:
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.
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.
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 :)

Efficient method for finding object in map based on coordinates

I am building an editor using C++/Qt which has a click-and-drag feel to it. The behavour is similar to schematic editors (Eagle, KiCAD, etc), Microsoft Visio, or other programs where you drag objects from a toolbar into a central editing area.
My problem is that when the user clicks inside the custom widget I want to be able to select the instance of the box-like object and manipulate it. There will also be lines connecting the boxes together. However, I can't decide on an efficient method for selecting those objects.
I have two main thoughts on how to do the programming for this: The first is that the widget which is drawing the entire editor would simply encapsulate every one of the instances of the box. The other is to have each instance of the box (which is in my Model) carry with it an instance of a QWidget which would handle rendering the box (which would be in my View...but it would end up being strongly attached to the model). As for the lines connecting them, since they don't have a square bounding boxes they will have to be rendered by the containing widget.
So here is the summary of how I see this being done:
The editor widget turns into a container which holds the widgets and the widgets process their own click events. The potential issues here are that I don't know how to make the custom widget turn into a layout which lets click-and-drag functionality.
The editor widget takes care of all the rendering and processes the mouse clicks (the easier way in that I don't have to worry about layout...its just selecting the instances efficiently that I don't know what would be best).
So, now that there is a bit of background, for the 2nd method I plan on having each box-like instance having a bounding rectangle and the lines being represented by 3-4 pixel wide bounding rectangle segments (they are at 90 degree angles). I could iterate through every single box and line, but that seems really inefficient.
The big question: Is there some sort of data structure I can hold rectangles in and link them to widgets (or anything else for that matter) and then give it two coordinates (such as mouse coordinates) and have it spit me out the bounding box or linked object that those coordinates are inside of?
It sounds like your real question is about finding a good way to implement your editor, not the specifics of rectangle intersection performance.
You may be interested in Qt's "Diagram Scene" example project, which demonstrates the QGraphicsScene API. It sounds like a good fit for the scenario you describe. (The full source for the example ships with Qt.)
The best part is that you still don't have to implement hit testing yourself, because the API already provides what you are looking for (e.g., QGraphicsScene::itemAt()).
It's worth noting that internally, QGraphicsScene uses a simple iterative method to perform hit tests. As others have pointed out, this isn't going to be a serious bottleneck unless your scenes have a lot of individual items.

Question regarding image tiling in a QGraphicsView

This is related to one of my other questions.
If I am tiling a large image by creating a separate QGraphicsItem (with the raster data as its pixmap), how do I keep track of the QGraphicsItem's position within the scene? Obviously for raster data, it is important to keep all the tiles "touching" to make a continuous image and they also have to be in the right place so the image doesnt look jumbled.
Does each tile have to have positioning methods that move it in relation to it's neighbors on the top/left/bottom/right? This seems kind of clunky. Is there a better way to make them all move together?
In other words, if I pan the scene with scroll bars, or pick up the image and drag/move it around in the scene, I want all the tiles to also move and stay in the right position relative to each other.
What is the best approach for controlling the layout, which tiles need to be rendered (i.e. only the visible ones), and populating the data only once it is needed? Also, once a tile has been rendered, is the data from it ever dropped, and repopulated from the image file, say if it stays out of view for a while, then comes back later if someone pans to that section?
There are (more than) 2 ways of doing this:
Use QGraphicsItemGroup which
handles grouping of your tile items
for you. It moves, selects, updates
it's group members as if they are
one. I've never used it but from the
doc, it seems to work with typical
applications.
Paint the tiles yourself in the
paint() of one custom item. This
gives you total control on how to
place and draw the tiles while the
item truly acts as one item since it
is, well, one item. This is what I
do.

How to display scrollbar for a list view whose contents keep changing?

I have a ListView-like control that displays a list of items of various heights. The contents of the list, and the heights of the items can change – a background thread is populating the list and calculating the layout of each item, possibly even while the user is scrolling the content.
Which brings me to my question: How do I display a useful vertical scrollbar for this view? I’ve seen cases (notably web browsers) where the slider “jumps away” from the mouse cursor while the user is dragging it, the result of the underlying content growing in height. I don’t want that.
So far
Instead of the slider representing the viewport height relative to the content height, maybe it could represent a point in a timeline instead? (The items are sorted by timestamp). This would at least prevent the scrollbar from changing as item layouts are calculated.
Get rid of the scrollbar altogether and use a forward/backward rocker switch like the one used in Picasa (the further the slider is pulled upwards or downwards, the faster the view is scrolled, until the user releases the slider). If I take this route, are there any controls you can recommend?
I am using Qt, but this applies to UI design in general.
IMO the fundamental problem with a classic scrollbar is that due to background population, the valid range is changing - and thus, the meaning of a scrollbar position changes.
If you can predict the full range of items, you can still provide a scrollbar and replace yet-unknown items with "loading...".
Otherwise, a rocker (is that an official name?) would be the next best thing to use.
However, since you have a dedicated scale (timeline), it might be better to have separate buttons that jump a dedicated time (e.g. one minute, one hour, one day, ..). For a fancier look, you could create a rocker with "hot" areas that jump for a specific time, whereas the areas inbetween are interpolated (linear or or logarithmic, depending on the scale to cover).
i.e. line this (drawing just the "backward" half):
--------------------------
|##|XXXXXXX|##|XXXXXXX|##|
--------------------------
-1h -1m -1s