如何在 C 中的 GTK+ 单按钮单击事件中传递多个小部件

How to pass multiple widgets in a GTK+ single button click event in C

因此,我的 GTK 应用程序中的二维数组中有很多条目,如下所示:

GtkWidget *entries[10][10];
for(int i = 0; i < 10; i++){
        for(int j = 0; j < 10; j++){
                entries[i][j] = gtk_entry_new();
        }
}

还有一个按钮:

GtkWidget *btn;
btn = gtk_button_new_with_label("Calculate");

我希望,当用户点击按钮时,条目中的所有值都被传递给回调函数,以便对数据进行一些操作。

我有:

g_signal_connect(btn, "clicked", G_CALLBACK(calculate), entries);

还有一个名为 calculate() 的函数:

void calculate(GtkWidget *btn, gpointer data){
        double **values = (double **) data;
    
        for(int i = 0; i < 10; i++){
                for(int j = 0; j < 10; j++){
                    printf("%f ", gtk_entry_get_text(GTK_ENTRY(values[i][j])));
                }
        
                printf("\n");
        }
}

顾名思义就是要进行计算。事实上,我打算为此开发代码,但在此之前我需要获取条目中的数据。

为什么我获取数据不成功?

[更新]

我把g_signal_connect(btn, "clicked", G_CALLBACK(calculate), entries);改成了g_signal_connect(btn, "clicked", G_CALLBACK(calculate), &entries[0][0]);

现在计算的函数是:

void calculate(GtkWidget* btn, gpointer *data){ 
    GtkWidget **values = (GtkWidget **) data;
    
    for(int i = 0; i < 10; i++){
        for(int j = 0; j < 10; j++){
            printf("%s\n", gtk_entry_get_text(GTK_ENTRY(*(values+i) + j)));
        }
    }
}

我使用gtk_entry_get_text(GTK_ENTRY(*values))成功获取了第一个条目的文本,但是如何获取其他条目的文本?

已在 C++ 中解决

我不是 C Gtk+ 用户,但我能够让它在 Gtkmm 3.24(我更熟悉)下工作。下面是我的程序,应该是translatable到C语言:

#include <array>
#include <iostream>
#include <string>

#include <gtkmm.h>

class MainWindow : public Gtk::ApplicationWindow
{

public:

    MainWindow();

private:

    Gtk::Grid m_layout;

    Gtk::Button m_button;
    std::array<Gtk::Entry, 4> m_entries;

};

MainWindow::MainWindow()
: m_button{"Print entries content"}
{
    // Configuring entries:
    size_t count = 0u;
    for(auto& entry : m_entries)
    {
        entry.set_text("Entry #" + std::to_string(count));
        ++count;
    }

    // Configuring the button handler:
    m_button.signal_clicked().connect(
        [this]()
        {
            for(const auto& entry : m_entries)
            {
                std::cout << "Entry text : " << entry.get_text() << std::endl;
            }
        }
    );

    // Configuring window layout:
    m_layout.attach(m_entries[0], 0, 0, 1, 1);
    m_layout.attach(m_entries[1], 1, 0, 1, 1);
    m_layout.attach(m_entries[2], 0, 1, 1, 1);
    m_layout.attach(m_entries[3], 1, 1, 1, 1);
    m_layout.attach(m_button, 0, 2, 2, 1);

    // Adding the layout to the window:
    add(m_layout);
}

int main(int argc, char *argv[])
{
    std::cout << "Gtk(mm) version : " << gtk_get_major_version() << "."
                                      << gtk_get_minor_version() << "."
                                      << gtk_get_micro_version() << std::endl;

    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
  
    MainWindow window;
    window.show_all();
  
    return app->run(window);
}

顺便说一句,请注意这是我所理解的问题的(最小)简化版本。

关于您的代码片段的其他注释

查看您的代码,我看到了这一行:

double **values = (double **) data;

但是,当您连接时,您有:

g_signal_connect(btn, "clicked", G_CALLBACK(calculate), entries);

根据我对 GtkButton clicked 信号处理程序的理解,data 的类型应该匹配 entries,这是 GtkEntry 的 table .为什么,然后将其转换为 (double **)?

您弄乱了传递给回调函数的参数类型:

GtkWidget *entries[10][10];
for(int i = 0; i < 10; i++){
        for(int j = 0; j < 10; j++){
                entries[i][j] = gtk_entry_new();
        }
}
...

g_signal_connect(btn, "clicked", G_CALLBACK(calculate), entries);

这定义了一个 10*10 指针的数组。

但是你告诉你的编译器把它当作一个指向指针的指针:

void calculate(GtkWidget *btn, gpointer data){
        double **values = (double **) data;

这表明内存布局非常不同。 二维数组与指向指针的指针不同。除此之外,您的数组本身包含指针,而不是 double 值。

你需要的是:

void calculate(GtkWidget *btn, gpointer data){
       GtkWidget*(*values)[10] = (GtkWidget*(*)[10])data;
...

这应该可以解决您正确处理条目的问题。

此外,您可能 运行 遇到另一个问题。 如果数组 entries 在你的回调函数被调用时不再有效,你有一个非法的内存访问导致未定义的行为。

您必须将该数组设为静态或全局。或者您必须确保执行初始化的函数,在应用程序终止之前永远不会 returns。