Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
How do I create an SDL2 application, which is event based? (C++)
My current model has an update loop, which just polls input devices, right when I need them, or just leave them alone if the logic does not need it.
However I want to move to an event driven model, however there are a lot of systems which don't update on some event, just update on every tick of the update loop.
How do I deal with these?
Do I add a new thread and interrupt the update loop somehow, when I receive a new event?
There are many ways to implement what you're trying to do, one way I can think of is an events dispatch system. Suppose you have an event manager. Your application can register various handlers for various events with the event manager. Your event manager would listen/poll for events, it then dispatch (call handlers to those that matches the event). Your event manager would have a lookup mapping to keep track of all the handlers to corresponding event type.
To do event-based programming in SDL2, you need to implement part of it yourself. Right now, you probably have a basic outline that looks something like this (+ error handling, etc):
SDL_Init(SDL_INIT_VIDEO);
auto window = SDL_CreateWindow(/*arguments*/);
//create something in the window, possibly in a loop
SDL_DestroyWindow(window);
SDL_Quit();
To do event handling, you need to create a main loop yourself. In this loop, you repetitively ask SDL for the next event, and process that event as soon as it is given to you. You also re-draw the contents of the window in this loop. In game programming (and general UI, to a lesser extent) the standard system is to, over and over, clear an offscreen buffer (an offscreen buffer is just an image that isn't visible to the user), draw to it, and then make that buffer visible (while usually taking the buffer (buffers are just images) that was visible and making that be the offscreen buffer for the next iteration of the loop). The number of times that this loop runs is your FPS value in a video game, and you can measure FPS by counting how many times your loop runs in a second.
bool quit = false;
SDL_Event event;
while(!quit){
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
quit = true;
break;
//add more event types here as you see fit
}
}
//it is customary to re-draw the window as fast as possible here, to allow for the window contents to change
}
You can optionally write a more complex event handling system to abstract this loop, but a simple loop + switch as shown above is usually sufficient. noobius's answer gives some more detailed pointers on how to make a more complex system if a simple loop+switch is insufficient (Make sure that it actually is! Complexity is the enemy of software development, so simpler is always better all else being equal.)
Reference, to learn more: https://lazyfoo.net/tutorials/SDL/03_event_driven_programming/index.php
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
When I resize the window for my C++ application and make circling motions (just drag the top-left corner a bunch), it causes a strange artefact.
When I let go of my mouse:
Essentially what's happening is the application pauses whilst the window is being resized. Is there a way around this?
EDIT: Thanks for closing my question guys...
If anyone miraculously finds this question, I was able to find my own "solution". Do yourself a favour and use freeGLUT rather than SDL2, works like a charm, the set-up is much easier too.
Pretty much all window APIs(Win32, GLFW, etc) have some sort of PollEvents() function that takes all the events out of the event queue and processes them. For Win32, you have a callback function that gets called every event and you process them individually until the queue is empty. For GLFW you poll the events, then you read the state of a certain key from the updated input data (As I understand it). Regardless of the specific implementation for input, most PollEvents() functions become blocking when you either resize or move the window. What that means is that it will be constantly receiving events of type window resize or window move, even if there is no change. This causes the rendering to not update, which causes all sorts of weird stuff. The way around this is to put the PollEvents() function on a different thread than the update loop and call it repeatedly. Depending on what API you're using, there might be restrictions. For example, GLFW's PollEvents() function must be on the main thread, forcing the update loop to be on a separate thread. However, the idea is still the same across window APIs.
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).
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Context: a native C++ desktop application that runs on Windows. The GUI uses plain old GDI and standard controls. The application itself is not GUI-rich but all the standard controls I use (static, button, edit and list as a base) are either owner-drawn, custom-drawn, or a mix of both.
My question is about some parts of the GUI I draw directly onto the dialog/window. Each one of these parts is clearly delimited by a rectangle, which is kept as a property for fast access, and these parts get painted only when their respective rectangle overlaps the one that comes from the WM_PAINT and similar messages. Mostly to draw text and icons (transparent background). These parts don't require any end-user interaction but they display valuable information (think status bar or any other GUI element that reacts to a state change).
The result is smooth and flicker-free thanks to the use of some tricks gathered here and there.
Q: Still, out of curiosity, I wonder in such a case (i.e.: non rich application) what would be the benefits of creating a child window for each one of these "parts" instead of just sticking to the current all-in-one drawing technique? Is there any reason why I would have to think about creating children windows?
From where I stand, I see only cons of creating children windows since it would mean more resources (children windows plus their context), plus having to deal with their procedure, which means more code to write-then-maintain.
Answering my own question a few month later...
The way the described application works is just fine as long as the amount of code to deal with those fake control rectangles (content and drawing) does not bloat parent window's code. Also, this technique spares the application from the creation of any resource associated to additional (child) windows, which cannot be a bad thing.
That being said, in the case of a layered parent window that is updated only with UpdateLayeredWindow, it can be preferable (more speed-optimized) to create child controls, especially if we need to update their content quite often.
The benefit of using child windows is simplification and code reuse. Microsoft has implemented many standard controls, and others are available from different sources, all of which are implemented as independent windows. A window will get messages directed at it so that the parent does not have to include logic to determine which function needs to respond to a particular message.
I’m using Qt 4.8.
I have a big QGraphicsScene to update (it takes 3 secs to append the new QGraphicsObjects).
I would like to show the user that the update is in progress.
In particular I thought about showing a loading wheel on screen and than remove it when the update ends.
The problem here is that I should make the wheel visible and then not visible in the
same thread of the scene update. This because:
It is not allowed to edit graphic properties outside the gui thread.
I cannot move the computation in a “worker thread” since it involves graphics.
This results in the wheel not showing at all, since when the view is updated the wheel
has been already set visible and then not visible again:
showWheel();
/*... big computation involving graphics ...*/
hideWheel();
/*... here GUI is updated, thus the wheel doesn't show up...*/
Is there anything I can do?
Thanks
Presumably you have some event triggering the computation. Instead of using it to trigger the computation, use it to trigger a scheduleComputation()slot. The scheduleComputation slot can call showWheel() and then schedule the doComputation() slot for the end of the next event queue, after which it will return. This will allow the event loop to run and show your wheel, then perform computation. When computation is over, you can call hideWheel() and return to the event loop.
Something like this:
void scheduleComputation()
{
computeScheduler = new QTimer(this);
computeScheduler->setInterval(0);
connect(computeScheduler,SIGNAL(timeout()),this,SLOT(doComputation()));
showWheel();
}
void doComputation()
{
//...Computation Here...
hideWheel();
}
It is also a good idea to keep from blocking the UI thread for long periods of time. This can be done by splitting your long running code into smaller pieces that can be triggered by a timer.
At regular intervals in the "big computation" you can let the event handler run for a little while.
I am new to Qt Programming, but I have basic on C++.
I want to update my GUI while it is processing, example:
while (....)
{
do some calculation...
if (condition fulfill)
change the color of label.
}
However, I realise that I failed to get the result I want (update the GUI while processing). The GUI will only update after the while loop.
Why is it so? Anyone can help?
In addition, I wish to "slower" the color change since the processing is too fast and I can't see the animation. Any idea to do it?
Thank you very much!
Clarification:
Actually I wish to update the GUI while I am processing...Meaning that, if I have 100 iteration, after each iteration I wish to update the GUI immediately.
Use a QTimer. This will allow you to control the speed of your animation and keep your UI responsive.
You have to place your processing code to another thread and update the gui, because like this GUI will be waiting for your process to end and will refresh after its end
read more here:
http://www.qtcentre.org/threads/41545-How-to-refresh-GUI-while-heavy-processing-is-ongoing
http://www.qtcentre.org/threads/32416-Update-GUI-from-another-thread
Forcing the Qt GUI to update
You don't necessarily need a thread.
Calling QApplication::processEvents() will process pending events, including any redraws you may have caused during your processing.
If you wish to animate the color to indicate that the system is currently working, you might want to use QApplication::setOverrideCursor to show a waitCursor, or a QProgressDialog instead.