c语言 - 无法在 XtAddCallback 中传递 Motif 小部件数组作为client_data?



大家打招呼,我得到的是一个真实程序的简化片段,它必须更新 4500 万个 Motif 标签小部件中的标签字符串。简化版:我创建了两个标签小部件,并将它们的标签字符串设置为"文本"。 我将这两个小部件放入一个标准的 C 数组中,并使用 XtAddCallback 将其作为client_data传递给回调函数。回调由按钮调用,它应该将标签字符串从"文本"更改为"不同文本",但它只更改第一个标签小部件中的字符串。我假设无论出于何种原因,应该具有两个小部件数组的client_data(XtPointer)实际上只有第一个小部件。我完全意识到我可以从作为 XtAddCallback 中的第一个参数传入的父小部件访问标签小部件,然后使用 XtNameToWidget 获取标签,但这需要 4500 万次调用 XtNameToWidget,我宁愿避免。我还意识到我可以将所有标签小部件放入一个全局数组中,然后在数组上索引以更改标签字符串,但全局也是我宁愿避免的东西。另一件奇怪的事情是,如果没有第二个小部件,我会认为在其上调用 XtSetValues 会导致程序崩溃,但事实并非如此。所以,如果有人有兴趣看看这个(值得怀疑),这里是简化的片段,如果你把它命名为 arrays.c,它使用 gcc -lXm -lXt -lX11 -o arrays arrays.c 编译(至少在 Linux 上) - 哦,出于违反逻辑解释的原因,我被迫使用 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,
0,
&argc,
argv,
NULL,
applicationShellWidgetClass,
av,
ac);
form = XtVaCreateManagedWidget("form",
xmFormWidgetClass, toplevel,
XmNheight,         100,
XmNwidth,          200,
NULL);
text = XmStringCreateLocalized((char *) "text");
label_01 = XtVaCreateManagedWidget("label_01",
xmLabelWidgetClass, form,
XmNwidth,           60,
XmNheight,          20,
XmNlabelString,     text,
XmNtopAttachment,   XmATTACH_WIDGET,
XmNtopWidget,       toplevel,
NULL);
label_02 = XtVaCreateManagedWidget("label_02",
xmLabelWidgetClass, form,
XmNwidth,           60,
XmNheight,          20,
XmNlabelString,     text,
XmNtopAttachment,   XmATTACH_WIDGET,
XmNtopWidget,       label_01,
NULL);
XmStringFree(text);
Widget label_widgets[2] = { label_01, label_02 };
button = XtVaCreateManagedWidget("button",
xmPushButtonWidgetClass, form,
XmNwidth,                60,
XmNheight,               20,
XmNtopAttachment,        XmATTACH_WIDGET,
XmNtopWidget,            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 %dn", i);
XtVaSetValues(*label_widgets[i], XmNlabelString, text, NULL);
}
XmStringFree(text);
}
XtAddCallback(button, XmNactivateCallback, pass_array_cb, *label_widgets);

*label_widgetslabel_widgets[0]完全相同,在您的情况下与label_01完全相同。您正在传递label_01作为回调参数。它具有类型Widget.

Widget (*label_widgets)[2] = (Widget (*)[2])client_data;

label_widgets现在是一个指向 2 元素数组的指针Widget,这与你作为参数传递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, XmNactivateCallback, pass_array_cb, label_widgets);

接收指向Widget数组的第一个元素的指针。

Widget* label_widgets = (Widget*)client_data;

使用指向其第一个元素的指针索引到上述数组(所有数组索引都以这种方式工作)。

XtVaSetValues(label_widgets[i], XmNlabelString, text, NULL);

最新更新