QPainter and paintEvent : what is the use of QPaintEvent *event? - c++

I have a school project involving creating a simple GUI and coloring graphs using a minimal number of colors. I am working with a classmate, and so far, we have laid out different ideas regarding how we will store the graphs in memory, and how to implement different coloration algorithms.
To create the GUI, we are using Qt, as I used it for another project before, it is free, and I generally find the documentation generally well detailed. Besides, I knew it had a drawing module, although I never used it.
After reading and the documentation and some examples, I was able to draw some basic shapes where I wished inside of a set area of a widget, and get them to correctly respond to resizing the widget.
To draw what I wish, I can write the paintEvent method this way, and just never use *event
void DrawArea::paintEvent(QPaintEvent *event)
{
//method body
}
Or I can write it this way, and it works too
void DrawArea::paintEvent(QPaintEvent *)
{
//method body
}
So, i have two questions :
How does the widget knows when to call the paintEvent method ?
If I'm not mistaken, every widget has a paint event, and I am
overwriting it ? If it's wrong please correct me, maybe that is the
reason why I don't really understand the way this pointer work.
What is the QPaintEvent pointer ? (I mean, what does it represent ?)
Thanks for any insight you may give me

So much text and so little questions...
You should learn about events handling in window systems (keywords are event loop, event queue and so on; in terms of Windows OS events are named "messages"). It is simple and useful thing to know.
In short, your program asks OS for new tasks time after time. If they exist, some information about it is provided, and you should handle them. Otherwise OS stops the program until such tasks will appear.
It means that OS notifies you to handle paint events when you are ready to do it.
QPaintEvent provides additional information about the event. At present it can give you a region to redraw. It may be used for painting optimization in some cases. But in simple cases it is not used.

Related

What is the correct way to display widgets without calling QApplication::exec()?

For test purposes I'd like to create and display a widget. For now I only need the widget to render correctly but in the future I may want to extend this so I simulate various events to see how the widget behaves.
From various sources it would appear that the following should work:
QApplication app;
QPushButton button("Hello");
button.show();
// Might also be necessary:
QApplication::processEvents();
But for me the widget does not render correctly. A window is created to display the widget, however it is entirely black.
I can get the widget to render correctly by adding the following lines:
std::this_thread::sleep_for(std::chrono::milliseconds(10));
QApplication::processEvents();
With 10 milliseconds being about the smallest time necessary to get the widget to render correctly.
Does anyone know how to get this to work without the time delay, or know why the delay is necessary?
To test Qt GUI application you need at least QApplication instance and event loop being processed. The fastest way is just use QTEST_MAIN macro, this answer explains in a nice way what it does exactly. However, to have more flexibility (e.g. to use GTest, GMock) you can also simply create QAplication instance in your tests main (no need to call exec).
Then, to have the events processed, you should invoke QTest::qWait. This will process your events for the specified amount of time. It is a good practice to use qWaitFor which accepts a predicate - this way you avoid race conditions in your tests.
In the particular scenario, when you expect some signal to be emitted, you can also use similar functionality of QSignalSpy::wait.
Small example when we want to wait until some parameters are passed from one item to another:
QSignalSpy spy(&widget1, &Widget1::settingsChanged);
widget2->applySettings();
ASSERT_TRUE(spy.wait(5000));
// do some further tests based on the content of passed settings
Why don't you want to have the application run exec ? The process of displaying a widget is not "static". You don't "draw" the widget on the screen, but rather you have an application that listen for various events and receives draw events from the windowing manager. The application can only draw the widget when the windowing manager asks it to.
The reason your second code works is that you wait sufficiently long for the windowing manager to have sent the "draw" request in your conditions. This does not guarantee it will always work.
If you want to guarantee the display of the widget, you need to start a loop and wait until you have received at least one draw event, but even that isn't foolproof.
As expertly described by Vincent Fourmond, widgets are not a one-off deal. The GUI is non-blocking and for this, it needs to run in an event loop.
The exec() method starts this event loop which you mimicked by polling.
While it is possible to combine Qt's event loop with other event loops, I would recommend you a simpler solution:
Proceed your program within the event loop by calling a method when it starts. Find an excellent answer here on how to do this: https://stackoverflow.com/a/8877968/21974
As you mentioned unit testing, there is also a signal you can use for doing checks at the end of the lifecycle (before widgets are destroyed): QApplication::aboutToQuit. This will happen when the last window is closed (programmatically or by the user).

QT Managing OpenGL context in a separate thread

