[英]The simplest possible example for a multi-threaded gtkmm application
I'm developing a stopwatch application in c++ and gtkmm.The first approach was to integrate the stopwatch loop with main event loop,but that caused delays in the stopwatch loop,So I decided to use two threads, one for GUI the other is for the stopwatch counter.我正在 c++ 和 gtkmm 中开发秒表应用程序。第一种方法是将秒表循环与主事件循环集成,但这会导致秒表循环延迟,所以我决定使用两个线程,一个用于 GUI,另一个用于秒表计数器。 the GUI thread and and stopwatch thread -which counts the number of seconds passed-, the stopwatch thread updates the label after each second. GUI 线程和秒表线程 - 计算经过的秒数 - 秒表线程每秒更新 label。 I've read that I've to use specific techniques to use multi threaded gtkmm program.我读过我必须使用特定技术来使用多线程 gtkmm 程序。 I also checked this example which i didn't understand.我还检查了这个我不明白的例子。 Can any one tell me what shall I do in the stopwatch thread to make it update the GUI without crashing.谁能告诉我我应该在秒表线程中做什么以使其更新 GUI 而不会崩溃。
Here's the code,这是代码,
#include <ctime>
#include <thread>
#include <iostream>
#include <sstream>
#include <gtkmm.h>
using namespace std;
using namespace Gtk;
using namespace std::chrono;
class Timer
{
bool condition;
Label *label_ptr;
private:
void startTimer()
{
condition = true;
auto t0 = high_resolution_clock::now();
int x = 0;
while (condition)
{
cout << condition << endl;
auto t1 = high_resolution_clock::now();
int duration = duration_cast<seconds>(t1 - t0).count();
if (duration - x == 1)
{
x = duration;
//cout << duration_cast<seconds>(t1 - t0).count() << "sec" << endl;
stringstream moment;
moment << to_string(duration_cast<seconds>(t1 - t0).count());
moment << ": 0 s";
label_ptr->set_label(moment.str());
}
if (g_main_context_pending(NULL))
{
g_main_context_iteration(NULL, true);
}
}
}
public:
//This is the function which start the thread
void start_timer(){
thread t0(sigc::mem_fun(this , &Timer::startTimer));
}
Timer(Label &label)
{
condition = 0;
label_ptr = &label;
}
void stop_timer()
{
label_ptr->set_text("0 : 0");
condition = false;
}
};
int main(int argc, char *argv[])
{
auto app = Application::create(argc, argv, "Timer");
if (!g_thread_supported())
g_thread_init(NULL);
gdk_threads_init();
gdk_threads_enter();
Window window;
HBox mainBox;
window.add(mainBox);
window.set_title("Timer & Stopwatch");
window.set_default_size(240, 100);
window.set_border_width(10);
Label label;
VButtonBox buttons;
Separator sep0;
mainBox.pack_start(buttons, PACK_EXPAND_PADDING, 20);
mainBox.pack_start(sep0, PACK_SHRINK);
mainBox.pack_end(label, PACK_EXPAND_PADDING);
label.set_size_request(120, 100);
Button start, stop;
buttons.add(start);
buttons.add(stop);
start.set_border_width(5);
stop.set_border_width(5);
start.set_label("Start");
stop.set_label("Stop");
label.set_text("0 : 0");
Timer timer(label);
start.signal_clicked().connect(sigc::mem_fun(timer, &Timer::start_timer));
window.show_all_children();
gdk_threads_leave();
return app->run(window);
}
if your requirement is just to count number of seconds elapsed, you do not need a worker thread.如果您的要求只是计算经过的秒数,则不需要工作线程。 Also you cannot modify any GUI element (in your case the 'label') from a worker thread since Gdk is not thread safe.此外,您不能从工作线程修改任何 GUI 元素(在您的情况下为“标签”),因为 Gdk 不是线程安全的。 You will then need to use Glib::Dispatcher to notify the main thread of a 'tick' event and then increment a counter from the main loop.然后,您将需要使用 Glib::Dispatcher 通知主线程“tick”事件,然后从主循环中增加一个计数器。
Instead of all this you can simply use Glib::SignalTimeout and connect a function to it like below.而不是所有这些,您可以简单地使用Glib::SignalTimeout并将 function 连接到它,如下所示。
In the function that handles starting of the stop-watch在处理秒表启动的 function 中
//Connect to timeout
m_connectionStopWatch = Glib::SignalTimeout::connect(sigc::mem_fun(*this, &CStopWatchClass::OneSecondElapsed), 1000);
//Reset counter
m_nCounter = 0;
The function that is called every second每秒调用的 function
bool CStopWatchClass::OneSecondElapsed(void)
{
//Increment counter
m_nCounter++;
//TODO Update label
return true;
}
In the function that stops the stop watch在停止秒表的 function
m_connectionStopWatch.disconnect();
m_connectionStopWatch and m_nCounter shall be class private (or protected or even public though not preferred) members. m_connectionStopWatch和m_nCounter应为 class 私有(或受保护或什至公共,但不是首选)成员。
If you are not particular about having a delay of up to 0.99... seconds in starting your stop watch you can even use Glib::SignalTimeout::connect_seconds which loads your application even less.如果您不特别想在启动秒表时延迟最多 0.99... 秒,您甚至可以使用Glib::SignalTimeout::connect_seconds来减少应用程序的负载。 In any case a 1 second timeout is no problem at all, I myself am using a 20 millisecond timeout for a similar graphical application.在任何情况下,1 秒的超时都不是问题,我自己正在为类似的图形应用程序使用 20 毫秒的超时。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.