Is there a way to get the repainted area in Qt? - c++

When calling update() or repaint() with no arguments, everything (including visible elements underneath) is fully repainted. This can be optimized by passing the ClipRect as a parameter.
Is there an easy way to get the repainted area or I have to determine it manually?
P.S. There is no such problem when using QGraphicsScene, however, I'm dealing with a QmlApplicationViewer and QDeclarativeItems. May be there is a way to force it to the same behaviour for it.

Is there an easy way to get the repainted area or I have to determine
it manually?
The QPaintEvent object that is passed in to paintEvent() contains rect and region members that you can examine to determine which part(s) of the QWidget in particular need to be repainted.

Related

Drawing outside of the QPaintEvent handler

We have big QT project where painting procedure often doesn't follow the rule that it should be done in overridden paintEvent method. As result we have warnings about it: Painter not active etc... But all work fine and at first glance I don't see any problems. Could you explain should I worry about it or not? What is the price of the incorrect use of this functionality?
Paint event is sended to the window when it is should be updated, eg when it is shown or something else. For example if widget is covered by another window, and this windows is moved away, then widget should be updated. Common way is to paint on the pixmap and draw this pixmap on the widget in the paint event handler. Or you can update/repaint each time you need to repaint it.
You can use QPainter to draw on pixmap, printer and so on whenever you want, but to draw on windget it must be done in paintEvent.
I found mistake - it is happened when invalid pixmap(I have created pixmap with size 0x0) is used. I have add check on it and now all are okey.

How to force Qt update the widget under mouse?

On Windows 7 to be specific, while I don't think it matters.
We have all seen this issue in countless desktop applications, especially games that tend not to use OS-supplied controls: when the screen changes programmatically under a motionless mouse cursor (as opposed to user moving the cursor to a new widget), they go out of sync. Either the cursor does not change or the widget is not painted as it should be with the cursor inside it - obviously the widget's mouse enter event is not triggered. If you shake the mouse a bit without even leaving the widget, the thing fixes itself.
Sadly, Qt 5.7 shares this widespread problem. The first solution to come to mind is to move the mouse programmatically to (0, 0) and back by Windows means. However, it's not cross-platform(ish). Any better ideas?
I don't know if your question is still actual
You can override method underMouse() with following code:
bool MyWidget::underMouse()
{
return rect().contains(mapFromGlobal(QCursor::pos()));
}
Events moveEvent or resizeEvent in the rest panels will be definitely triggered when splitter resizes panel. All you need is check if widget is under mouse and then invoke enterEvent() manually
I found two solutions.
The first one is a simple hack: Call widget->hide() and then immediately widget->show(). This will reevaluate and update the widget's visual state depending on whether it is under mouse cursor or not, even if the cursor has not moved. But I would not recommend this solution because it might have some unwanted side effects. Though I have not encountered any yet.
The second solution is better because it does not look like a hack and it probably does not have any side effects:
widget->setAttribute(Qt::WA_UnderCursor, qApp->widgetAt(QCursor::pos()) == widget);
widget->update();
The code is assumed to be called from widget's parent. But you can adjust it and calle it from any other place. Note: it is better to use QApplication::widgetAt() than widget->rect().contains(), which is suggested in another answers, because in the latter case we would get false positives for widgets which are overlayed by other widgets.
What is actually complicated, is to find the place in code from where you should call this. Because there can be many sources of the widget's motion - moving withing its parent, moving of parent(s), resizing, resizing of parent(s), scrolling etc. This is probably the reason why this would be too complicated to implement this to standard Qt widget library. It would be probably a performance killer in some scenarios. (my guess)
Just to show my usage: I am moving a whole container widget which contains many child widgets. Subsequently one of the child widgets may get under the cursor after the container is moved. So I call:
containerWidget->move(dx, dy); // this moves the container
for (QWidget *child : containerWidget->findChildren<QWidget*>())
{
child->setAttribute(Qt::WA_UnderMouse, qApp->widgetAt(QCursor::pos()) == child);
child->update();
}

Qt repaint paintEvent called but widget not updating

My paintEvent has access to a pointer whose value changes from time to time and what gets painted depends on these values. With basic debugging I'm sure that this function is being called but the window does not get updated. The new stuff only appears on the window when it loses focus to another application.
If this is about performance I can set a static variable in the paintEvent to check if the pointer has been updated or not to avoid unnecessary repaints. It would be nice if Qt would just paint when I told it to.
I was hoping someone could help me out or point me in the direction of the right documentation. Thanks.
you must call update() method to repaint your widget.

qt hiding a control on showEvent()

I call show() on a window and it has several controls and all controls are displayed.
One of the controls is a custom control that inherits from QFrame.
I want to hide this control if a particular flag is set. So, I have
void MyCustomControl::showEvent ( QShowEvent * /* evt */ )
{
if (!m_visibleAllowed)
hide();
}
While this hides the control, it makes the control goofy; it looks frozen. When the window is resized, the area where the control is supposed to be does not get refreshed. Searching around forums, the idea that I get is that hiding the control is not supposed to be done on showEvent() is that true? if so then how/where should I try to hide the control. If hiding the control from showEvent() is possible, how can I prevent the control getting frozen.
Thanks for you time.
If the problem is with calling hide() during your show event (I can't confirm that it's explicitly disallowed, but it doesn't sound like a good idea in general) and calling hide from your show event is where you really need to have this code then you could use a single shot timer:
QTimer::singleShot( 0, this, SLOT(hide()) );
which will simply defer the execution of the hide() function until the next round of the event loop.
Maybe you could use a QStackedLayout or a QStackedWidget that has two widgets in the stack: your control, and a "blank" QWidget. If you did that, instead of using show() and hide() on your control, you switch what's on top of the stack.
That way you never try to render a hidden widget - if your control isn't visible, you render the blank QWidget instead - and I suspect this will solve your graphics glitches.
Hope this helps!

QGLWidget not receiving calls to resizeGL after initialization

I am having what appears to be the same problem as asked in this (unanswered) question: Qt resizeGL problem
I am testing a new QGLWidget for a larger application. The resizeGL method is wired up to change the glViewport and repaint the OpenGL view. My QGLWidget is not part of a layout and is simply being created displayed as follows:
boost::shared_ptr<StandardCustomWidgetBuilder>
builder(new StandardCustomWidgetBuilder());
WaterfallDirector<StandardCustomWidgetBuilder, DataSource> director(builder);
director.construct();
std::unique_ptr<CustomWidget> widget = builder->getWidget();
widget->show();
On my computer, this defaults to creating a 640x480 window and calls resizeGL upon initialization. Whenever I resize the window, resizeGL is never called.
In my attempts to remedy this I have attempted creating a separate QWidget that has a QVBoxLayout containing only the CustomWidget. This created a very small window, so I fixed my sizeHint and sizePolicy for CustomWidget, though this still had no affect on having resizeGL called. At this point I'm not sure precisely how to proceed.
I resolved my problem with some help from my co-worker. As it turns out, I had implemented the event method and forgot to call the QGLWidget::event method inside it. The widget now correctly resizes.
If you haven't done so already, I would suggest checking the size hints and size policies of all widgets concerned.
For example, the following will make sure your widget uses available space when the window grows:
widget->setSizePolcy( QSizePolicy::MinimumExpanding,
QSizePolicy::MinimumExpanding );
I don't think that the default size policy for QGLWidget makes it want to expand, so I'm thinking it's just possible that this needs changing.