回调函数不会修改小部件

问题描述 投票:0回答:1

我正在尝试制作一个用 C 编写的 GTK 4 应用程序。我想制作一个回调函数,该函数对下拉小部件中新选择的项目做出反应,并使用所选项目的值更新条目小部件。

仅当我将条目小部件设置为全局变量并直接在函数中使用它时,我的函数才有效。我更愿意传递一个指向该小部件的指针,并让回调函数以这种方式修改它。其他传递给小部件的指针的函数可以工作,但这个函数不想这样做。

//main.c
#include <gtk/gtk.h>
#include <windows.h>
#include <stdio.h>
#include <stdint.h>

#include "uiElements.h"


static void baudrateDropdownSelectCallback(GtkDropDown *dropdown, void *data[]);
static void activateApp(GApplication *app);


int main (int argc, char *argv[]) {

  //starting application
  return startApp("exe.GTKforSO", G_APPLICATION_DEFAULT_FLAGS, activateApp, argc, argv);
}

static void activateApp (GApplication *app) {

  static GtkWidget *win;
  static GtkWidget *box;

  //window
  win=initWindow(app, "GTKforSO", 400, 200);

  //box
  box=initBox(GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_window_set_child(GTK_WINDOW(win), box);

  static GtkWidget *baudrateDropdown;
  static GtkWidget *baudratesBox;
  static GtkWidget *baudrateEntry;
  static GtkEntryBuffer *baudrateEntryBuffer;


    /** the important part **/
      baudratesBox=initBox(GTK_ORIENTATION_HORIZONTAL, 10);
        gtk_box_append(GTK_BOX(box), baudratesBox);

      char *baudrates[]={"50", "75", "110", "134",
          "150", "200", "300", "600", "1200", "1800",
          "2400", "4800", "9600", "19200", "28800",
          "38400", "57600", "76800", "115200", "230400",
          "460800", "576000", "921600", NULL};
      baudrateDropdown=initDropDown(baudrates, 18); //dropdown widget with 'baudrates' list of items and 18th item selected
        gtk_box_append(GTK_BOX(baudratesBox), baudrateDropdown);

      void *selectedItem=gtk_drop_down_get_selected_item(GTK_DROP_DOWN(baudrateDropdown)); //getting selected item from dropdown widget
      const char *selectedBaudrate=gtk_string_object_get_string(GTK_STRING_OBJECT(selectedItem)); //getting item value as string
      baudrateEntryBuffer=gtk_entry_buffer_new((const char*)selectedBaudrate, strlen(selectedBaudrate)); //new entry buffer widget
      baudrateEntry=gtk_entry_new_with_buffer(GTK_ENTRY_BUFFER(baudrateEntryBuffer)); //new entry widget with buffer 'baudrateEntryBuffer'

      void *entryAndBuffer[2]={baudrateEntry, baudrateEntryBuffer}; //data to pass to callback
      g_signal_connect(baudrateDropdown, "notify::selected-item", G_CALLBACK(baudrateDropdownSelectCallback), entryAndBuffer); //connection to callback
        gtk_box_append(GTK_BOX(baudratesBox), baudrateEntry);
    /**/


  gtk_window_present(GTK_WINDOW(win));
}

static void baudrateDropdownSelectCallback(GtkDropDown *dropdown, void *data[]) {

    void *newlySelectedItem=gtk_drop_down_get_selected_item(GTK_DROP_DOWN(dropdown)); //getting selected item from dropdown widget
    char *selected=gtk_string_object_get_string(GTK_STRING_OBJECT(newlySelectedItem)); //getting item value as string

    GtkEntryBuffer *buffer;
    buffer=gtk_entry_buffer_new(selected, strlen(selected));
    data[1]=buffer; //replacing old buffer with new one

    gtk_entry_set_buffer(GTK_ENTRY(data[0]), data[1]);       //this doesn't work
  //gtk_entry_set_buffer(GTK_ENTRY(baudrateEntry), data[1]); //this works if static GtkWidget *baudrateEntry; is global variable
}
//uiElements.h
#ifndef UI_ELEMENTS_H
#define UI_ELEMENTS_H

#include <gtk/gtk.h>

typedef enum {
    NO_ENTRY=0,
    WITH_ENTRY=1
} withEntry;

int startApp(char *id, GApplicationFlags flags, void (*activateFunc), int argc, char *argv[]);
GtkWidget *initWindow(GApplication  *app, char *windowTitle, int windowWidth, int windowHeight);
GtkWidget *initBox(GtkOrientation orientation, int spacing);
GtkWidget *initDropDown(char *list[], uint8_t selectedByDefault);


#endif /* UI_ELEMENTS_H */
//uiElements.c
#include "uiElements.h"

int startApp(char *id, GApplicationFlags flags, void (*activateFunc), int argc, char *argv[]) {
    GtkApplication *app;
    int stat;

    app=gtk_application_new(id, flags);
    g_signal_connect(app, "activate", G_CALLBACK(activateFunc), NULL);
    stat=g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return stat;
}

GtkWidget *initWindow(GApplication  *app, char *windowTitle, int windowWidth, int windowHeight) {
    GtkWidget *win;
    win=gtk_application_window_new(GTK_APPLICATION(app));
    gtk_window_set_title(GTK_WINDOW(win), windowTitle);
    gtk_window_set_default_size(GTK_WINDOW(win), windowWidth, windowHeight);

    return win;
}

GtkWidget *initBox(GtkOrientation orientation, int spacing) {
    GtkWidget *box;
    box=gtk_box_new(orientation, spacing);
    gtk_box_set_homogeneous(GTK_BOX(box), TRUE);

    return box;
}

GtkWidget *initDropDown(char *list[], uint8_t selectedByDefault) {
    GtkStringList *stringList=gtk_string_list_new((const char * const *)list);
    GtkWidget *dropdown;
    dropdown=gtk_drop_down_new(G_LIST_MODEL(stringList), NULL);
    gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), selectedByDefault);

    return(dropdown);
}

