正确退出一个 gtkmm 应用程序

3
我正在使用Glade创建GUI,并且能够正确地连接信号。我试图添加一个按钮,以便简单地退出应用程序。
文档并没有非常清楚地说明如何实现这一点。在一些论坛上,你应该这样做:
Gtk::Main::quit(); 

我的应用程序退出了,但出现了分段错误。显然我应该直接从我的应用程序中调用quit(),如下所示:
p_application->quit(); 

但这会在编译时返回错误:
error: invalid use of member ‘GUI::p_application’ in static member function
     Glib::RefPtr<Gtk::Application> p_application;
                                    ^
error: from this location
     p_application->quit();
     ^

我使用以下内容创建了这个应用程序:
 p_application = Gtk::Application::create(argc, argv, "org.app.app");

我该怎么办?
2个回答

1

看起来您正在尝试从GUI的静态成员函数中访问p_application成员。

由于没有实例,因此无法从静态函数访问成员。将函数更改为非静态,或获取实例并在其上访问成员。


问题是,这个函数需要是静态的,否则我无法将其连接到按钮的信号。 - user96649
1
使用sigc::mem_fun或glibmm中的其他API将成员函数用作信号处理程序。 - ptomato

0

警告:我找到的所有在线文档都是针对gtkmm-4的。如果你还在使用Ubuntu上的gtkmm-3.0,那就从存储库下载你自己的文档(见下文)。我已经包含了gtkmm-4文档的链接,希望它们能有所帮助;但使用时请自行斟酌风险。

下面是适用于gtkmm-3.0的工作解决方案。使用以下命令进行编译:

 g++ helloworld.cc -o main `pkg-config --cflags --libs gtkmm-3.0`

代码:

// In file helloworld.cc
// sigc::mem_fun is the important part:
// it lets you turn a member function into a static one (or something).
// I don't really get it.
// I got most of the code here from https://www.gtk.org/docs/language-bindings/cpp

#include <iostream>

#include <sigc++/sigc++.h>            // Unnecessary, because the gtkmm modules also include mem_fun.
#include <glibmm/refptr.h>            // The wrapper object that Application::create returns.

#include <gtkmm/application.h>        // C++ wrapper for C's gtk_main.
#include <gtkmm/button.h>
#include <gtkmm/window.h>

class HelloWorld : public Gtk::Window
{
public:
    HelloWorld(Glib::RefPtr<Gtk::Application>);

protected:
    void on_button_clicked();

    Gtk::Button m_button;
    Glib::RefPtr<Gtk::Application> app;
};


// Constructor for window class. app should be a pointer to the Application instance you made in main.
HelloWorld::HelloWorld(Glib::RefPtr<Gtk::Application> app)
: m_button("Quit this program")     // Sets button label. I have no idea what this syntax is. C++ be whack, yo
{
    this->app = app;
    // mem_fun does most of the magic. How does it work? idk lol
    m_button.signal_clicked().connect(sigc::mem_fun(*this,
                            &HelloWorld::on_button_clicked));
    add(m_button);
    m_button.show();
}

void HelloWorld::on_button_clicked()
{
    std::cout << "Exiting the program now." << std::endl;
    this->app->quit();
    std::cout << "Note: Program doesn't actually end until this function finishes." << std::endl;
}

int main (int argc, char *argv[])
{
    Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
    HelloWorld helloworld(app);
    return app->run(helloworld);
}

我的想法是:我真的不太理解?

Gtk::Button.signal_clicked()(reference)返回一个Glib::SignalProxy<void()>。SignalProxy(reference)有模板<R(T...)>,我认为它描述了可以连接的函数类型--在这种情况下,具有返回类型void和空列表()的参数。SignalProxy.connect()返回我将忽略的内容,并接受SlotType&SlotType&&(我不知道区别是什么),其中SlotTypesigc::slot<R(T...)>,或在这种情况下是sigc::slot<void()>

sigc::slot<R(T...)>(reference)似乎非常基础。它看起来只是一个包装器,用于保存函数(可能是为了让SignalProxy在以后按钮被点击时调用它)。到目前为止,一切都很合理。

关于 sigc::mem_fun 的注释(参考资料)说它返回一个sigc::mem_functor,听起来很合理,但是mem_functor似乎不能满足SignalProxy.connect()所需的: sigc::slotsigc::mem_functor之间没有继承关系。令人困惑。我猜这里可能有某种未记录的类型强制转换?也许?另一个线索是mem_fun显然返回decltype(auto)类型的对象?我试着阅读了一下相关文档,然后他们开始谈论左值和非括号表达式,我的眼睛就变得模糊了。看看旧文档,以前有大约70个重载版本的mem_fun,现在一个版本就可以做到这一点,所以我猜decltype正在发挥作用。但是重点是,那是我放弃的地方。

decltype(auto)mem_functors是C++的深度魔法。mem_fun执行SignalProxy.connect()所需的操作,这就是我所知道的全部。

参考资料:

gtkmm-4.0文档

glibmm文档

sigc++文档

c中的gdk文档 << gtkmm引用了诸如“GdkEventKey”和来自头文件<gdk/gdkkeysyms.h>的枚举。我找不到关于此的C++参考资料,或者类似于“gdkmm”的任何内容。我认为可能是gtkmm直接使用C结构体来处理事件?

安装文档:我正在使用Ubuntu 20.04.3 LTS。您可以从存储库中安装gtk 3.0的html文档。请执行以下操作:sudo apt install libgtkmm-3.0-doc libglibmm-2.4-doc libsigc++-2.0-doc。如果要查找例如gtkmm的索引文件在哪里,请执行dpkg -L libgtkmm-3.0-doc | grep index。sigc++有多个索引文件,其中两个是陷阱。我无法弄清楚GDK的文档在哪里,可能是因为存储库中没有。请使用在线文档替代。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接