Is it possible force Qt to call paintEvent after other Qt components are drawn? - c++

I've a class that extends QWidget and contains a QLabel (lblBackground). I've overriden paintEvent function too.
I want to draw something on top of lblBackground however paintEvent method is called before the QLabel is drawn. Thus my custom drawings are overwritten.
Is there a way to change drawing order?

Painting the children on top of their parent is the common thing to do. That being said you could try one of the following options:
extend QLabel itself to paint whatever you want
try to set the Qt::WA_TranslucentBackground flag on the QLabel and having an alpha channel, so that the underlying parent (QWidget) would shine through
if you are only using the QLabel to paint some background, maybe you can get rid of it and paint the desired background first thing in the QWidget's paintEvent()?

If you want to use label as a background then just create your custom widget as a child of your label. May be split some window frame related tasks if any (to be implemented as a parent of the label) and drawing/controls/etc (to be child of the label).

Related

How to draw a QQuickItem on a QQuickItem

I have two QQuickItems and I would like to draw one on top of the other in C++ before it is exposed to QML. I would like to do this because I want the second QQuickItem (which I would refer to as background QQuickItem from here on) to act as the background of the first QQuickItem (which I would refer to as parent QQuickItem from here on) and then draw a QPixmap (which has been painted on using QPainter) on top of both items. I would also prefer to pass in the second "background" QQuickItem as a property to the first QQuickItem so that it can be set dynamically from QML. Does anyone have any idea on how to do this?
I would like to mention that both QQuickItems have implementations of QQuickItem::updatePaintNode(). Is there a way to make them work together?
To do that, you have to use the visual parent property (note that in c++ you access it with setParentItem() and parentItem(), not parent() which is for the QObject parent).
If you want to have a background property, I guess you don't want to have your background as the parent of your item, so you could instead set yourself as the parent of the background and set the background's z to -1 so it paints behind your item.
Alternatively, and that's what Qt Quick Controls 2 do, you could have a QQuickItem painting nothing and just be a parent for your background and your content item (QQC2 controls expose their contentItem as a property but you don't have to).
For some inspiration you can check the source code of QQC2's Control here : https://code.woboq.org/qt5/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp.html
Don't forget to handle the resizing of your background to the size of your item.

How to use QImage and mousetracking event at the same time in QT?

I am starting to use Qt and I am trying to do an application that uses mouseEvents on a picture QImage. Since I know that QImage is part of QPaintDevice and mouseEvents is part of QWidgets, I don't know how to use both on the same class or even if it would require me to make two independent widgets and overlap them on top of each other. I tried with pixmap, but it is not the best choice since I need pixel manipulation.
Evaluate mouse position/events in a QWidget. Draw the image on that QWidget either in a paintEvent or simply by placing QLabel with an image without margins/borders on that widget.
When the image is not scakled, you can calculate the pixel position having the mouse-position within the image.
I think the simplest way to start is to derive your widget from QLabel and overwrite required mouse events. The offset to the pixel is the contentsRect-position

QDockWidget::background-color not applied when docked

I have a QDockWidget:
I would like to alert the user to certain events by setting the background color of the title bar.
I have achieved this by setting the style sheet for my DockWidget:
void DockWidget::setCriticalAlert()
{
setStyleSheet("QDockWidget { background-color:red; }");
}
The result is this:
The problem is that the background-color doesn't get applied when the QDockWidget is docked:
How can I get the background color to be applied when the QDockWidget is docked?
This is a bug in Qt.
Issue 10537
Quoting from the linked issue:
The problem is that in QDockWidget::paintEvent, there is a
isFloating() condition before drawing PE_FrameDockWidget. We cannot
jsut remove this condition as it would break the other style (that
does not whish to draw frame when the dockwidget is docked) We cannot
either use PE_Widget to draw the frame as then it goes over the
dockwidget's title The solution is maybe to introduce a new
PE_FrameDockWidgetDocked primitive element. Or some
SH_DockWidget_DrawDockedFrame stylehint to draw the frame in every
cases.
a valid workaround seems to be to set the stylesheet of the parent, and use the class-and-id selector. Forgive the python formatted code but the concept is the same - in this case, 'dock' is a QDockWidget which has been given an object name using setObjectName(), and its parent, the QMainWindow, is 'self':
self.setStyleSheet("QDockWidget#"+str(dock.objectName())+"::title {background-color:red}")
In PyQt5.5, this works at runtime, i.e., can be changed on the fly.
I find a solution like this:
Firstly put a frame behind all the widgets of dockwidget's center widget, as the background.
Then set stylesheet for the frame.
By this way, we could change the background color of dockwidget.
Or you can extend the dockwidget and overwrite the function
void QDockWidget::setWidget(QWidget *widget)
using private/qdockwidget_h. and add a frame as this widget's father.

How can I create a QPushButton with a custom (triangular) shape in Qt 5.5?

How can I create a triangular pushbutton in Qt? What is the most simplest way of executing this? I use the designer to create buttons and not code.
Also, I read somewhere that shapes may be changed as long as the frame of the button is still rectangular but I want the frame to adjust according to the shape as well. How can I achieve this?
More detail: I want to place lots of small triangular buttons next to each other with every other triangle flipped. Each triangle button has it's own function, etc (no overlapping borders accepted). Can anyone give me a descriptive explanation for how I might go about this?
The geometry on a QWidget is always a rectangle.
It would be possible to create a QPushButton derivative, override its paintevent and do some nasty painting considering its neighborhood etc. but it would be really a pain...
it is much easier to use a QGraphicsView, QGraphicsScene and add appropriate QGraphicsItem (maybe the QGraphicsPolygonItem?), add them and use their signals/slots or create a derived class for your purposes.
It is not that hard to override the mouseevents to recognize clicks and you can even use the QStyleSheets to let the "button" look like it gets pressed.

How to paint with QPainter only after a specific event?

I have a main window with some widgets on it, each needs its own graphic. I would like to use QPainter to draw shapes, lines, etc. on them, but only after a specific event, like the press of a button.
The problem is, if I just create a QPainter in any function, it won't work:
QPainter::setPen: Painter not active
The QPainter methods can only be called inside a paintEvent(QPaintEvent *) function! This raises the following problems:
I have to derive my custom classes for all the widgets I would like to paint on, so I can't use the Designer to place my widgets. This can get frustrating with a large number of widgets.
The widgets redraw themselves after each paint event of the window, like moving it around, or moving other windows in front of it. I do a lot of drawing in those widgets, so they will visibly blink in these cases.
Is there a better and simpler way to solve this? I started to think about just displaying images, and re-manufacturing those images only when the specific buttons are pressed. I doubt that it's the most elegant solution...
You can use custom widgets in the designer: Creating Custom Widgets for Qt Designer.
Qt Designer's plugin-based architecture allows user-defined and third party custom widgets to be edited just like you do with standard Qt widgets.
For your second question, one of the approaches is to create a QPixmap for each of your widgets. When your widget's appearance needs to be changed, you draw in that pixmap (using QPainter's constructor that takes a QPaintDevice - QPixmap is a QPaintDevice).
In your widget's paintEvent function, you simply fill your widget with that "cache" pixmap. This way, you only do the (potentially expensive) painting when it's actually necessary.