如何在 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。
因此,我的 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。