I have learned about setting up separate rendering thread for Qt QGLWidget here ,here and here .
I also managed to get a kind of "working" setup: clearing color in the viewport.Seems to be ok.But I am getting the following warning:
QOpenGLContext::swapBuffers() called with non-exposed window, behavior
is undefined
I first create a widget that inherits from QGLWidget.Where I also setup OpenGL Format:
In the Widget constructor:
QGLFormat format;
format.setProfile(QGLFormat::CompatibilityProfile);
format.setVersion(4,3);
format.setDoubleBuffer(true);
format.setSwapInterval(1);
setFormat(format);
setAutoBufferSwap(false);
Then I init the rendering thread in the same Widget:
void GLThreadedWidget::initRenderThread(void){
doneCurrent();
context()->moveToThread(&m_renderThread);
m_renderThread.start();
}
and from that point the whole rendering is done inside that thread:
RenderThread constructor:
RenderThread::RenderThread(GLThreadedWidget *parent)
:QThread(),glWidget(parent)
{
doRendering = true;
}
RenderThread run() method:
void RenderThread::run(){
glWidget->makeCurrent();
GLenum err = glewInit();
if (GLEW_OK != err) {
printf("GLEW error: %s\n", glewGetErrorString(err));
} else {
printf("Glew loaded; using version %s\n", glewGetString(GLEW_VERSION));
}
glInit();
while (doRendering){
glWidget->makeCurrent();
glClear(GL_COLOR_BUFFER_BIT );
paintGL(); // render actual frame
glWidget->swapBuffers();
glWidget->doneCurrent();
msleep(16);
}
}
Anyone can point out where is the issue?And if that message can be discarded? Also a straightforward and concise explanation on render thread setup in Qt would be extremely helpful.Using Qt 5.2 (Desktop OpenGL build)
With what you've shown, it looks like that message handler warning you were getting was because you started triggering buffer swaps "too soon" in the window setup sequence, either directly through QGLContext::/QOpenGLContext::swapBuffers() or indirectly through a number of possible ways, none of which are really detectable outside of manual debugging. What I mean by too soon is before the widget's parent window was marked "exposed" (before it was being displayed by the windowing system).
As far as whether the message can be discarded, it can...but it's not safe to do, as in it's possible to get undefined behavior for the 1st few frames or so where you do it and the window's not ready (especially if you're immediately resizing to different extents at startup than your .ui file specifies). Qt documentation says that before your window's exposed, Qt has to basically tell OpenGL to paint according to what are effectively non-trustworthy extents. I'm not sure that's all that can happen though personally.
With the code you showed, there's an easy fix--avoid even starting your render logic until your window says it's exposed. Detecting exposure using QGLWidget isn't obvious though. Here's an example roughly like what I use, assuming your subclass from QGLWidget was something like 'OGLRocksWidget', it was a child of a central widget, and that central widget was a child of your implementation of QMainWindow (so that your widget would have to call parentWidget()->parentWidget() to get at its QMainWindow):
OGLRocksWidget::paintGL()
{
QMainWindow *window_ptr =
dynamic_cast<QMainWindow *>(parentWidget() ? parentWidget()->parentWidget() : 0);
QWindow *qwindow_ptr = (window_ptr ? window_ptr->windowHandle() : 0);
if (qwindow_ptr && qwindow_ptr->isExposed())
{
// don't start rendering until you can get in here, just return...
// probably even better to make sure QGLWidget::isVisible() too
}
}
Of course you don't have to do this in your implementation of QGLWidget::paintGL(), but in your particular setup you're better off not even starting your render thread until your window tells you it's exposed.
It looks like you have might have slightly bigger problems than that though. You weren't hooking the right GL activity into the right places in your code vs QGLWidget's intent. I feel for the position you were in because the documentation on this is a little spotty and scattered. For that part, QGLWidget's detailed description down where it says "Here is a rough outline of how a QGLWidget subclass might look" is a good place to start getting the idea. You'll want to override any of the key virtuals in there that you have related code for and move them into those calls.
So for example, your widget's constructor is doing setup work that is probably safer to put in an initializeGL() override, since QGLWidget's intent is to signal you when it's safely time to do that through that call. What I mean by safer whenever I say that here is that you won't get seemingly random debug exceptions (that in release builds can silently wreak havok on your runtime stability).
Side advice: install Qt source, point your debugger at it, and watch your code run, including into Qt. Your setFormat() call, last time I watched it, actually deletes the current underlying QOpenGLContext. That's probably good to know because you'll want to create a new one soon after or at least test out your options.
The risk of instability is why I'm trying to put together at least some kind of answer here a year later. I just learned this through a lot (too much) debugging. I love what the Qt team's done with it, but Qt will be much better off when they finish migrating everything over to QOpenGL* calls (or wherever they see a final proper place for their OpenGL support including permanent considerations for it and windowing support together).
A QOpenglWidget comes with its own context. If you want a background thread to do the rendering, you have to pass a shared context to the thread and do a few steps correct.
Details in: https://stackoverflow.com/a/50368372/3082081

Implementation of glutdisplayFunc()

