问题描述
大家好,我得到的是一个真实程序的简化片段,该程序必须更新 4500 万个 Motif 标签小部件中的标签字符串。简化版:我创建了两个标签小部件并将它们的标签字符串设置为“文本”。我将这两个小部件放入标准 C 数组中,并将其作为 client_data 传递给使用 XtAddCallback 的回调函数。回调由按钮调用,它应该将标签字符串从“文本”更改为“不同文本”,但它只更改第一个标签小部件中的字符串。我假设无论出于何种原因,应该具有两个小部件数组的 client_data(一个 XtPointer)实际上只有第一个小部件。我很清楚我可以从作为 XtAddCallback 中第一个参数传入的父小部件访问标签小部件,然后使用 XtNametoWidget 来获取标签,但这将需要对 XtNametoWidget 进行 4500 万次调用,我宁愿避免这种情况。我也意识到我可以将所有标签小部件放入一个全局数组,然后在数组上索引以更改标签字符串,但全局变量也是我宁愿避免的。另一件很奇怪的事情是,如果没有第二个小部件,我会认为在其上调用 XtSetValues 会使程序崩溃,但事实并非如此。所以,如果有人有兴趣看看这个(可疑),这里是简化的片段,如果你将它命名为 arrays.c,它编译(至少在 Linux 上)使用 gcc -lXm -lXt -lX11 -o arrays arrays.c - 哦,出于不符合逻辑解释的原因,我被迫使用 Motif-2.1.32
/* Impossible to pass a widget array using XtAddCallback? */
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <stdio.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
void pass_array_cb(Widget,XtPointer,XtPointer);
int main(int argc,char * argv[])
{
XtAppContext app_context;
xmstring text;
Widget toplevel;
Widget form,button,label_01,label_02;
Arg av[10];
int ac = 0;
toplevel = XtOpenApplication(
&app_context,"arrays",NULL,&argc,argv,applicationShellWidgetClass,av,ac);
form = XtVaCreateManagedWidget("form",xmFormWidgetClass,toplevel,XmNheight,100,XmNwidth,200,NULL);
text = xmstringCreateLocalized((char *) "text");
label_01 = XtVaCreateManagedWidget("label_01",xmLabelWidgetClass,form,60,20,XmNlabelString,text,XmNtopAttachment,XmATTACH_WIDGET,XmNtopWidget,NULL);
label_02 = XtVaCreateManagedWidget("label_02",NULL);
xmstringFree(text);
Widget label_widgets[2] = { label_01,label_02 };
button = XtVaCreateManagedWidget("button",xmpushButtonWidgetClass,label_02,NULL);
XtAddCallback(button,XmNactivateCallback,pass_array_cb,*label_widgets);
XtRealizeWidget (toplevel);
XtAppMainLoop (app_context);
return 0;
}
void pass_array_cb(Widget w,XtPointer client_data,XtPointer call_data)
{
Widget (*label_widgets)[2] = (Widget (*)[2])client_data;
xmstring text = xmstringCreateLocalized((char *)"different text");
int i;
for(i = 0; i < 2; i++)
{
printf("in the callback,widget index is %d\n",i);
XtVaSetValues(*label_widgets[i],NULL);
}
xmstringFree(text);
}
解决方法
XtAddCallback(button,XmNactivateCallback,pass_array_cb,*label_widgets);
*label_widgets
与 label_widgets[0]
完全相同,在您的情况下与 label_01
完全相同。您将 label_01
作为回调参数传递。它的类型为 Widget
。
Widget (*label_widgets)[2] = (Widget (*)[2])client_data;
label_widgets
现在是指向 Widget
的 2 元素数组的指针,它与您作为参数传递的 Widget
非常非常不同。
XtVaSetValues(*label_widgets[i],XmNlabelString,text,NULL);
*label_widgets[i]
与 label_widgets[i][0]
相同。由于 label_widgets
是一个指针(见上文),因此它被视为指向数组第一个元素的指针。什么数组?二元素数组或Widget
。所以它需要该数组的第 i
个元素,它恰好是一个 Widget
的 2 元素数组,并获取它的第 0
个小部件。不用说,任何地方都没有 Widget
的数组,所以这段代码只是徘徊在 La-La Land 上。
你想要这个:
传递一个指向 label_widgets
的第一个元素的指针。查看数组到指针衰减了解更多信息。
XtAddCallback(button,label_widgets);
接收指向 Widget
数组第一个元素的指针。
Widget* label_widgets = (Widget*)client_data;
使用指向第一个元素的指针对上述数组进行索引(所有数组索引都是这样工作的)。
XtVaSetValues(label_widgets[i],NULL);