draw qt widget bigger as the mouse hovers over it (overlapping of widgets) - qt

I would like to create a simple effect with my qt gui, but i have no idea how to achieve this.
I have several widgets, that i implemented as subclasses of qwidget. These are part of another widget and live in a layout. When the mouse hovers over these widgets, i want them to appear bigger to highlight the selected one.
This is what i already tried:
Override the paint event, and simply paint it bigger. But then, the other widgets that also live in the same layout overpaint the oversized areas.
I also tried to call the paint function "by hand" from the parent window, to get control over the painting order. But that didnt help either.
I think there has to be a possibility achieving this effect this qt, but i simply dont know how.
Any ideas?

You could either:
create your GUI inside a QGraphicsView, with QGraphicsWidgets and use setScale when the mouse enters or leave the widget, or
use QML.

Related

Qt/PySide: Linking the hover-highlight state of two widgets

I need a function that takes two Qt widgets and "links" them such that no matter which one the mouse is hovering over, they both get highlighted with their (standard) hover highlighting (if they have such).
This needs to work with whatever kinds of widgets the caller passes to this function; this function can't require callers to create widget subclasses just to make this work.
Here are some images of what I'm referring to:
Normally, when you hover the cursor over a widget, it gets highlighted as shown in Images 1 and 2. I need an example of how to set things up so that regardless of which widget the mouse is hovering over, they BOTH get highlighted with their standard hover highlighting, as shown in Image 3. Ideally, this function would work generically, only operating on its arguments as QWidgets, regardless of what kind of widgets they actually are (because hover highlighting is a generic Qt behavior, after all).
def link_highlighting(widgetA, widgetB):
... what should go here? ...
This feels like it would involve some pretty dark event hackery, but my event hacking fu is not strong.
Ideas? Suggestions?
I did a bit of research and I see two ways this can be done right now in a generic way.
The first part is detecting the hover action. This should be easy. Just subscribe to the enterEvent and leaveEnvent of both widgets. As long as they are of type QWidget this will work. With that you will be notified when the mouse enter or leaves a widget.
Then the highlighting part. Here you have two options:
You can fake a mouse event on the second widget, basically emulating a second mouse enterEvent. This can be done with qApp.sendEvent(widget, event).
You can change the palette of the second widget. Basically to set the normal palette to the highlighted palette. Here you would use functions like:
palette = widget.getPalette()
palette.setColor(QPalette.Base, widget.palette().color(QPalette.Highlight))
widget.setPalette(palette)
This obviously needs some experimenting. And for now this only works for widget styles that work with paletters. For the ones that work with CSS one would need to basically do the same. Find the bit that applies to highlight and copy it over to the normal state.
Depending on how general your case is, this could be really easy or very hard.
Let me know how this goes.

Qt: The best procedure to create own QGraphicsScene/s