I've used glutdisplayFun(void(*func)) in several of my program to sets the callback display to the current window.And by the use of it, i've rendered different things on the screen. By looking at the documentation of glut, passing null to it is illegal and we can't deregister it also.
The problem is that as we can't deregister it and i write a set of code to display the mainmenu(i.e as shown in the game). And i like to change to next window on the keypress(i.e play the game by clicking on the option play present in the mainmenu).
How to make the glutdisplayfunc call to the mainmenu inactive and and to set the glutdisplayfunc() for calling the next window.
std::%something%<std::function<void(void)>> displayFns;
void myDisplayFunc() {
for (auto& displayFn : displayFns)
displayFn();
}
Now register myDisplayFunc to GLUT and change the displayFns collection.
As for something, map<int, function<...>> would be a good start. Unordered map if you can guarantee your code doesn't need to be called in order. It starts to resemble good old BASIC times with line numbers, but I said upfront it will be a simple answer.
That's not how I would do it, but should do the trick for a quick'n'easy solution.
Funny thing with this is that you can create sets of those to have one element appear in more than one choice rather easily. So maybe it's not that bad after all.

Qt4: Making fullscreen window impossible to get around (a lock screen)?

My application is an OS lock screen (like GDM's lock screen or KDE's), so I'm trying to make it function like one.
I am trying to make my application's window hover above all other windows and disable/intercept all keyboard shortcuts (ALT-TAB, CTRL-ALT-D, etc.) that would cause it disappear.
Is there any way to do this? I'm 100% sure there is, as lock screens with GUIs exist, but I just can't find the place to look...
I don't know how to do it with Qt, but what you are looking for is called grabbing. You can grab the pointer input device as well as the keyboard.
Edit: Looking in to the Qt4 docs, have you tried to use QWidget::grabMouse? It looks like this function does exactly what you want.
I don't know if this is the best solution, but you can try an event handler using QObject::installEventFilter().
If you are using Windows, you can install an event filter that handles messages where event->type() == QEvent::WinEventAct.
I don't really know much about other OSs, but Qt probably has something for that too.
inherit Qwidget class with parameter Qt::WindowStaysOnTopHint see below
myclass::myclass(QWidget *parent) : QWidget(parent,Qt::WindowStaysOnTopHint)

How to mix C++ and external buttons on seperate window?

I want to make a C++ button on Start>Run i.e but when I do it will not do signalled event?
Im sorry I have seen that you do not get the question.
Ok basically when you create a button with CreateWindowEx(); I want to do that but put on a different window with SetPArent which I have already done now the button does not work so I need my program to someone get when it is clicked from the Run window as example!
And yes you have it, but it's not making the button is the problem it's getting when it's clicked with my program since it does not belong to it anymore!
You need to apply the ancient but still-supported technique known in Windows as subclassing; it is well explained here (15-years-old article, but still quite valid;-). As this article puts it,
Subclassing is a technique that allows
an application to intercept messages
destined for another window. An
application can augment, monitor, or
modify the default behavior of a
window by intercepting messages meant
for another window.
You'll want "instance subclassing", since you're interested only in a single window (either your new button, or, the one you've SetParented your new button to); if you decide to subclass a window belonging to another process, you'll also need to use the injection techniques explained in the article, such as, injecting your DLL into system processes and watching over events with a WH_CBT hook, and the like. But I think you could keep the button in your own process even though you're SetParenting it to a window belonging to a different process, in which case you can do your instance subclassing entirely within your own process, which is much simpler if feasible.
"Superclassing" is an alternative to "subclassing", also explained in the article, but doesn't seem to offer that many advantages when compared to instance subclassing (though it may compared with global subclassing... but, that's not what you need here anyway).
You'll find other interesting articles on such topics here, here, and here (developing a big, rich C++ library for subclassing -- but, also showing a simpler approach based on hooks which you might prefer). Each article has a pretty difference stance and code examples, so I think that having many to look at may help you find the right mindset and code for your specific needs!
OK, I'll do my very best - as I understand you, you're trying to inject a button into some existing window. That meaning: Your tool creates a button in some window that does not belong to your application. Now, you want to be notified when that button is pressed. Am I correct so far?
To be notified about the button being pressed, you need to get the respective window message, which will only work if you also "inject" a different WndProc into the window. Actually I have no idea how that should work, but I faintly remember functions like GetWindowLong and SetWindowLong. Maybe they will help?
EDIT
I've searched MSDN a little: While you can get the address of a window's WndProc using GetWindowLong, you can not set the WndProc using SetWindowLong on Windows NT/2000/XP (and up I suppose). See here (MSDN).
So what you could do is install a global message hook that intercepts all window messages, filter those for the window you've injected the button into and then find your message. If you have trouble with this, however, I'm the wrong person to ask, because it's been years ago since I've done anything like that, but it would be stuff for a new question.
EDIT 2
Please see Alex Martinellis answer for how to define the hook. I think he's describing the technique I was referring to when I talked about defining global message hooks to intercept the window messages for the window you injected your button into.