I want to know how to retrieve all items rendered in the grid, specially their positions.
I fail to see in the documentation how I can achieve this. It seems there are multiple callbacks to react to certain events (drop, resize, etc...) but some are triggered multiple times when the widgets are moved and the order is not predictable either. That plus the fact the callback argument only refer to a particular item at a time, and not to the whole grid, makes really difficult to keep track of the grid state.
Thanks.
Related
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.
I'm having all sorts of size problems with Qt. I am creating my own widgets and using different layouts (generally, I need my own to make them work properly without spending hours on the "powerful" default layouts... which don't lay things out as intended.)
Once I'm done with a widget and its layout though, it doesn't work right. The size is never getting set properly unless I call widget->resize(1, 1); which finally forces a "resize" and makes the widget look correct (i.e. recompute the geometry.) Even the updateGeometry() call has no effect.
This is a dreadful problem when the resize() needs to be called on the parent widget (yuck!) and from what I'm reading should not be necessary were the layouts properly programmed.
Is there a sample that works and is not several thousand of lines long, or does Qt require several thousand lines to make anything work perfectly, even the simplest widget?
What are the minimal functions to be called to make a widget & its layout work at once?
Thank you.
Alexis
P.S. I tried to implement the sizeHint(), minimumSize(), maximumSize(), others that I'm missing? I was hoping that would be enough. Obviously, I also implement the setGeometry() on the layout to resize the children appropriately.
--- addition 1
There is a sample image with a layout that clearly isn't available as is in Qt. The positioning, functions, and colors of the different keys is XML driven and works for any keyboard in the world.
(note, this sample doesn't show the Enter key displayed on two rows and wider below than at the top; more or less, not doable at all with the regular layouts; of course, it works with my version.)
--- clarification
I'm not too sure how to describe the problem better. I was thinking to write a test widget next to see how I can reproduce the problem and then post that and eventually fix it. 8-)
The default layout function that the internal Qt layouts make use of require a lot of coding. I would like to avoid having to copy/paste all of that because for maintenance, it makes it close to impossible.
--- today's findings
As I needed to tweak one of the widgets, I decided to add a VBoxLayout and make it work.
I actually found the problem... One of the widgets in my tree is a QScrollArea and that sizeHint() returns (-1, -1). Not exactly what I'd expect but... whatever you put inside that widget has better know how to compute its width and height or else... it fails.
Looking at the code closely, I could actually compute the width by using the widest width found. Once I used that, the widget would appear (and it actually resizes itself as things change in the list, kinda cool.)
This being said, my earlier comment about having a tree of widgets that auto-resize themselves stands. From the root up to the parents of the leaves in your tree, all of those widgets will need a valid layout. Once I added one in the top widget it resized itself and its children properly (well... in my case up to the QScrollArea, the rest required a bottom to top resizing. Funny how that works!)
--- ah! ha! moment (or: what you find reading the implementation code!)
Today I bumped in another problem which just needed the correct call... I just couldn't find anything worth it in the documentation.
All the objects have a layout now, but a certain parent would not resize properly. Plain simple.
I had a call to the parent as following:
// changes to the children are changing the geometry
parentWidget()->updateGeometry();
Yeah. The docs says that's what you have to do. Nothing happens at all with that call. No idea what it's supposed to do, I did not look at that function. It never did anything for me anyway.
So... I looked at the layout to try to understand how it would send the info up/down. I did not see much except for one interesting comment:
// will trigger resize
This is said of the SetFixedSize mode. To reach that function you need to make the layout for update. Ah! Yes... the layout, not the parent widget... let's try that instead:
parentWidget()->layout()->update();
And voila! It resizes correctly in all cases I have. Quite incredible that the widget updateGeometry() doesn't trigger the same effect...
Although it's possible to do what you want it sounds like the problems you are having are because you're using Qt in a way that it's not meant to be used. Why do you need separate widgets for each key represented on the keyboard?
I see two options, both of which are better in some way:
Use QGraphicsScene and QGraphicsView.
A single custom widget that uses custom drawing to display the keyboard (and likely uses hover for hints).
The first option is probably better. Your keys could then be represented by QGraphicsSimpleTextItem's or even a QGraphicsSvgItem. It also provides a number of standard layouts or you could choose to write your own layout. By default you can use the keyPressEvent or mouseReleaseEvent to respond to user interactions.
I'd highly recommend you take a look at the QGraphicsView examples to get an idea what you can do.
If you go the second route you'll need to record the different key locations so you can respond accordingly as the user moves the mouse around, clicks, etc.
This won't help you with your immediate issue but I wanted to show you a keyboard I made using standard layouts and buttons. It's not perfect and it still won't help you with an enter key that spans two rows but it's not bad. It's resizable too by resizing the window, although I'm not sure if that will be apparent from the images below as SO may be scaling them. (you can view the actual images by opening them in their own tab)
Anyway, this was done using only Qt Designer with no manual coding. It consists of a top level vertical layout with 5 horizontal layouts in it. The buttons are then inserted into one of the 5 horizontal layouts. The size of the keys can be controlled by setting the horizontal and vertical size policies to "ignored" for most of the buttons and then horizontal "minimum" for buttons that you want to be wider. Things can be tweaked by setting min and max size restrictions to buttons. When resized, the buttons will not maintain their relative proportions though, that would probably take some custom programming.
The styling in your example could be approximated pretty well using css style sheets and background images. Still not a minor effort but you should be able to get most of the way there without custom layouts and buttons.
Greetings!
I've made a program that lets you draw shapes. All shapes are contained in a vector. What I need help with is; when several shapes are stacked on top of each other, I want to cycle through them, top to bottom, if the user clicks repeatedly. I'm thinking something along the lines of:
Store every object under the mouse location where the user clicked in some sort of container
Keep track of which object was first in queue, and should be last (?) after the next click
Repeat step two until the user clicks somewhere that results in a different queue
This is more of a general programming question, rather than just C++, but any help would be greatly appreciated, and if that answer also provides a pretty solution in C++, all the better!
A popular approach to this is to assign each item a z-order. Items with higher z-order hide items with lower z-order if they overlap. In your case, you would just have to find all items below the cursor and rotate their z-orders when the user clicks.
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
I used the owner-drawn strategy on CMyListBox class which derives from CListBox. I only want the DrawItem() method to perform when I insert an item in the listbox. But the method is invoked many times. How can I change to invoke it whenever I need.
You could always cache the initial drawing by outputting the content to an in-memory bitmap and then drawing that, it does mean you need to track when something has changed so you can run the actual rending code agaain. It does save running through your render code everytime if there's a lot of it.
I've done exactly what Kieron suggests by caching bitmaps, but only in very expensive rendering code. I actually have to keep multiple cached "states" depending on if an item is highlighted, disabled, normal, etc (this is for toolbar buttons, not listitem - but I think it applies). I only cache the pre-rendered image when I first need it - that way I only cache "states" that I actually need.
My drawing was pure GDI calls. Mostly bitmap manipulations and other drawing that just takes time, plus I was being redrawn much too often (for no good reason - long story).
Changing the fundamentals in the framework I was using (MFC and Stingray) was just not an option. The caching was a last resort after all other optimizations weren't good enough (damn slow virtual machines!!).
Normally drawing is fast enough to do when you're invalidated (DrawItem in this case). I would take a look at what exactly you're doing in DrawItem. I would look into caching data and calculations that are needed by rendering and not the rendering itself (eg the final bitmaps) unless there are no other options.
Also, I read the Vista rending is more optimized, they cache what you've drawn on your window to reduce the contain invalidate/redraw cycle when, for example, a window is moved from behind another.
The DrawItem() method is called whenever there is a requirement to draw any given item in the listbox. If you do not respond to it you are likely to get a blank area in your list box, where the drawn data has been erased and you have not refreshed it. If you really do not think the drawing is necessary, you could do something like
void CMyListBox::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
if (!m_DrawingEnabled)
return;
}
Where m_DrawingEnabled is a member you maintain to stop unnecessary draws,