I read this book. For graphics I installed FLTK on my compiler, MS visual studio 2012. The machine I'm using is MS Windows 7.
I have read that book until chapter 17 and I haven't studied any method for waiting. By waiting I mean executing a statement, making the system to wait for a while, and executing second statement.
In the following there is a simple example that draws two shapes on the window. The graphics libraries used for the book are here.
For example in this code I have two circles with two different positions and different radiuses.
I want to attach first circle (c1), than wait one second, detach the c1 and attach the c2 this time. What is simplest method for waiting for one second of time (or more) please?
#include <Windows.h>
#include <GUI.h>
using namespace Graph_lib;
//---------------------------------
class Test : public Window {
public:
Test(Point p, int w, int h, const string& title):
Window(p, w, h, title),
quit_button(Point(x_max()-90,20), 60, 20, "Quit", cb_quit),
c1(Point(100,100), 50),
c2(Point(300,200), 100) {
attach(quit_button);
attach(c1);
attach(c2);
}
private:
Circle c1, c2;
Button quit_button;
void quit() { hide(); }
static void cb_quit(Address, Address pw) {reference_to<Test>(pw).quit();}
};
//------------------
int main() {
Test ts(Point(300,250), 800, 600, "Test");
return gui_main();
}
If you're using c++11:
std::this_thread::sleep_for(std::chrono::seconds(1));
Otherwise use the Windows function Sleep.
And if you want to wait without blocking the main thread you can use std::async:
#include <future>
// in your Test's constructor
std::async([&]()
{
attach(quit_button);
attach(c1);
std::this_thread::sleep_for(std::chrono::seconds(1));
attach(c2);
});
That might not be working though since I don't know much about the library you're using.
You need to use callbacks to put a delay into drawing. The add_timeout method in the FLTK allows you to set a timer that will be called once after a delay. In the callback you can attach the c2.
By sleeping in between attach(c1) and attach(c2) does not pass control back to the GUI thread to allow it to draw anything. By using the add_timeout control is passed back to the GUI thread so it can draw c1. One second later your callback will be called where you can attach c2.
// The function that will be called after the timeout. The testWindow object will be of type Test*
void callback(void* testWindow)
{
Test* t = reinterpret_cast<Test*>(testWindow);
t->doCallback();
}
class Test : public Window
{
public:
Test(Point p, int w, int h, const string& title):
Window(p, w, h, title),
quit_button(Point(x_max()-90,20), 60, 20, "Quit", cb_quit),
c1(Point(100,100), 50),
c2(Point(300,200), 100)
{
attach(quit_button);
attach(c1);
// Setup the timeout and pass a pointer to the Test window to the call back
Fl::add_timeout(1.0, callback, this);
}
// Method that is called by callback() and will attach c2
void doCallback()
{
attach(c2);
}
// rest of class
You want to use the Sleep function, which takes milliseconds:
Sleep(1000);
As you have found out, Sleep isn't the answer, because you need to let control pass back to the system while waiting, or else the window won't get updated.
What you need is a timeout. FLTK provides add_timeout:
http://www.fltk.org/doc-1.1/Fl.html#Fl.add_timeout
Related
I'm currently updating an existing codebase designed to be used with a GTK GUI to QT, so that it can implement multi threading, as the functions take hours to complete.
This codebase makes frequent calls to a function display(std::string), for the purpose of updating a text display widget. I redefined this function for the new QT version:
In Display.cpp:
void display(std::string output)
{
//
MainWindow * gui = MainWindow::getMainWinPtr(); //Gets instance of GUI
gui->DisplayInGUI(output); //Sends string to new QT display function
}
In MainWindow.cpp:
void MainWindow::DisplayInGUI(std::string output)
{
//converts output to qstring and displays in text edit widget
}
void MainWindow::mainFunction(){
//calls function in existing codebase, which itself is frequently calling display()
}
void MainWindow::on_mainFunctionButton_released()
{
QFuture<void> future = QtConcurrent::run(this,&MainWindow::mainFunction);
}
If I run the main function in a new thread, display(std::string) won't update the GUI until the thread completes. I understand why; the GUI can only be updated in the main thread. Everything else functions as intended.
What I want to implement, but I'm not sure how, is having display(std:string) send a signal back to the main thread to call MainWindow::DisplayInGUI(output_text) with the string that was passed to the display() function. I believe this is the correct way to do it, but correct me if I'm wrong. I want to avoid changing the existing codebase at all costs.
EDIT: I should add that for some dumb reasons entirely out of my control, I am forced to use C++98 (yeah, I know)
You must schedule the code that does UI calls to run in the main thread. I use a simple and easy to use wrapper for that:
#include <QApplication>
#include <QtGlobal>
#include <utility>
template<typename F>
void runInMainThread(F&& fun)
{
QObject tmp;
QObject::connect(&tmp, &QObject::destroyed, qApp, std::forward<F>(fun),
Qt::QueuedConnection);
}
You can now run code (using a lambda in this example, but any other callable will work) in the main thread like this:
runInMainThread([] { /* code */ });
In your case:
void display(std::string output)
{
runInMainThread([output = std::move(output)] {
MainWindow* gui = MainWindow::getMainWinPtr();
gui->DisplayInGUI(output);
});
}
Or you can leave display() as is and instead wrap the calls to it:
runInMainThread([str] { display(std::move(str)); );
The std::move is just an optimization to avoid another copy of the string since you should not pass the string by reference in this case (it would be a dangling reference once the string object goes out of scope.)
This is not a high performance inter-thread communication mechanism. Every call will result in the construction of a temporary QObject and a temporary signal/slot connection. For periodic UI updates, it's good enough and it allows you to run any code in the main thread without having to manually set up signal/slot connections for the various UI update operations. But for thousands of UI calls per second, it's probably not very efficient.
First of all: there's no way to make the getMainWinPtr method thread-safe, so this pseudo-singleton hack should probably go away. You can pass around some application-global context to all the objects that do application-global things like provide user feedback. Say, have a MyApplication : QObject (don't derive from QApplication, it's unnecessary). This can be passed around when new objects are created, and you'd then control the relative lifetime of the involved objects directly in the main() function:
void main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow win;
MyApplication foo;
win.setApplication(&foo);
// it is now guaranteed by the semantics of the language that
// the main window outlives `MyApplication`, and thus `MyApplication` is free to assume
// that the window exists and it's OK to call its methods
...
return app.exec();
}
Of course MyApplication must take care that the worker threads are stopped before its destructor returns.
To communicate asynchronous changes to QObject living in (non-overloaded) QThreads (including the main thread), leverage the built-in inter-thread communication inherent in Qt's design: the events, and the slot calls that traverse thread boundaries.
So, given the DisplayInGUI method, you need a thread-safe way of invoking it:
std::string newOutput = ...;
QMetaObject::invokeMethod(mainWindow, [mainWindow, newOutput]{
mainWindow->displayInGUI(newOutput);
});
This takes care of the thread-safety aspect. Now we have another problem: the main window can get hammered with those updates much faster than the screen refresh rate, so there's no point in the thread notifying the main window more often than some reasonable rate, it'll just waste resources.
This is best handled by making the DisplayInGUI method thread-safe, and leveraging the timing APIs in Qt:
class MainWindow : public QWidget {
Q_OBJECT
...
static constexpr m_updatePeriod = 1000/25; // in ms
QMutex m_displayMutex;
QBasicTimer m_displayRefreshTimer;
std::string m_newDisplayText;
bool m_pendingRefresh;
...
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == m_displayRefreshTimer.timerId()) {
QMutexLocker lock(&m_displayMutex);
std::string text = std::move(m_newDisplayText);
m_pendingRefresh = false;
lock.release();
widget->setText(QString::fromStdString(text));
}
QWidget::timerEvent(event);
}
void DisplayInGUI(const std::string &str) {
// Note pass-by-reference, not pass-by-value. Pass by value gives us no benefit here.
QMutexLocker lock(&m_displayMutex);
m_newDisplayText = str;
if (m_pendingRefresh) return;
m_pendingRefresh = true;
lock.release();
QMetaObject::invokeMethod(this, &MainWindow::DisplayInGui_impl);
}
private:
Q_SLOT void DisplayInGui_impl() {
if (!m_displayRefreshTimer.isActive())
m_displayRefreshTimer.start(this, m_updatePeriod);
}
};
In a more complex situation you'd likely want to factor out the cross-thread property setting to some "adjunct" class that would perform such operations without the boilerplate.
You could take advantage of the fact that QTimer::singleShot has an overload which, when called with a zero time interval, allows you to effectively schedule a task to be run on a specified thread during that thread's next idle slot...
void QTimer::singleShot(int msec, const QObject *context, Functor functor);
So your MainWindow::mainFunction could be something along the lines of...
void MainWindow::mainFunction ()
{
...
std::string output = get_ouput_from_somewhere();
QTimer::singleShot(0, QApplication::instance(),
[output]()
{
display(output);
});
...
}
I have one problem which I can't solve using the Internet. I have label and I set pixmap on it. I put it on main window (widget) where is button (QPushButton) too. I want to do that:
If I click on the button then on this pixmap will be drawn circles continuously
If I click this button for second then drawing must be stopped by function pause()
The second one is easy, it's empty slot:
void pause() {}
But at first I've tried to use loop
while(true)
draw();
but it crashed a program (loop).
Any idea how to solve it?
You should never block the main thread. This will cause the OS to consider your application has hanged. In fact it is a good practice to move any code, whose execution takes more than 50 milliseconds to another thread to keep the main thread responsive, especially in the case of Qt, where it is also the GUI thread.
You should use an event driven approach, which will not block the thread.
class YourClass : public QObject { // QObject or derived
Q_OBJECT
public:
YourClass() { connect(&timer, &Timer::timeout, this, &YourClass::draw); }
public slots:
void start() { timer.start(33); }
void pause() { timer.stop(); }
private:
QTimer timer;
void draw() { ... }
};
When start() is invoked, draw() will be called every 33 miliseconds. pause() will effectively stop that until start() is invoked again. You can control the rate at which draw() is invoked by adjusting the timer's interval, by default it is 0, which in the case of drawing is overkill, you should adjust for a desired framers per second. In the example above, the it is 33 milliseconds, or roughly 30 FPS.
You should then call draw() with some time interval, instead of halting the whole GUI thread with it.
For that, there's QTimer:
QTimer timer; // should be a member, a pointer optionally - you then do new Qtimer(this);
connect(&timer, &QTimer::timeout, draw);
timer.start(500); // in milliseconds
// assuming you are calling this from member function of QObject-deriving class
// and draw is a non-member function
If you know to do the connections, you can connect it to anything...
The same can be done with QThread and putting it to sleep in that loop.
Anyhow, I don't get how an empty pause() stops the drawing. Aren't you halting your application again? Just do timer.stop();.
I have a .NET form with a boolean property called _isResized, which is set to true when the SizeChanged event is called and is set to false when the bool isResized() function is called.
ref class net_window : public System::Windows::Forms::Form
{
private:
bool _isResized;
public:
net_window(void)
: _isResized(false){
InitializeComponent();
}
void InitializeComponent(void){
this->SizeChanged += gcnew EventHandler(this, &net_window::eventResized);
}
bool isResized(void){
bool temp = _isResized;
_isResized = false;
return temp;
}
Void eventResized(Object^ sender, EventArgs^ e){
_isResized = true;
}
};
I also have an native C++ class called window which acts as a layer around the .NET form. This class is updated every frame of the main loop and uses the bool isResized() function of the form to see if the size has changed.
class Window
{
private:
void* _net_window_handle;
Window(){
_net_window_handle = new gcroot<net_window^>;
(*(gcroot<net_window^>*)_net_window_handle) = gcnew net_window;
}
~Window(){
delete _net_window_handle;
}
void update(void)//Called every frame.
{
if( (*(gcroot<net_window^>*)_element)->isResized() )
//Do stuff.
}
};
The delegate added to SizeChanged is called whenever the form is being resized, so _isResized is set to true as soon as the form size changes, but for some reason the thread of the main loop freezes whenever the window class uses the bool isResized() function, until the user has released the edge of the form and thus the resizing has finished.
Is it not possible to access .NET form values as long as it is being resized. Is there an alternative?
Thanks
EDIT
I use a main loop which calls System::Windows::Forms::Application::DoEvents() every frame. When the thread of the loop enters this function and the main window is resizing, it freezes. Is there a way to avoid this problem.
DoEvents strikes again. Windows pumps a modal message loop when the user starts dragging a window edge. Which means that your DoEvents loop isn't running anymore. Use a timer instead, SetTimer with a 15 or 31 msec interval is about right. Having your code respond to the Resize event directly of course highly preferred.
Thanks Hans Passant
I have an RPC thread that is calling back to me from that thread. I need to somehow inform Qt that it needs to make a function call from the main thread. In straight Windows I could do this by using a custom message and then posting that message to the message queue, e.g., I could create a WM_CALLFUNCTION message and pass the function pointer through wParam and the parameter (class pointer) through lParam.
Has anyone an idea how I could do this with Qt? I've come across QCustomEvent but I have no idea how to use it or how to process it. Any help would be hugely appreciated!
Edit:
In the end I went with QMetaObject::invokeMethod which works perfectly.
Using custom events generally involves creating your own QEvent subclass, overriding customEvent() in the QObject class that will receive the event (often the main window class) and some code that "posts" the event from your thread to the receiver.
I like to implement the event posting code as a method of the receiver class. That way, the caller only has to know about the recevier object and not any of the "Qt" specifics. The caller will invoke this method which will then essentially post a message to itself. Hopefully the code below will make it clearer.
// MainWindow.h
...
// Define your custom event identifier
const QEvent::Type MY_CUSTOM_EVENT = static_cast<QEvent::Type>(QEvent::User + 1);
// Define your custom event subclass
class MyCustomEvent : public QEvent
{
public:
MyCustomEvent(const int customData1, const int customData2):
QEvent(MY_CUSTOM_EVENT),
m_customData1(customData1),
m_customData2(customData2)
{
}
int getCustomData1() const
{
return m_customData1;
}
int getCustomData2() const
{
return m_customData2;
}
private:
int m_customData1;
int m_customData2;
};
public:
void postMyCustomEvent(const int customData1, const int customData2);
....
protected:
void customEvent(QEvent *event); // This overrides QObject::customEvent()
...
private:
void handleMyCustomEvent(const MyCustomEvent *event);
The customData1 and customData2 are there to demonstrate how you might pass some data along in your event. They don't have to be ints.
// MainWindow.cpp
...
void MainWindow::postMyCustomEvent(const int customData1, const int customData2)
{
// This method (postMyCustomEvent) can be called from any thread
QApplication::postEvent(this, new MyCustomEvent(customData1, customData2));
}
void MainWindow::customEvent(QEvent * event)
{
// When we get here, we've crossed the thread boundary and are now
// executing in the Qt object's thread
if(event->type() == MY_CUSTOM_EVENT)
{
handleMyCustomEvent(static_cast<MyCustomEvent *>(event));
}
// use more else ifs to handle other custom events
}
void MainWindow::handleMyCustomEvent(const MyCustomEvent *event)
{
// Now you can safely do something with your Qt objects.
// Access your custom data using event->getCustomData1() etc.
}
I hope I didn't leave anything out. With this in place, code in some other thread just needs to get a pointer to a MainWindow object (let's call it mainWindow) and call
mainWindow->postMyCustomEvent(1,2);
where, just for our example, 1 and 2 can be any integer data.
In Qt 3, the usual way to communicate
with the GUI thread from a non-GUI
thread was by posting a custom event
to a QObject in the GUI thread. In Qt
4, this still works and can be
generalized to the case where one
thread needs to communicate with any
other thread that has an event loop.
To ease programming, Qt 4 also allows
you to establish signal--slot
connections across threads. Behind the
scenes, these connections are
implemented using an event. If the
signal has any parameters, these are
also stored in the event. Like
previously, if the sender and receiver
live in the same thread, Qt makes a
direct function call.
--
http://doc.qt.nokia.com/qq/qq14-threading.html#signalslotconnectionsacrossthreads
I have an application which needs to draw on a pixel by pixel basis at a specified frame rate (simulating an old machine). One caveat is that the main machine engine runs in a background thread in order to ensure that the UI remains responsive and usable during simulation.
Currently, I am toying with using something like this:
class QVideo : public QWidget {
public:
QVideo(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), screen_image_(256, 240, QImage::Format_RGB32) {
}
void draw_frame(void *data) {
// render data into screen_image_
}
void start_frame() {
// do any pre-rendering prep work that needs to be done before
// each frame
}
void end_frame() {
update(); // force a paint event
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(rect(), screen_image_, screen_image_.rect());
}
QImage screen_image_;
};
This is mostly effective, and surprisingly not very slow. However, there is an issue. The update function schedules a paintEvent, it may not hapen right away. In fact, a bunch of paintEvent's may get "combined" according to the Qt documentation.
The negative effect that I am seeing is that after a few minutes of simulation, the screen stops updating (image appears frozen though simulation is still running) until I do something that forces a screen update for example switching the window in and out of maximized.
I have experimented with using QTimer's and other similar mechanism to have the effect of the rendering being in the GUI thread so that I can force immediate updates, but this resulted in unacceptable performance issues.
Is there a better way to draw pixels onto a widget constantly at a fixed interval. Pure Qt solutions are preferred.
EDIT: Since some people choose to have an attitude instead of reading the whole question, I will clarify the issue. I cannot use QWidget::repaint because it has a limitation in that it must be called from the same thread as the event loop. Otherwise, no update occurs and instead I get qDebug messages such as these:
QPixmap: It is not safe to use pixmaps outside the GUI thread
QPixmap: It is not safe to use pixmaps outside the GUI thread
QWidget::repaint: Recursive repaint detected
QPainter::begin: A paint device can only be painted by one painter at a time.
QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent
QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent
EDIT: to demonstrate the issue I have created this simple example code:
QVideo.h
#include <QWidget>
#include <QPainter>
class QVideo : public QWidget {
Q_OBJECT;
public:
QVideo(QWidget *parent = 0, Qt::WindowFlags f = 0) : QWidget(parent, f), screen_image_(256, 240, QImage::Format_RGB32) {
}
void draw_frame(void *data) {
// render data into screen_image_
// I am using fill here, but in the real thing I am rendering
// on a pixel by pixel basis
screen_image_.fill(rand());
}
void start_frame() {
// do any pre-rendering prep work that needs to be done before
// each frame
}
void end_frame() {
//update(); // force a paint event
repaint();
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(rect(), screen_image_, screen_image_.rect());
}
QImage screen_image_;
};
main.cc:
#include <QApplication>
#include <QThread>
#include <cstdio>
#include "QVideo.h"
struct Thread : public QThread {
Thread(QVideo *v) : v_(v) {
}
void run() {
while(1) {
v_->start_frame();
v_->draw_frame(0); // contents doesn't matter for this example
v_->end_frame();
QThread::sleep(1);
}
}
QVideo *v_;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QVideo w;
w.show();
Thread t(&w);
t.start();
return app.exec();
}
I am definitely willing to explore options which don't use a temporary QImage to render. It is just the only class in Qt which seems to have a direct pixel writing interface.
Try emitting a signal from the thread to a slot in the event loop widget that calls repaint(), which will then execute right away. I am doing something like this in my graphing program, which executes the main calculations in one thread, then tells the widget when it is time to repaint() the data.
In similar cases what I did was still using a QTimer, but doing several simulation steps instead of just one. You can even make the program auto-tuning the number of simulation steps to be able to get whatever frames per seconds you like for the screen update.