首页 > 解决方案 > Solved: Impossible to pass a Motif widget array as client_data in XtAddCallback?

问题描述

Greets all, what I've got is a much simplified snippet of a real program that has to update the label strings in 45 million Motif label widgets. Simplified version: I create two label widgets and set their label strings to "text." I place the two widgets into a standard C array and pass it as client_data to a callback function using XtAddCallback. The callback is invoked by a pushbutton and it's supposed to change the label strings from "text" to "different text," but it only changes the string in the first label widget. I'm assuming that for whatever reason the client_data (an XtPointer) that's supposed to have the two widget array actually only has the first widget. I realize full well that I could access the label widgets from the parent widget that's passed in as the first parameter in XtAddCallback, then use XtNameToWidget to get the labels, but that would entail 45 million calls to XtNameToWidget, which I'd rather avoid. I also realize I could put the all the label widgets into a global array, and then index over the array to change the label strings, but globals are also something I'd rather avoid. Another thing that's weird, if there is no second widget I would have thought that calling XtSetValues on it would crash the program, but it doesn't. So, if anyone's interested in taking a look at this (doubtful), here's the simplified snippet, if you name it arrays.c, it compiles (at least on Linux) with gcc -lXm -lXt -lX11 -o arrays arrays.c - Oh and for reasons that defy logical explanation, I'm being forced to use 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 %d\n", i);
        XtVaSetValues(*label_widgets[i], XmNlabelString, text, NULL);
    }
    XmStringFree(text);
}

标签: arrayscx11motif

解决方案


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数组的第 th 个元素,它恰好是 的 2 元素数组Widget,并采用该0ths 小部件。不用说,任何地方都没有数组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);

推荐阅读