旧 window 的信号处理程序被新的 windows 信号处理程序 GTK+ 取代

Signal handler of old window getting replaced by new windows signal handler GTK+

我的 GUI 应用程序有 2 个 windows。 Main window destroy 信号设置为使用 gtk_main_quit.

退出应用程序

另一个 window 销毁信号被设置为使用方法 gtk_widget_destroy.

销毁特定的 window

我们从 Main window 启动另一个 window。在我们点击关闭 button(X) 时启动另一个 window 然后另一个 window 成功销毁但主要 window 保持 运行ning,到目前为止一切正常.

现在,当我们点击 Main windows close button(X) 时,它并没有退出整个应用程序,而只是破坏了 main window 并且进程继续 运行宁.

如果我不从主 window 启动另一个 window,那么一切正常,应用程序成功退出。

这是重现问题的示例代码:

#include <gtk/gtk.h>

#include <iostream>

using namespace std;

class OtherWindow {
    private:
        int number;

        GtkWidget* window;

        GtkWidget* button;

    public:
        OtherWindow(int num);

        static void read_number(GtkWidget *widget, gpointer data);

};

OtherWindow::OtherWindow(int num)
{
    number = num;
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    button = gtk_button_new_with_label("Read Number");

    gtk_container_add(GTK_CONTAINER(window), button);

    // signal handler
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_widget_destroy), NULL);

    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(OtherWindow::read_number), this);

    gtk_widget_show_all(window);

    gtk_main();

}

void OtherWindow::read_number(GtkWidget *widget, gpointer data)
{
    OtherWindow* other_win = static_cast<OtherWindow*>(data);
    cout << other_win->number << endl;
}

class MainWindow {

    private:
        GtkWidget* window;

        GtkWidget* button;

    public:
        MainWindow();

        static void open_other_window(GtkWidget *widget, gpointer data);
};


MainWindow::MainWindow()
{
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    button = gtk_button_new_with_label("Open Another Window");

    gtk_container_add(GTK_CONTAINER(window), button);

    // signal handler
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(MainWindow::open_other_window), NULL);

    gtk_widget_show_all(window);

    gtk_main();    
}

void MainWindow::open_other_window(GtkWidget *widget, gpointer data)
{
    OtherWindow other(10);
}

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

    MainWindow win;

}

还有一个疑问是,当我尝试从 OtherWindow 构造函数中删除 gtk_main 循环时,应用程序成功退出,但是如果我从 OtherWindow 构造函数中删除 gtk_main 循环,并且然后单击 Other window 上的按钮以使用指针引用访问成员变量我的应用程序然后出现分段错误。

我也没有使用 gtkmm 因为我有一些限制,因为我必须 运行 在没有编译器支持的旧 Solaris 服务器上应用程序。

从主 window 启动其他 windows 是很常见的事情,我想我缺少一些基本的东西。任何可以在这里提供帮助的东西。

还有一个问题在回答我自己。 这里首先要注意的是为什么我使用 @jku 指出的两个主循环。 我使用了两个主循环,因为之前只有一个循环,我的进程正在转储核心,我没有集中精力检查出了什么问题,而是开始以其他方式思考并插入了一个不需要的主循环。

现在,当我在我的 post 上写评论时,我突然想到了为什么它正在倾销核心。它是被释放的对象,我仍在 OtherWindow 的按钮的信号处理程序中使用其引用。 当我在堆栈上创建对象时,函数一结束对象就被删除,但后来在信号处理程序中尝试使用它时,它肯定会转储我刚刚知道的核心。

因此,我通过再引入一个主循环来处理段错误的方法是一个非常糟糕的主意,因为我们应该只使用一个主循环,因为引入更多主循环会导致其他问题,如 [=23] 中所述=].

因此,只需对上述代码进行少量更改即可使一切正常:

首先从 OtherWindow 构造函数中删除 gtk 主循环。

其次动态创建 OtherWindow 对象如下:

void MainWindow::open_other_window(GtkWidget *widget, gpointer data)
{
    OtherWindow* other = new OtherWindow(10);
}