简体   繁体   English

如何使 Motif Push Button 小部件显示为永久按下?

[英]How can I make Motif Push Button widget to appear as permanently pushed?

I have written a simple tool to select an audio channel in FreeBSD.我已经为 select FreeBSD 中的音频通道编写了一个简单的工具。

This is the code:这是代码:

xaudio.c 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;
}

devices.c:设备.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;
}

devices.h:设备.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

And the corresponding makefile (for FreeBSD):以及相应的 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

The program compiles and works (it switches the audio channel as expected).该程序编译并运行(它按预期切换音频通道)。 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. 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. Sort kind of "selectable button set".排序一种“可选按钮集”。

It is my understanding that such behaviour was achieved by the following widget parameter:据我了解,这种行为是通过以下小部件参数实现的:

XtVaSetValues(buttons[default_device].button, XmNset, True, NULL);

However, as seen here, this is not happening and the buttons appear always unclicked except the normal dynamic click effect when pressed.然而,正如此处所见,这并没有发生,按钮似乎总是未被点击,除了按下时的正常动态点击效果。

在此处输入图像描述

The desired behaviour you describe is what "radio buttons" are for.您描述的所需行为是“单选按钮”的用途。 In Motif, I believe you need the XmCreateRadioBox function.在 Motif 中,我相信您需要 XmCreateRadioBox function。

No, XmPushButton cant be configured to looked always pushed.不,不能将 XmPushButton 配置为看起来总是被按下。 Try using XmToggleButton instead of XmPushButton.尝试使用 XmToggleButton 而不是 XmPushButton。 Set XmNindicatorOn to False to get rid of the diamond checkbox.将 XmNindicatorOn 设置为 False 以去除菱形复选框。 Then XmNset,False will make it looked pressed.然后 XmNset,False 会让它看起来很压抑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM