【问题标题】:Signal handler of old window getting replaced by new windows signal handler GTK+旧窗口的信号处理程序被新窗口信号处理程序 GTK+ 替换
【发布时间】:2016-11-20 00:51:46
【问题描述】:

我的 GUI 应用程序有 2 个窗口。 主窗口销毁信号设置为使用gtk_main_quit 退出应用程序。

另一个窗口销毁信号被设置为使用方法gtk_widget_destroy销毁该特定窗口。

我们从主窗口启动另一个窗口。当我们点击关闭button(X)启动另一个窗口后,另一个窗口成功销毁但主窗口继续运行,到目前为止一切都很好。

现在,当我们点击主窗口关闭button(X) 时,它并没有退出整个应用程序,而只是破坏了主窗口,进程继续运行。

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

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

#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 循环,然后单击“其他”窗口上的按钮使用指针引用访问成员变量我的应用程序然后得到分段错误。

另外,我没有使用gtkmm,因为我必须在没有编译器支持的旧 Solaris 服务器上运行应用程序,因此我几乎没有限制。

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

【问题讨论】:

  • 为什么要运行多个主循环?
  • 我们不必为每个顶层窗口运行主循环。无论如何,如果您不运行 OtherWindow 主循环,它将转储核心(分段错误),正如我在帖子中提到的那样。它转储核心的原因是因为一旦 OtherWindow 被实例化,它就会立即被删除,因为中间没有阻塞函数,然后稍后在其信号处理程序中我们尝试使用对象引用时,它将转储核心,因为对象已经被释放。
  • 之前我确实只使用了一个主循环,但在我写这篇评论时它被丢弃了,我很确定我找到了解决方案。对于一些问题,当我提出问题时,只有我的大脑在工作,现在看看我发现了哪里出了问题。让我试着确认一下。感谢您让我的大脑足够努力地思考。!!
  • 哦,是的,我找到了
  • 感谢@jku 实际上在添加第二个主循环时我感觉这不是正确的做法,但后来我在互联网上找到了一个使用两个主循环的示例,所以我碰巧使用了那时我不知道是什么倾倒了核心。不管怎样,你让我重新思考,这让我现在感觉很轻松。

标签: c++ gtk gtk2


【解决方案1】:

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

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

因此,我通过引入一个主循环来处理段错误的方式是一个非常糟糕的主意,因为我们应该只使用一个主循环,因为引入更多的主循环会导致进一步的其他问题,如帖子中所述。

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

首先从 OtherWindow Constructor 中移除 gtk 主循环。

第二次动态创建OtherWindow对象如下:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2017-11-13
    • 1970-01-01
    相关资源
    最近更新 更多