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
使用XmForm
class,玩转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 现在指的是行数而不是列数,但这是一个单独的问题,因此上面的代码确实回答了我原来的问题。
我在工作中使用 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
使用XmForm
class,玩转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 现在指的是行数而不是列数,但这是一个单独的问题,因此上面的代码确实回答了我原来的问题。