Motif 库 (C) 的水平绘制的 RowColumn Class?

Horizontally-Drawn RowColumn Class for Motif Library (C)?

我在工作中使用 Motif 库。如果有人不熟悉这个库,你可以在这里找到文件列表 https://packages.ubuntu.com/xenial/amd64/libmotif-dev/filelist, as well as another question here Motif 1.2 X11 on using RowColumn widget inside a ScrolledWindow.

我的问题是 xmRowColumnWidgetClass 是垂直绘制的,这意味着它是逐列绘制的(从左上角开始移动到左下角,然后向右移动到下一列,等等)

做这样的事情:

Widget parentWidget, rowColumn;

XtAppContext app;

parentWidget = XtVaAppInitialize(&app, "rowColumn", NULL, 0,
&argc, argv, NULL, NULL);

然后像这样:

rowColumn = XtVaCreateManagedWidget("rowcolumn",
            xmRowColumnWidgetClass,
            parentWidget,
            XmNnumColumns, 3,
            XmNpacking, XmPACK_COLUMN,
            XmNspacing, 6,
            NULL);

(void) XtVaCreateManagedWidget("button 1",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 2",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 3",
xmPushButtonWidgetClass, rowColumn, NULL);
        
(void) XtVaCreateManagedWidget("button 4",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 5",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 6",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 7",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 8",
xmPushButtonWidgetClass, rowColumn, NULL);

(void) XtVaCreateManagedWidget("button 9",
xmPushButtonWidgetClass, rowColumn, NULL);

所以上面的代码会像这样创建小部件:

button 1    button 4    button 7

button 2    button 5    button 8

button 3    button 6    button 9

我的问题是我想要某些并排而不是上下。

假设我指定这样的顺序:按钮 1、按钮 4、按钮 7、按钮 2、按钮 5、按钮 8、按钮 3、按钮 6、按钮 9。这看起来像这个:

button 1    button 2    button 3

button 4    button 5    button 6

button 7    button 8    button 9

但是,如果我想删除一个按钮或添加一个新按钮,这会把一切都搞砸。假设我从上面的例子中删除了“按钮 4”,所以顺序是这样的:按钮 1、按钮 7、按钮 2、按钮 5、按钮 8、按钮 3、按钮 6、按钮 9。看起来像这样:

button 1    button 5    button 6

button 7    button 8    button 9

button 2    button 3

如您所见,现在几乎没有任何东西应该并排在一起。

添加新按钮时也会出现此问题:假设我们要在末尾添加按钮 10:按钮 1、按钮 4、按钮 7、按钮 2、按钮 5、按钮 8、按钮 3、按钮 6、按钮 9、按钮 10。这看起来像这样:

button 1    button 5    button 9

button 4    button 8    button 10

button 7    button 3

button 2    button 6

到目前为止这看起来是最糟糕的,因为添加一个新按钮会将行的法线增加到 4 而不是 3,这会改变整个布局。


致所有熟悉此库的人:

如何创建水平(逐行)而不是垂直绘制的 xmRowColumnWidgetClass 实例? (逐列)

或者,我如何扩展这个库并可能制作一个 xmHorRowColumnWidgetClass 来做我想要的?


本库的另一组例子:
https://github.com/spartrekus/Motif-C-Examples
https://github.com/spartrekus/Motif-C-Examples/blob/master/rowcol.c

使用XmFormclass,玩转children的受限资源。您可以在child中生成XmATTACH_POSITION,并在表格中设置一个网格,使其(网格)随parent调整大小而拉伸和压缩。例如,您可以将 child 的四个边框附加到覆盖 parent (XmForm) 小部件的 4x3 单元假想网格,并将 children 附加到固定位置parent,所以如果你删除其中一个,这个洞就不会被邻居小部件填补。请参阅 XmForm 的文档,恕我直言,您应该使用该小部件。

keypad.c

下面是一个使用 int XmForm 的简单键盘示例,用于说明如何初始化资源。它显示了要触摸的最少硬连线资源。

/* main.c -- main program to create a keypad with an XmForm
                         widget.
 * Author: Luis Colorado <luiscoloradourcola@gmail.com>
 * Date: Tue Apr 21 16:15:28 EEST 2020
 * Copyright: (C) 2020 Luis Colorado.  All rights reserved.
 * License: BSD.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushBG.h>

#define F(_fmt) __FILE__":%d:%s: " _fmt, __LINE__, __func__

/* XmForm has a coordinate set based on a common denominator
 * that it applies to x and y coordinates, in order to subdivide
 * the grid (that has the same subdivisions along the x axis, as
 * it has along the y axis, so in order to make a 4x3 grid we
 * calculate the MCM(3, 4) = 12 to use as the denominator to
 * divide the x and y sides of it.  This makes the coordinates 
 * to go as the drawing marks.
 *      0   4   8  12
 *      +---+---+---+  0
 *      | 1 | 2 | 3 |
 *      +---+---+---+  3
 *      | 4 | 5 | 6 |
 *      *---+---+---+  6
 *      | 7 | 8 | 9 |
 *      +---+---+---+  9
 *      | * | 0 | # |
 *      +---+---+---+ 12
 */

struct but_desc {
        int left_x, top_y;
        int right_x, bot_y;
        char *name;
        char *out;
        void (*cb)(Widget, XtPointer, XtPointer);
};

void callback(Widget w, XtPointer data, XtPointer cd);

static struct but_desc
pos_tab[] = {
    { 4, 9,  8, 12, "b0",        "0", callback, },
        { 0, 0,  4,  3, "b1",        "1", callback, },
        { 4, 0,  8,  3, "b2",        "2", callback, },
        { 8, 0, 12,  3, "b3",        "3", callback, },
        { 0, 3,  4,  6, "b4",        "4", callback, },
        { 4, 3,  8,  6, "b5",        "5", callback, },
        { 8, 3, 12,  6, "b6",        "6", callback, },
        { 0, 6,  4,  9, "b7",        "7", callback, },
        { 4, 6,  8,  9, "b8",        "8", callback, },
        { 8, 6, 12,  9, "b9",        "9", callback, },
        { 8, 9, 12, 12, "bhash",     "#", callback, },
        { 0, 9,  4, 12, "basterisk", "*", callback, },
        { 0, 0,  0,  0, NULL, NULL, },
};

int
main(int argc, char **argv)
{
        XtAppContext app_ctx;
        char *class_name = "XKeypad";

        Widget topLevel = XtVaAppInitialize(
                &app_ctx,
                class_name,
                NULL, 0, /* XrmOptionDescRec array */
                &argc, argv, /* args to main */
                NULL, /* default resources */
                NULL); /* empty list of arguments */

        if (!topLevel) {
                fprintf(stderr,
                F("Couldnt create main widget"));
                exit(EXIT_FAILURE);
        }

        char *form_name = "form";
        Widget form = XtVaCreateManagedWidget(
        form_name,
                xmFormWidgetClass,
                topLevel,
                XmNfractionBase, 12,
                NULL);

        if (!form) {
                fprintf(stderr,
                        F("Couldn't create form '%s'\n"),
                        form_name);
                exit(EXIT_FAILURE);
        }

        struct but_desc *p;
        for (p = pos_tab; p->name; ++p) {
                printf(F("Creando botón '%s'@{(%d,%d),(%d,%d)}\n"),
                        p->name, p->left_x, p->top_y, p->right_x, p->bot_y);
                Widget button =
                        XtVaCreateManagedWidget(
                                        p->name,
                                        xmPushButtonGadgetClass,
                                        form,
                                        XmNleftAttachment, XmATTACH_POSITION,
                                        XmNrightAttachment, XmATTACH_POSITION,
                                        XmNtopAttachment, XmATTACH_POSITION,
                                        XmNbottomAttachment, XmATTACH_POSITION,
                                        XmNleftPosition, p->left_x,
                                        XmNrightPosition, p->right_x,
                                        XmNtopPosition, p->top_y,
                                        XmNbottomPosition, p->bot_y,
                                        NULL, NULL);
                if (!button) {
                        fprintf(stderr,
                                F("Couldnt create button '%s'\n"),
                                p->name);
                        exit(EXIT_FAILURE);
                }
                XtAddCallback(button, XmNactivateCallback, p->cb, p);
        }

        XtRealizeWidget(topLevel);
        XtAppMainLoop(app_ctx);

} /* main */

void callback(Widget w, XtPointer p, XtPointer cd)
{
        struct but_desc *data = p;
        write(1, data->out, strlen(data->out));
}

我在下面的示例代码中添加了 this repository。存储库包括一个 Makefile 和一个默认资源文件 (XKeypad)。

要使 xmRowColumnWidgetClass 实例水平绘制,请将 XmNorientation, XmHORIZONTAL 添加到代码中:

rowColumn = XtVaCreateManagedWidget("rowcolumn",
            xmRowColumnWidgetClass,
            parentWidget,
            XmNnumColumns, 3,
            XmNorientation, XmHORIZONTAL,
            XmNpacking, XmPACK_COLUMN,
            XmNspacing, 6,
            NULL);

这使得它是逐行绘制而不是逐列绘制。

出于某种原因,XmNnumColumns 现在指的是行数而不是列数,但这是一个单独的问题,因此上面的代码确实回答了我原来的问题。