c - 在 C 中使用 GTK 的 GUI 不显示输入的实时值
问题描述
我正在尝试为 C 中的活动监视器构建一个 GUI 应用程序,并决定使用 GTK 库和 Glade 来帮助设计。(使用 Ubuntu 20.04)
按下按钮后,值将显示在相应的位置,并在每次单击时更新。唯一的问题是我需要它自己实时更新,所以我用 sleep(1) 将代码转换为无限循环,所以它每 1 秒更新一次。但是现在甚至没有在 GUI 上显示值。为了测试代码是否正在执行,我尝试在控制台上从代码的不同部分打印值,它们确实正在被打印。
我尝试过但没有奏效的事情:
- 在循环和递归之间切换,都失败了。
- 使用 time.h 库将 sleep() 函数替换为自制计时器
- 将 GUI 显示代码封装到一个函数中,并在循环中调用整个函数。
- 使用 GDK 函数强制刷新 GUI,因此它在每次迭代中手动更新 GUI。
- 在代码的不同部分使用 gtk_show_all 强制它在每次迭代结束时显示。
我认为它与按钮触发器有关,并且仅在执行回调函数后才在 GUI 上更新输出(根据我对控制台打印的观察)。因此,我试图以编程方式每隔一段时间按下按钮,以避免每次都自己单击它,但在该主题上找不到太多。
如果您能想到任何方法来完成这项工作或替代我正在采用的方法,请提供帮助。主要思想是,无论按钮如何,输出 GUI 都应该具有实时更新的值。
提前致谢!
这是用于在 GUI 上打印出值的函数:
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = 1000 * 1000 * 1000;
myproc_t* myprocs = NULL;
unsigned int myprocs_len = 0;
//call to function that will return the processes and their specifications
sample_processes(&myprocs, &myprocs_len, tm);
if(s == 0){
// sort by CPU usage
qsort(myprocs, myprocs_len, sizeof(myprocs[0]), myproc_comp_pcpu);
}
else if(s == 1){
// sort by Memory usage
qsort(myprocs, myprocs_len, sizeof(myprocs[0]), myproc_comp_rss);
}
for (i = 0; i < myprocs_len && i < 5; i++)
{
if (strlen(myprocs[i].cmd) == 0) {
break;
}
//convert specs read from /proc file to string format
sprintf(pid, "%d", myprocs[i].tid);
sprintf(cpu, "%.2f",myprocs[i].pcpu);
sprintf(memory, "%lu", myprocs[i].vm_rss/1000);
sprintf(cmd, "%s", myprocs[i].cmd);
switch(i)
{
case 0:
gtk_label_set_text(GTK_LABEL(PID1), pid);
gtk_label_set_text(GTK_LABEL(CPU1), cpu);
gtk_label_set_text(GTK_LABEL(MEM1), memory);
gtk_label_set_text(GTK_LABEL(CMD1), cmd);
case 1:
gtk_label_set_text(GTK_LABEL(PID2), pid);
gtk_label_set_text(GTK_LABEL(CPU2), cpu);
gtk_label_set_text(GTK_LABEL(MEM2), memory);
gtk_label_set_text(GTK_LABEL(CMD2), cmd);
case 2:
gtk_label_set_text(GTK_LABEL(PID3), pid);
gtk_label_set_text(GTK_LABEL(CPU3), cpu);
gtk_label_set_text(GTK_LABEL(MEM3), memory);
gtk_label_set_text(GTK_LABEL(CMD3), cmd);
case 3:
gtk_label_set_text(GTK_LABEL(PID4), pid);
gtk_label_set_text(GTK_LABEL(CPU4), cpu);
gtk_label_set_text(GTK_LABEL(MEM4), memory);
gtk_label_set_text(GTK_LABEL(CMD4), cmd);
case 4:
gtk_label_set_text(GTK_LABEL(PID5), pid);
gtk_label_set_text(GTK_LABEL(CPU5), cpu);
gtk_label_set_text(GTK_LABEL(MEM5), memory);
gtk_label_set_text(GTK_LABEL(CMD5), cmd);
}
}
解决方案
使用带有阻塞的循环sleep(1)
或任何阻塞的东西总是不行的,因为这意味着您实际上是在阻止 UI 线程执行任何实际工作。正常的工作流程如下:
- 您希望通过使用
gtk_main()
或gtk_application_new()
连接到“激活”信号(将在您调用时调用gtk_application_run()
)来运行主循环。 - 初始化你的后端代码
- 初始化您的 UI 代码,您可以在其中为每个进程创建必要的小部件。此时,您可能已经希望使用
gtk_widget_show()
和朋友使其可见 - 对于定期更新,您应该将定期事件发布到主循环,您可以使用类似
g_timeout_add_seconds ()
. 在回调中,您可以调用gtk_label_set_text()
您在上一步中创建的标签。只要回调返回G_SOURCE_CONTINUE
,回调就会以指定的时间间隔周期性地被调用。
推荐阅读
- python - 日期时间转换为年
- ios - 尝试在 swift 中使用 URLSession 解析 JSON 时出错
- java - 如何使用 AES 方法解密加密列?
- angular - 如何以角度比较未来日期和当前日期?
- windows - 在 Windows 上为 Linux 开发 docker 容器的推荐方法是什么?
- python - 如何根据模型要求重塑我的数据?
- spring - 使用休眠序列创建唯一的 8 位数字的最佳实践是什么
- angular - 从其他控件动态设置角度控制值
- swift - 如何在快速为 UIView 提供阴影的同时去除某些 iPhone 中的额外黑色阴影?
- c# - WPF:如何实现清除命令