c gcc gtk gnome gtk4
1个回答
0
投票

首先:非常感谢来自 discourse.gnome.orgyvs2014 的帮助!


显然回调函数应该声明为:

static void baudrateDropdownSelectCallback(GtkDropDown *dropdown, void *unused, void *data[])

解决方案可能与GNOME GTK Repository中的此功能实现有关:

static void
selected_item_changed (GtkDropDown *self,
                       GParamSpec  *pspec,
                       GtkListItem *list_item)
{
  GtkWidget *box;
  GtkWidget *icon;
  box = gtk_list_item_get_child (list_item);
  icon = gtk_widget_get_last_child (box);
  if (gtk_drop_down_get_selected_item (self) == gtk_list_item_get_item (list_item))
    gtk_widget_set_opacity (icon, 1.0);
  else
    gtk_widget_set_opacity (icon, 0.0);
}


它也适用于结构。这是一个用 WidgetStruct *data 替换 void *data[] 的工作代码。

//main.c
#include <gtk/gtk.h>
#include <windows.h>
#include <stdio.h>
#include <stdint.h>

#include "uiElements.h"


typedef struct {

   GtkWidget *win;
   GtkWidget *box;
   GtkWidget *baudrateDropdown;
   GtkWidget *baudratesBox;
   GtkWidget *baudrateEntry;
   GtkEntryBuffer *baudrateEntryBuffer;

} WidgetStruct;

WidgetStruct widgetStr;
WidgetStruct *widgetStrPtr=&widgetStr;

static void baudrateDropdownSelectCallback(GtkDropDown *dropdown, void *unused, WidgetStruct *data);
static void activateApp(GApplication *app);


int main (int argc, char *argv[]) {

  widgetStrPtr=g_new0(WidgetStruct, 1);

  //starting application
  return startApp("exe.GTKforSO", G_APPLICATION_DEFAULT_FLAGS, activateApp, argc, argv);
}

static void activateApp (GApplication *app) {

  static GtkWidget *win;
  static GtkWidget *box;

  //window
  win=initWindow(app, "GTKforSO", 400, 200);

  //box
  box=initBox(GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_window_set_child(GTK_WINDOW(win), box);

  static GtkWidget *baudrateDropdown;
  static GtkWidget *baudratesBox;
  static GtkWidget *baudrateEntry;
  static GtkEntryBuffer *baudrateEntryBuffer;


    /** the important part **/
      baudratesBox=initBox(GTK_ORIENTATION_HORIZONTAL, 10);
        gtk_box_append(GTK_BOX(box), baudratesBox);

      char *baudrates[]={"50", "75", "110", "134",
          "150", "200", "300", "600", "1200", "1800",
          "2400", "4800", "9600", "19200", "28800",
          "38400", "57600", "76800", "115200", "230400",
          "460800", "576000", "921600", NULL};
      baudrateDropdown=initDropDown(baudrates, 18); //dropdown widget with 'baudrates' list of items and 18th item selected
        gtk_box_append(GTK_BOX(baudratesBox), baudrateDropdown);

      void *selectedItem=gtk_drop_down_get_selected_item(GTK_DROP_DOWN(baudrateDropdown)); //getting selected item from dropdown widget
      const char *selectedBaudrate=gtk_string_object_get_string(GTK_STRING_OBJECT(selectedItem)); //getting item value as string
      baudrateEntryBuffer=gtk_entry_buffer_new((const char*)selectedBaudrate, strlen(selectedBaudrate)); //new entry buffer widget
      baudrateEntry=gtk_entry_new_with_buffer(GTK_ENTRY_BUFFER(baudrateEntryBuffer)); //new entry widget with buffer 'baudrateEntryBuffer'

    widgetStrPtr->box=box;
    widgetStrPtr->baudrateDropdown=baudrateDropdown;
    widgetStrPtr->baudratesBox=baudratesBox;
    widgetStrPtr->baudrateEntry=baudrateEntry;
    widgetStrPtr->baudrateEntryBuffer=baudrateEntryBuffer;

      g_signal_connect(baudrateDropdown, "notify::selected-item", G_CALLBACK(baudrateDropdownSelectCallback), widgetStrPtr); //connection to callback
        gtk_box_append(GTK_BOX(baudratesBox), baudrateEntry);
    /**/


  gtk_window_present(GTK_WINDOW(win));
}

static void baudrateDropdownSelectCallback(GtkDropDown *dropdown, void *unused, WidgetStruct *data) {

    WidgetStruct *_widgetStr=data;

    void *newlySelectedItem=gtk_drop_down_get_selected_item(GTK_DROP_DOWN(dropdown)); //getting selected item from dropdown widget

    const char *selected=gtk_string_object_get_string(GTK_STRING_OBJECT(newlySelectedItem)); //getting item value as string

    gtk_editable_set_text(GTK_EDITABLE(_widgetStr->baudrateEntry), selected);
}
© www.soinside.com 2019 - 2024. All rights reserved.