使用GtkFileChooserButton和GtkFileChooserDialog的区别

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

我想让用户选择两个目录,然后在单击按钮后检索其URI,以便将它们传递给另一个函数。现在,我尝试着做一些事情:

directory1 = gtk_file_chooser_button_new ("Choose directory 1",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);

目录2相同。然后将它们放入struct

struct directories {
    GtkWidget *first;
    GtkWidget *second;
};

struct directories directory;
    directory.first = directory1;
    directory.second = directory2;

并且在单击按钮后将其传递给函数,该函数当前不执行任何操作,但尝试检索URI并打印它们。

g_signal_connect(button, "clicked", G_CALLBACK(print_test), &directory);

print_test (struct directories *dirc)
{
    g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->first)));
    g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->second)));
}

[我也尝试用GTK_FILE_CHOOSER替换GTK_FILE_CHOOSER_BUTTON,但结果是相同的:我的程序已编译,我选择了一些目录,并在激活按钮后崩溃,打印出一个]

(null)

和以下调试信息

GLib-GObject-WARNING **: 02:52:03.786: invalid uninstantiatable type 'gchararray' in cast to 'GtkFileChooserButton'
Gtk-CRITICAL **: 02:52:03.786: gtk_file_chooser_get_uri: assertion 'GTK_IS_FILE_CHOOSER (chooser)' failed

我以为gtk_file_chooser_button是一个很好的解决方案,因为它似乎比手动建立对话框更容易使用,但是现在我开始质疑是否可以那样使用它,或者我的程序失败是错误的传递方法的错误指向print_test的指针。不幸的是,我发现的所有示例都集中在使用对话框上,因此我没有找到一个好的示例来学习如何使用gtk_file_chooser_button。

编辑:根据请求,我展示我的代码示例。我只删除了与该问题无关的其他类型的按钮,并执行了第一个注释中所述的更改,因此与上述问题相比,您可以观察到两行的细微差别。

#include <stdio.h>
#include <gtk/gtk.h>

struct directories {
    GtkWidget *first;
    GtkWidget *second;
};

static void
print_test (GtkWidget *somewidget, struct directories *dirc)
{
    g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->first)));
    g_print("%s\n", gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dirc->second)));
}

static void
set_expand (GtkWidget *widget)
{
    gtk_widget_set_hexpand(widget, 1);
    gtk_widget_set_vexpand(widget, 1);
}

static void
activate (GtkApplication* app,
          gpointer        user_data)
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *frame;
    GtkWidget *settings;
    GtkWidget *directory1;
    GtkWidget *directory2;
    GtkWidget *button;

    //Prepare the window
    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Sagger");
    gtk_window_set_default_size (GTK_WINDOW (window), 400, 200);
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);

    //Prepare the grid
    grid = gtk_grid_new();
    //gtk_grid_set_column_homogeneous(grid, 1);
    //gtk_widget_set_halign (grid, GTK_ALIGN_FILL);
    //gtk_widget_set_valign (grid, GTK_ALIGN_FILL);
    set_expand(grid);
    gtk_container_add(GTK_CONTAINER(window), grid);

    //Prepare directory chooser
    settings = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    frame = gtk_frame_new("Choose directories");
    set_expand(settings);
    gtk_container_add(GTK_CONTAINER(frame), settings);
    directory1 = gtk_file_chooser_button_new ("Source directory",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
    set_expand(directory1);
    gtk_container_add(GTK_CONTAINER(settings), directory1);
    directory2 = gtk_file_chooser_button_new ("Target directory",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
    set_expand(directory2);
    gtk_container_add(GTK_CONTAINER(settings), directory2);
    gtk_grid_attach(grid, frame, 0, 0, 2, 1);

    //Prepare the run button
    settings = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
    gtk_button_box_set_layout(GTK_BUTTON_BOX(settings), GTK_BUTTONBOX_EXPAND);
    set_expand(settings);
    gtk_grid_attach(grid, settings, 0, 2, 2, 1);
    button = gtk_button_new_with_label("RUN");

    //Try to pass the chosen directories
    struct directories directory;
    directory.first = directory1;
    directory.second = directory2;
    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(print_test), (gpointer) &directory);

    gtk_container_add(GTK_CONTAINER(settings), button);

    gtk_widget_show_all (window);
}

int
main (int    argc,
      char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("pl.etua.sagger", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}
c gtk gtk3
1个回答
0
投票

directory对于activate()函数而言是本地的,并且如注释中所述,超出范围将被销毁。稍后,在单击按钮时调用print_test()函数时,它将尝试访问该内存,从而导致分段错误。

两种简单的解决方法:

directory全局设置为:

struct directories {
    GtkWidget *first;
    GtkWidget *second;
};
struct directories directory;

或使其在activate()中为静态:

static struct directories directory;
© www.soinside.com 2019 - 2024. All rights reserved.