Qt paintEvent() unnormally triggered - c++

I'm a Qt beginner.
So I have my MainWindow with a QSlider and a QPixmap. I redefined the paintEvent( QPaintEvent* event ) and
connect( slider, SIGNAL(valueChanged(int)), this, SLOT(centerChange(int)) );
with a slot:
void MainWindow::centerChange(int value)
{
center = value;
update();
}
So I wanted repainte the Pixmap only if the slider's value is changed. But I notice that everytime when I make a mouse-in or a mouse-out to the slider, the repaint is triggered. Why is this happenning?
Thanks.

Paint event may be triggered at any time by the underlying Qt drawing system. You should not assume that paint event can be triggered only by you. You need to change the logic in your app.

The documentation says:
A paint event is a request to repaint all or part of a widget. It can happen for one of the following reasons:
repaint() or update() was invoked,
the widget was obscured and has now been uncovered, or
many other reasons.
(emphasis mine). Specifically, the underlying OS could trigger a repaint event whenever it feels like.

Based on your requirements, don't reimplement paintEvent then. Just do your QPixmap updating when the slider value changed.

Related

QWidget listening to other QWidgets events

To explain the situation, I have a QMainWindow with plenty of stuff inside.
My goal is to make some kind of a notification that appears at the bottom right corner of this window.
The notification widget must be over every other widgets.
So far I've created that Notification widget that inherits from QWidget.
By setting the QMainWindow as its parent I've got it 'floating' on top of every other widgets. It doesn't belong to any layout.
Now the big issue is to make it stick to the bottom right corner. I managed to place it manually but what I want now is to move it upon a resize event.
Unfortunately since it doesn't belong to any layout it doesn't receive any resizeEvent, so I can't overload the resizeEvent() function.
An attempt was to make the QMainWindow emit a signal in its resizeEvent method but I am not really happy with this method. Especially because in the Notification widget constructor I have this connect(static_cast<MainWindow*>(parent), &MainWindow::resized, this, &Notification::update_position);, and it kind of breaks the genericity of the widget since its parent must be a MainWindow widget.
So the question is how can one widget react to another widget event ?
In my case here how can the notification widget be notified when its parent is getting resized ?
And I forgot to mention that I don't want the MainWindow widget to know anything about this notification widget. The notification widget can be managed on its own. You just call something like new Notification(parent) and it will do its stuff on its own
Any ideas are welcome,
Thanks in advance :)
You can install the notification widget as an event filter for its parent, e.g.:
NotificationWidget::NotificationWidget(QWidget *parent) : QWidget(parent) {
parent->installEventFilter(this);
}
bool NotificationWidget::eventFilter(QObject *obj, QEvent *event) {
// normal event handling
bool ret = QObject::eventFilter(obj, event);
if (event->type() == QEvent::Resize) {
// Parent resized, adjust position
}
return ret;
}

How to stop a paint event from propagating?

I have two widgets, A and B, A has B as its parent.
Inside the A widget, I have a timer to trigger the repaint slot of itself. Thus, the paintEvent of widget A is triggered. However, I found B's paintEvent is also triggered. How could I trigger only A's paintevet?
I have tried to accept A's paintEvent as:
void A::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
paintA();
event->accept();
}
But it doesn't help. What should I do?
When a widget is sent a paint event, so are all of its enabled children. You can work around this by installing an event filter on the child widget and discarding any paint events you don't want.
You can't because Qt must do composition of the widgets.
Options:
Consider making the widget a non-child and display it as a separate "window". You can use Qt::FramelessWindowHint and Qt::WA_TranslucentBackground to make it look as a child widget. This option will give you perfect results as it leaves the composition to the underlying OS, which, at least on Desktop, will not repaint the bottom widget unless requested.
Consider caching. Use QPixmapCache to cache all drawing of your bottom widget to one window-sized pixmap, which will be very fast to draw when needed.

Qt QGraphicsview how to hook to resize event

we're working on a Qt C++ Widget project and recently ve'we run into trouble. We're Qt rookies.
On our widget there are two QGraphicsView which need to resize automatically when the window is resized (we've done that) and keep the content inside them resized/fit/scaled accordingly to...
So we've figured we need to somehow hook to onResizeEvent or find which slot does it. But we're somehow lost as to how to do it.
P.S.: Please excuse my english.
If you have a QWidget you only need to reimplement the resizeEvent function.
void QWidget::resizeEvent ( QResizeEvent * event ) [virtual protected]
In the Qt documentation you can find the scribble example for a full code example: http://doc.qt.io/qt-5/qtwidgets-widgets-scribble-example.html
Alternatively you can install an event handler and grab the QEvent::Resize.
How to install event filters is described here: http://qt-project.org/doc/qt-4.8/eventsandfilters.html
You can make your custom class which inherits from QGraphicsView. You should reimplement resizeEvent( QResizeEvent *event ) in your custom QGraphicsView like:
void MyView::resizeEvent(QResizeEvent *event)
{
fitInView(0, 0, 500, 500,Qt::KeepAspectRatio);
QGraphicsView::resizeEvent(event);
}
This way the view will always display the whole scene. I.e. if the window size is changed and the graphicsView is resized, The scene gets scaled and you can see everything appropriately.
If you are resizing in some slot then you can use sender().
Btw you can always use debugger or logs/backtraces to get such information.

Qt how to set global mouseReleaseEvent when i have pile of widgets

is there away to set global mouseReleaseEvent?
what i mean is i have QMainWindow and on it QFrame and init QListView and In it
i have Widgets that constarct the QListView and inside the widget i have al sort of lables and text fields.
so i want to detect mouseRelease any where in my app i have to implement in all widgets the mouseReleaseEvent?
void ItemWidget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
;
}
event->accept();
}
According to the QMouseEvent documentation, the widget that receives the mouse press will also get the mouse release. So, you shouldn't have to look any further for your mouse release than the widget that received the original press. This is usually referred to as a mouse "grab."
You may also want to check that Qt::WA_NoMousePropagation is not set on one of your children. If it is set, it will ensure that your mouse event does not bubble up.
If you really want to catch all mouse release events, you could try installing an event filter on the QApplication itself. That is a bit of a heavy solution, but you should get every mouse release event.
Looking at the (somewhat older) documentation here indicates that events are by default ignored by a widget and are propagated to their parents. So, if you make all your widgets children of your main application widget (or 'grandchildren', etc.) then you should only need to install the event handler on the application widget.

QGraphicsItem doesn't receive mouse hover events

I have a class derived from QGraphicsView, which contains QGraphicsItem-derived elements. I want these elements to change color whenever the mouse cursor hovers over them, so I implemented hoverEnterEvent (and hoverLeaveEvent):
void MyGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
update (boundingRect());
}
However, this event handler code is never executed. I've explicitly enabled mouse tracking:
MyGraphicsView::MyGraphicsView(MainView *parent) :
QGraphicsView(parent)
{
setMouseTracking(true);
viewport()->setMouseTracking(true);
...
}
Still, no luck. What am I doing wrong?
Fixed it. I need to use setAcceptHoverEvents(true) in the constructor of my QGraphicsItem-derived class.
In my case, hover events wouldn't work if I overrode mouseMoveEvent in my implementation of the QGraphicsView class. I fixed this by adding a call to
QGraphicsView::mouseMoveEvent(event);
which propagated the event to the parent, which in turn sent it out to all the scene items.