I'm making fractal creator software. So I need one scene per fractal and these scenes need to be "layered" because of zooming rubber band.
I've already tried to write it the "widget" way, so I had one custom widget called "canvas". In my canvas class I overrided paintEvent, and inside this event I rendered current fractal. Everytime when somebody clicked to menu with another fractal, I called update() method and new fractal was rendered. To zooming I used overriding of mouse events and update() of canvas. At the first time I repainted the whole canvas, but it was very very slow. After that I repainted only the part under the rubber band, but still slow when I'd like to select some bigger area and other problems with repainting.
So I've looked for another way to do it. Layers. I've found the QStackedWidget, but I didn't find way how to make visible both of my layers and the top one to be transparent. After that, I've found QGraphicsScene and this seems to be the best way to do it. But I don't know the correct procedure to do it. Below are two procedures I'm thinking about:
Create QGraphicsView
Instead of the widget, the canvas will be QGraphicsScene
I'll override some QGraphicsScene event (but I don't know which one - drawItems() is obsolete and override update() seems wrong to me, but maybe...)
When other fractal will be chosen, I'll repaint canvas by calling update() the same way as in my "widget" solution
In the foreground layer will be zooming rubber band
or:
Create QGraphicsView
Instead of the widget, the canvas will be QGraphicsScene
Every fractal will be the child of QGraphicsItem
When other fractal will be chosen, I'll remove the old one fractal
item and replace it by new one and probably call invalidate()
In the foreground layer will be zooming rubber band - I think, that
it's common behaviour of the QGraphicsScene isn't it?
Is one of my reasonings correct? Do you suggest anything else? Fractals are complicated in the calculations and It's very important to repaint only if it is necessary. Could you help me, please?
Thank you :-)
Edit: "zooming rubber band" explanation:
I'm sorry for my expression "zooming rubber band". It means scale (zoom) the area below the selection made by the rubber band - zooming the same way as in Photoshop CS5 (for example). And I'd like to know what part of the scene is repainted while selecting this way. If there is repainted whole scene, or the part of the scene below selected area, or there is nothing repainted and rubber band selection is done in separate layer.
I hope my explanation helped :-).
In Qt, a QGraphicsScene can be thought of as a world of items, with a QGraphicsView as a window into that world. Therefore, you should be adding items to the QGraphicsScene, based on QGraphicsItem (or QGraphicsObject if you want signals and slots).
In your situation, I'd create a Fractal class that inherits from QGraphicsItem and add that to the scene. Ensure to override the necessary pure virtual functions such as boundingRect and paint.
Do not calculate the fractal code in the paint function. I suggest the Fractal class stores a QPixmap (or QImage if you're drawing at the pixel level) and render the fractal to this. Then perodically, in the paint function, the Fractal class would render the contents of the QPixmap with a call to painter->drawImage or painter->drawPixmap; whichever is relevant in this case.
As for zooming, your Fractal class can then response to being scaled, appropriately changing the rendering on the internal representation.

QWidget with movable/draggable children

I'm looking for an existing solution in Qt5 which would allow me to construct a QWidget with horizontal layout with some child widget which would be movable within parent widget area.
As an example of such behaviour you may try to play with tabs in firefox - user can drag a tab and move it right and left and other tabs are drawing aside to make a place for dragged one.
Also I'd like to be able to drag and drop child widgets from one parent widget to another, like in case of firefox: one tab can be dragged to another window. However in my case drag and dropping would occur in one application.
Is there such a solution or I've to do it myself?
I am using Qt4 but I am sure that the following should work for Qt5 too:
For moving tabs within tabwidget there is a API "setMovable (bool movable)" available in QTabWidget class.
To your other requirement you may need to do a little bit of coding. You should look into documentation of QDrag class and
examples of drag-drop in qt installation (examples/draganddrop) folder.
Santosh

Creating a permanent static overlay for QGraphicsView scene

I am making an app using Qt (currently 4.8) which displays a literal map from a large number of QGraphicsScene items. I would like to annotate the view with a scale. My requirement for the scale is that it is permanently fixed w.r.t the viewport widget. It needs to be updated whenever the view scale changes (zoom in, etc). There are other possible overlay items as well (compass, etc) so I'd prefer a generic solution.
I have looked at earlier questions around this which suggest:
using the ItemIgnoresTransform
using an overlay pixmap.
I tried IgnoresTransform but that way didn't work right: I couldn't figure out how to fix it in place in (say) the bottom corner of the viewport and was having some difficulty getting the text and lines always displaying in the correct size.
I scrapped that and subclassed QGraphicsView, adding an overlay pixmap by reimplementing the paintEvent (calls original one, then paints the overlay pixmap on top), and an alignment option to indicate where it goes. Coding some pixmap paint code produces a usable scale on the view. Yay! ... but it doesn't work with scrolls - I get "shattered" renderings of the scale all over, or sometimes no scale at all. I think this is because QGraphicsView::scrollViewportBy() uses viewport()->scroll() so I wondered if switching to ViewportSmartUpdate would help, but it doesn't help enough. I'd prefer not to switch to ViewportFullUpdate as that would likely slow the app down too much (there are millions of items in the scene and that would require a full repaint just to move around).
So. Any ideas from here? Would adapting my pixmap code to write to a new mostly-transparent Widget that is overlaid on the viewport be a better way?
Thanks for any help...
Though it may not be the best way of doing this, in the past I've added custom widgets to the window that holds the QGraphicsView / QGraphicsScene, which have the same graphic style as the QGraphicObjects in the scene. When the view is then used to move objects in the scene, or the scene itself, the items on the window remain in the same place.
Hope that helps.

Scalable painting of a Qt application

I'm writing a simulation of an embedded device's screen (which contains custom widgets on top of a main QWidget), and while the native size of the screen is 800x600, I want to be able to scale it up and down by dragging the window's corner. Without diddling with grid layouts and stretchers (which won't scale the fonts up/down), how do I accomplish this sort-of zoom? I think part of the solution might be to create a QTransform and somehow inject that into the QWidget for the entire application, or its QPaintDevice or QPaintEngine. I'd like to do this without putting QTransform in each custom widget, just the "main window" QWidget.
This is possible if you are using QGraphicsView as your main display widget. QGraphicsScene now supports widgets as content, so you can literally just scale them.
I believe the alternative is to reimplement the paint() for each widget, and manually set the transform/scale before the painting of child widgets.
Bit of a guess here as I've not tried it... but you could try putting the top-level widget into a QGraphicsView then get the QGraphicsView to do the scaling.
You could then enable OpenGL on the QGraphicsView and have it scaled in hardware so it's nice and fast.

Resources