I'm working with QGraphicsView/Scene for the first time. This is in PyQt, but except for the fact that Python is different with multiple inheritance, I think this is a generic Qt question.
I started out by creating a couple of QGraphicsItem overloads as building blocks. Once I had those working the way I wanted, I wanted to try to combine them and was unpleasantly surprised to find that I couldn't use the in QGraphicsLayouts. This is due to the fact the QGraphicsLayouts take items that inherit from QGraphicsLayoutItem, and QGraphicsItems are inherited by QGraphicsLayoutItems, which are in turn inherited by QGraphicsWidgets.
There is a graphicsItem property of QGraphicsItem/QGraphicsWidget, but looking at the code, I don't think I can assign my Item's to this property and have them work properly. I did find this example, but strangely enough it has examples that inherit from both classes. Pretty confusing to me.
So I'm trying to find the easiest way to get my Items working in Layouts. Is there an easier way to do this than rewriting and inheriting from one of this two classes?
Secondary question, is there a rule of thumb for when you should inherit from QGraphicsWidget vs when you should inherit from QGraphicsLayoutItem?
Extra credit for explaining when sizeHint vs. boundingRect are used.
Appreciate the help,
Brett
The easiest way to get items working in layouts is to change the inheritance to QGraphicsWidget and override the setGeometry() and sizeHint() methods. Should be a simple change since your items will still be QGraphicsItems through the inheritance ancestry.
The Qt Graphics View framework is designed to be as lightweight as possible. Thus there are many choices for assembling items with different capabilities. If the sizes of items to be in layouts are not a concern, you can inherit from QGraphicsWidget. Otherwise, inherit from QGraphicsLayoutItem (unless you need the extra capabilities of QGraphicsWidget). Since you can't multiply inherit from PyQt classes, you'll have to use composition for creating an item controlled by the QGraphicsLayoutItem, like in the example you referenced.
The boundingRect() method is used by the scene to manage items. The sizeHint() method is used by the layouts to determine the size of layout items. The shape() method is used by the scene to more precisely determine the location of items (for collisions, hit tests, etc).
Related
Qt's widgets have 2 properties determining how small they can be:
minimumSizeHint
minimumSize
Now their basic difference seems clear enough: minimumSize restricts what size the widget can actually have, and Qt won't allow setting the size smaller. It also overrides minimumSizeHint, if set. And then minimumSizeHint is only used by layouts, which won't resize the widget smaller than that when resizing its contents.
Now I was implementing a custom widget, no problems there, and I started wondering about this.
Question: why would you ever want to use mininumSizeHint at all? What is the scenario, where you have to, or want to use it instead of just always using minimumSize? Why does minimumSizeHint exist?
(And if answer is "yeah, sizeHint is enough for everything", that's fine.)
I think the main difference is that minimumSize can be changed by any other object at any time, whether you like it or not, as all QWidgets have a public setMinimumSize() function; whereas your widget alone controls what is returned by minimumSizeHint().
As an implementer of a custom widget, you always want to override minimumSizeHint() if your widget has a minimum size that you think should usually be respected. This is what the built-in Qt widgets do.
We are building a flex project and would like it to render faster. We do have situations where we reference parent module size properties to size current module containers, as well as current module size properties for a bunch of attributes including font size and element positions and sizes.
Would it help to create temporary variables for
a) pcw=parentcontainer.width, pch= parentcontainer.height
b) ccw=currentcontainer.width, cch=currentcontainer.height
and reference to pcw,pch,ccw and cch while doing positioning. Will that help?
Also given the bulk of the positioning will be done in mxml, will setting these interim variables in initialization function, allow them to be used in mxml such that they will resize as browser size is changed. Thanks for pointers
I'm not sure if you're using the term "Module" a a generic term to refer to a component, or if you are explicitly referring to classes of the Module class.
It breaks encapsulation if a container is aware of it's parents. In Flex, a parent is always responsible for sizing it's children; and a child should never size itself.
You had code like this to access the parent's height and width:
pcw=parentcontainer.width
parentcontainer.height
I can't imagine how saving the parent's height and width values would speed anything up.
I also find it hard to envision a situation where knowing the parent container's width and height is helpful. Often a container has more than one children. It is important to know how much size a component has for laying out it's own children, not how much space the parent has.
The appropriate way to size and position a component's children is to override updateDisplayList(). updateDisplayList() has two parameters: unscaledWidth and unscaledHeight; that is, in essence, the height and width of the component. You should size and position the component's children based on those two values.
Of course, doing so often relies on ActionScript; not MXML.
Your primary question seemed to want to improve performance. There are many factors involved in the performance of an app. Using ActionScript for layout instead of MXML could be one factor that may help improve performance. Minimize your use on binding is another thing that can sometimes help performance.
Have you used the Flex Profiler? Have you stepped through code? Does doing these things help you determine what exactly the performance issue is?
Unless your application changes it's shape a lot, there shouldn't be any problems laying out with Flex if you use proper skinning/component/layout standards.
Most of the problem isn't from Flex, but the code most people add onto their own application that renders the whole system slow. Make sure you brush up on Flash performance improvements (like data structures, limiting binding, proper architecture, object lifecycle, etc).
On a form designed with Qt Designer, I have two QGroupBoxes with a bunch of controls in each of them. Both group boxes have nearly the same contents (QLineEdits with associated labels).
What I want to do, however, is to align the controls together, as if they were part of the same grid layout. But since they are in separate containers, they can't share the same layout, and I don't want to give them a fixed width.
Is there a way to do it in Qt Designer? If not, is there a way to do it in code?
Thanks!
There is no way to do this in Designer. As far as I know, Qt does not provide a good way to do this in code either. If you really want this, you will probably have to rely on something a little hacky.
Here's my first idea: Override resizeEvent() in the widget that contains the two group boxes to get the preferred size (via sizeHint() or minimumSizeHint()) of all of the labels and set the fixed width of all the labels to the largest preferred width.
I would encourage you to ask yourself if this really matters (is it worth the development time?) and consider whether you can avoid the problem entirely with a slightly different UI design.
BTW, you might want to take a look at QFormLayout if you haven't already.
What I'm trying to achieve is that a widget could exist in two different layouts, in this case in QHBoxLayout and in QVBoxLayout. I'm implementing a system which dynamically switches between the two layouts when a device's screen orientation changes.
Currently I'm creating, let's say a complex composite widget called MyWidget and adding it into a two different layouts:
MyWidget *wgt = new QWidget();
QVBoxLayout vlayout;
QHBoxLayout hlayout;
vlayout->addWidget(wgt);
hlayout->addWidget(wgt);
Now imagine that both layouts are hosted within a 'root' layout, and that this root layout can resize into a more wide than tall 'landscape' mode, and into a more tall than wide 'portrait' mode.
The MyWidget shows correctly in only the first layout it is added into, and when the layouts are switched, it shows all wrong or not at all.
I don't know if I'm making any sense here, but this is my problem. Maybe when the switch event is called all child widgets and layouts should be resized, so it would always look right. Only problem is that I don't know how.
This isn't a general solution for changing layouts, but an easy solution in your case: Just change the boxlayout's direction.
hlayout->setDirection(QBoxLayout::TopToBottom);
// now your hboxlayout works as vertical layout
hlayout->setDirection(QBoxLayout::LeftToRight);
// and now it is horizontal again
This isn't particularly easy to do, but is possible.
First of all, I'd recommend that you actually create two different widgets, one for the vertical and one for the horizontal, and manage things that way. If the source data is properly separated from the UI class, you should be able to do so without too much trouble, but by incurring some memory overhead.
One way to do as you desire would be to completely remove the widgets from one layout and add them to the other when you need to change the arrangement on the screen, and change the layout that is added to the widget. This should cause the same widgets to be drawn in a different way.
A different, more intricate way of handling this (although potentially more efficient) would be to write your own layout and have it handle rearranging widgets based on the orientation change.
I was told that there is an increase in performance when using Canvas versus HBox or VBox when laying out out the position of children. As a result, a number of our components have been converted over to using Canvas. However, now there is code being added to calculate the x and y positioning of some of the child elements based off of the width and height of other children. Is it worth using a Canvas to increase performance if code needs to be added to determine the coordinates/positions of the children? Is there a better method or technique available that should be practiced other than just minimizing the number of ui components added and specifying positioning absolutely?
There are a number of middle-of-the-road techniques, one of which is to use rendering-type components, such as TileGrid or ItemRenderers, if your layout fits a certain formula. If you're using forms, try using the Form layout component instead of using a custom layout.
If you do need to use the layout engine in Flex, the way to optimize your usage is to remember that certain techniques are used by the framework in increasing performance load, loosely following the below list, the last being the most performance intensive:
absolute positioning (<Canvas>)
relative positioning (<VBox>)
constraint-based positioning (right=0)
advanced constraint-based positioning (<constraintColumns>)
Using relative positioning is usually not that performance intensive. If you are finding that it is, it could be that you're using too many nested containers. Look at your layout architecture and try to find out ways in which your objects may be "over-laid out", and simplify them. A good tool for this is FlexSpy, which lets you introspect object layout at runtime.
Another common performance bottleneck is that your application is attempting to do some number-crunching at the exact same time that your GUI is attempting to respond to user interaction. Although no green threading frameworks exist at the moment which enable you to run UI and logic in separate 'threads', you can use a good architectural framework such as Cairngorm or Mate (there are many) which uses Commands instead of straight up methods, so that functionality execution which may take up processing cycles waits until the UI has finished responding to the user.
A couple things you want to keep in mind while optimizing a Flex UI:
Avoiding excessive nesting of containers. Consider using a Canvas with absolute or constraint-based positioning over nesting lots of HBox / VBox elements. However this doesn't mean you should NEVER use VBox/HBox. You can mix and match, such as using a Canvas as the main container and positioning child Boxes inside them as needed, just try to avoid too much nesting.
Using the UIComponent model properly in custom components. In particular, using invalidateProperties(), invalidateSize() and invalidateDisplayList() so that their companion functions (commitProperties(), measure() and updateDisplayList()) are invoked at an optimal time for the Flash Player. Deepa gives a great talk about this here:
http://tv.adobe.com/#vi+f15384v1002
She explains how making heavy use of the invalidation scheme allows the Flash Player to execute your code at an ideal time, i.e. not in the middle of a screen update. These principles are used by all Flex components and can/should be leveraged regardless of the framework being used.
To make sure I understand:
You heard that Canvas can position children faster than [VH]Box
Canvas only does absolute positioning
Some (many?) of your components have an absolute position, so you switched to using Canvas
But some of your components have a relative position, so you need to write code to position them
Is that correct?
Anyway, assuming I'm correct (which may not be the case), the first thing you want to do is pick the functioning interface which requires the fewest lines of code, then decide if it's "good enough". You want the one with the fewest lines of code because studies have shown that there is a correlation between lines of code and number of bugs (and you don't want bugs). You want to see if it's "good enough" because, if it IS "good enough", you don't need to do anything (if you do try and make it faster, you're committing Premature Optimization).
But that's probably not what you wanted to hear :)
So I'll also suggest that, if you want to stick with Canvas-based layout, you try sticking all the relatively positioned content inside [VH]Boxes, which are then absolutely positioned inside the Canvas. There's a good chance the code Adobe has written is faster than code, so you should try to take advantage of it.
But the only way to know for sure is to try it and profile it.