c - 尝试将文本附加到 Xm 文本小部件时出现多线程或 Motif 小部件问题
问题描述
我正在尝试使用 TextWidget 作为日志,其中以编程方式添加文本。通过使用XmTextInsert
,我可以将文本附加XtVaSetValues
到XmTextShowPosition
文本小部件,但是我注意到只有当小部件具有焦点或将鼠标指针滚动到文本小部件区域时才会更新文本。否则,小部件似乎只更新了大约 5/6 秒,所以你会看到一次出现几行。
我无法确定它是与 Motif 相关的问题还是纯 X11/Xt/Xm 多线程问题,但显然附加的代码缺少相关的内容。
例如,这个源代码只有 TextWidget,并且更新工作正常,即使焦点在另一个应用程序中,每一秒你都会看到一个新的 TEST 词添加到 Text Widget:
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void displayMessage(char *textLineBuffer);
void createWindow(int argc, char *argv[]);
void *logText(void *arg);
/* X11 RELATED VARIABLES */
XtAppContext context;
Widget toplevel;
Widget busForm;
Widget textWidget;
pthread_mutex_t textWidgetMutex;
long textWidgetLength = 0;
int main(int argc, char *argv[]) {
pthread_t thread;
/* INITIALIZE MULTITHREAD X11 ENVIRONMENT */
XInitThreads();
/* CREATE X WINDOW */
createWindow(argc, argv);
/* GET NEW THREAD TO PROCESS QUEUES */
/* PARENTS HANDLES X11 */
pthread_create(&thread, NULL, logText, NULL);
/* BEGIN X11 APPLICATION */
XtAppMainLoop(context);
}
void *logText(void *arg) {
/* READ CLIENT QUEUE MESSAGES */
while(1) {
sleep(1);
displayMessage("TEST\n");
}
}
void createWindow(int argc, char *argv[]){
Arg al[10];
int ac;
XmStringCharSet char_set = XmSTRING_DEFAULT_CHARSET;
char pidString[50];
/* CREATE TOP LEVEL */
sprintf(pidString, "Bus Client %d", getpid());
toplevel = XtAppInitialize(&context, pidString, NULL, 0, &argc, argv, NULL, NULL, 0);
/* RESIZE TOP LEVEL */
ac = 0;
XtSetArg(al[ac], XmNwidth, 300); ac++;
XtSetArg(al[ac], XmNheight, 300); ac++;
XtSetValues(toplevel, al, ac);
/* CREATE TOP LEVEL FORM MANAGER */
ac = 0;
busForm = XmCreateForm(toplevel, "busForm", al, ac);
XtManageChild(busForm);
/* CREATE TEXT WIDGET */
ac = 0;
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
XtSetArg(al[ac], XmNscrollingPolicy, XmVARIABLE); ac++;
XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++;
XtSetArg(al[ac], XmNscrollHorizontal, FALSE); ac++;
XtSetArg(al[ac], XmNeditable, FALSE); ac++;
textWidget = XmCreateScrolledText(busForm, "textWidget", al, ac);
XtManageChild(textWidget);
/* DISPLAY TOP LEVEL */
XtRealizeWidget(toplevel);
}
void displayMessage(char *textLineBuffer) {
pthread_mutex_lock(&textWidgetMutex);
XmTextInsert(textWidget, textWidgetLength, textLineBuffer);
textWidgetLength += strlen(textLineBuffer);
XtVaSetValues(textWidget, XmNcursorPosition, textWidgetLength, NULL);
XmTextShowPosition(textWidget, textWidgetLength);
pthread_mutex_unlock(&textWidgetMutex);
}
从输出中可以看出,即使窗口没有焦点,消息也会不断显示:
但是,如果添加一个按钮,当 Motif 应用程序的焦点在 Button Widget 中时,文本不会更新,直到鼠标悬停在 Text Widget 上。如果您单击文本小部件,则文本会像前面的示例一样不断更新。
这是源代码和相应的示例。
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/PushB.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
#include <unistd.h>
void displayMessage(char *textLineBuffer);
void createWindow(int argc, char *argv[]);
void sendButtonCB(Widget w, XtPointer client_data, XtPointer call_data);
void *logText(void *arg);
/* X11 RELATED VARIABLES */
XtAppContext context;
Widget toplevel;
Widget busForm;
Widget textWidget;
Widget registerButton;
Widget sendButton;
pthread_mutex_t textWidgetMutex;
long textWidgetLength = 0;
/* BUS CLIENT SYS V QUEUE VARIABLES */
int client_queue_id;
key_t client_queue_key;
int client_message_id;
int main(int argc, char *argv[]) {
pthread_t thread;
/* INITIALIZE MULTITHREAD X11 ENVIRONMENT */
XInitThreads();
/* CREATE X WINDOW */
createWindow(argc, argv);
/* GET NEW THREAD TO PROCESS QUEUES */
/* PARENTS HANDLES X11 */
pthread_create(&thread, NULL, logText, NULL);
/* BEGIN X11 APPLICATION */
XtAppMainLoop(context);
}
void *logText(void *arg) {
/* READ CLIENT QUEUE MESSAGES */
while(1) {
sleep(1);
displayMessage("TEST\n");
}
}
void createWindow(int argc, char *argv[]){
Arg al[10];
int ac;
XmStringCharSet char_set = XmSTRING_DEFAULT_CHARSET;
char pidString[50];
/* CREATE TOP LEVEL */
sprintf(pidString, "Bus Client %d", getpid());
toplevel = XtAppInitialize(&context, pidString, NULL, 0, &argc, argv, NULL, NULL, 0);
/* RESIZE TOP LEVEL */
ac = 0;
XtSetArg(al[ac], XmNwidth, 300); ac++;
XtSetArg(al[ac], XmNheight, 300); ac++;
XtSetValues(toplevel, al, ac);
/* CREATE TOP LEVEL FORM MANAGER */
ac = 0;
busForm = XmCreateForm(toplevel, "busForm", al, ac);
XtManageChild(busForm);
/* CREATE SEND BUTTON WIDGET */
ac = 0;
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
XtSetArg(al[ac], XmNlabelString, XmStringCreateLtoR("Send", char_set)); ac++;
sendButton = XmCreatePushButton(busForm, "sendButton", al, ac);
XtManageChild(sendButton);
XtAddCallback(sendButton, XmNactivateCallback, sendButtonCB, NULL);
/* CREATE TEXT WIDGET */
ac = 0;
XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
XtSetArg(al[ac], XmNtopWidget, registerButton); ac++;
XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
XtSetArg(al[ac], XmNscrollingPolicy, XmVARIABLE); ac++;
XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++;
XtSetArg(al[ac], XmNscrollHorizontal, FALSE); ac++;
XtSetArg(al[ac], XmNeditable, FALSE); ac++;
textWidget = XmCreateScrolledText(busForm, "textWidget", al, ac);
XtManageChild(textWidget);
/* DISPLAY TOP LEVEL */
XtRealizeWidget(toplevel);
}
void displayMessage(char *textLineBuffer) {
pthread_mutex_lock(&textWidgetMutex);
XmTextInsert(textWidget, textWidgetLength, textLineBuffer);
textWidgetLength += strlen(textLineBuffer);
XtVaSetValues(textWidget, XmNcursorPosition, textWidgetLength, NULL);
XmTextShowPosition(textWidget, textWidgetLength);
pthread_mutex_unlock(&textWidgetMutex);
}
解决方案
我刚刚发现:
void displayMessage(char *textLineBuffer) {
pthread_mutex_lock(&textWidgetMutex);
XmTextInsert(textWidget, textWidgetLength, textLineBuffer);
textWidgetLength += strlen(textLineBuffer);
XmUpdateDisplay(textWidget);
pthread_mutex_unlock(&textWidgetMutex);
}
强制小部件重绘。
推荐阅读
- pyspark - 如何将 SnowflakeCursor 转换为 pySpark 数据框
- python - Pandas DataFrame 上的组特定计算
- mocha.js - 摩卡记者不支持并行模式,有吗?
- python - 设置对象没有属性 DATABASE
- docker - 如何在浏览器中查看运行在容器上的 Web 应用服务器的结果
- google-apps-script - 有没有办法使用谷歌应用脚本的 GMAIL API 来更新 gmail 的签名“在回复/转发使用时”?
- c# - 是否可以将两个数组作为单个命令相乘以提高代码性能?
- javascript - 为什么按照示例教程解析错误意外令牌<出现在PHP Javascript的以下代码行中?
- c++ - 从 std::tuple 中提取类型以获得方法签名
- sql - 如何在动态查询中两次使用临时表?