[英]How can I make Motif Push Button widget to appear as permanently pushed?
我已经为 select FreeBSD 中的音频通道编写了一个简单的工具。
这是代码:
xaudio.c
#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xm/MainW.h>
#include <Xm/RowColumn.h>
#include <stdio.h>
#include <stdlib.h>
#include "devices.h"
struct button_data {
int device_num;
Widget button;
};
/* GLOBAL VARIABLES */
int num_devices;
struct device *devices;
struct button_data *buttons;
void button_callback(Widget widget, XtPointer client_data, XtPointer call_data);
void create_device_buttons(Widget parent, struct device *devices, int num_devices);
void button_callback(Widget widget, XtPointer client_data, XtPointer call_data) {
int i;
struct button_data *data = (struct button_data *)client_data;
int device_num = data->device_num;
// unclick all other buttons
for (i = 0; i < num_devices; i++) {
if (buttons[i].button != widget) {
XtVaSetValues(buttons[i].button, XmNset, False, NULL);
}
}
// click this button
XtVaSetValues(widget, XmNset, True, NULL);
// set audio device
set_audio_device(device_num);
}
void create_device_buttons(Widget parent, struct device *devices, int num_devices) {
int i;
XmString label;
struct button_data *data;
Arg args[5];
int n;
buttons = malloc(num_devices * sizeof(struct button_data));
if (buttons == NULL) {
perror("Failed to allocate memory");
exit(EXIT_FAILURE);
}
for (i = 0; i < num_devices; i++) {
// create button
n = 0;
label = XmStringCreateLocalized(devices[i].description);
XtSetArg(args[n], XmNlabelString, label); n++;
buttons[i].button = XmCreatePushButton(parent, "device_button", args, n);
XmStringFree(label);
XtManageChild(buttons[i].button);
// set button data
buttons[i].device_num = devices[i].number;
// set button callback
XtAddCallback(buttons[i].button, XmNactivateCallback, button_callback, &buttons[i]);
}
}
int main(int argc, char *argv[]) {
XtAppContext app;
Widget top_level, main_window, button_rowcolumn;
int default_device;
int n=0;
Arg args[10];
top_level = XtVaOpenApplication(&app, "XAudio", NULL, 0, &argc, argv, NULL, sessionShellWidgetClass, NULL);
main_window = XmCreateMainWindow(top_level, "main_window", NULL, 0);
XtManageChild(main_window);
n=0;
XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
button_rowcolumn = XmCreateRowColumn(main_window, "button_rowcolumn", args, n);
XtManageChild(button_rowcolumn);
/* GET LIST OF DEVICES AND DEFAULT DEVICE */
default_device = get_default_device(&devices, &num_devices);
int i=0;
for(i=0; i<num_devices; i++) {
printf("%d %s\n", devices[i].number, devices[i].description);
}
create_device_buttons(button_rowcolumn, devices, num_devices);
XtRealizeWidget(top_level);
/* CLICK DEFAULT BUTTON */
if (default_device >= 0) {
XtVaSetValues(buttons[default_device].button, XmNset, True, NULL);
}
XtAppMainLoop(app);
free(devices);
free(buttons);
return 0;
}
设备.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct device {
int number;
char description[256];
};
void set_audio_device(int device_num) {
char command[256];
sprintf(command, "sysctl hw.snd.default_unit=%d", device_num);
system(command);
}
int get_default_device(struct device **devices, int *num_devices) {
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
int num_dev = 0;
int default_device = -1;
fp = popen("cat /dev/sndstat", "r");
if (fp == NULL) {
perror("Failed to run command");
exit(EXIT_FAILURE);
}
while ((read = getline(&line, &len, fp)) != -1) {
if (strstr(line, "pcm") == line) {
// line starts with "pcm", so it is a device line
// increase number of devices and reallocate memory
num_dev++;
*devices = realloc(*devices, num_dev * sizeof(struct device));
if (*devices == NULL) {
perror("Failed to allocate memory");
exit(EXIT_FAILURE);
}
// get device number
sscanf(line, "pcm%d:", &(*devices)[num_dev - 1].number);
// get description
char *start = strchr(line, '<');
char *end = strchr(line, '>');
if (start != NULL && end != NULL) {
int length = end - start - 1;
strncpy((*devices)[num_dev - 1].description, start + 1, length);
(*devices)[num_dev - 1].description[length] = '\0';
}
// check if this is the default device
if (strstr(line, "default") != NULL) {
default_device = num_dev - 1;
}
}
}
*num_devices = num_dev;
pclose(fp);
return default_device;
}
设备.h:
#ifndef DEVICES_H
#define DEVICES_H
#include <stdio.h>
#include <stdlib.h>
struct device {
int number;
char description[256];
};
void set_audio_device(int device_num);
int get_default_device(struct device **devices, int *num_devices);
#endif
以及相应的 makefile(对于 FreeBSD):
CC = cc
CFLAGS = -Wall -Wextra -I/usr/local/include
LDFLAGS = -Wall -Wextra -L/usr/local/lib -lXm -lXt -lX11
all: xaudio
xaudio: xaudio.o devices.o
$(CC) $(LDFLAGS) -o $@ xaudio.o devices.o
xaudio.o: xaudio.c devices.h
$(CC) $(CFLAGS) -c -o $@ $<
devices.o: devices.c devices.h
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o xaudio
该程序编译并运行(它按预期切换音频通道)。 However, my intended behaviour was that the channel selected appeared as a permanently pushed button, and that when a new channel was selected the pushed button changed accordingly. 排序一种“可选按钮集”。
据我了解,这种行为是通过以下小部件参数实现的:
XtVaSetValues(buttons[default_device].button, XmNset, True, NULL);
然而,正如此处所见,这并没有发生,按钮似乎总是未被点击,除了按下时的正常动态点击效果。
您描述的所需行为是“单选按钮”的用途。 在 Motif 中,我相信您需要 XmCreateRadioBox function。
不,不能将 XmPushButton 配置为看起来总是被按下。 尝试使用 XmToggleButton 而不是 XmPushButton。 将 XmNindicatorOn 设置为 False 以去除菱形复选框。 然后 XmNset,False 会让它看起来很压抑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.