如何解决gtkmm 小部件 - 使用智能指针还是指针?
我正在尝试学习如何使用 gtkmm 并基本掌握了 C++(我喜欢挑战!)。我一直在学习教程(以及其他阅读材料)。我正在尝试使用使用glade的方法来设计UI,然后编写代码来完成工作。
所以我构建了一个非常简单的用户界面(目前是窗口和按钮!)。我正在使用 GTK::Builder 从文件加载 UI。我将代码分为类和主要调用者。
这里是main.cpp
#include "hellowindow.h"
#include <gtkmm/application.h>
int main(int argc,char *argv[]) {
auto app = Gtk::Application::create(argc,argv,"org.gtkmm.example"); //creates a Gtk::Application object,stored in a Glib::RefPtr smartpointer,create() method for this object initializes gtkmm.
HelloWindow hw; // Create a HelloWindow object
return app->run(hw,argc,argv); // shows the HelloWindow object and enter the gtkmm main processing loop,will then return with an appropriate success or error code
}
这是 HelloWindow 类的标题
#ifndef HELLOWINDOW_H
#define HELLOWINDOW_H
#include <gtkmm/application.h>
#include <gtkmm/applicationwindow.h>
#include <gtkmm/button.h>
#include <gtkmm/box.h>
#include <gtkmm/builder.h>
#include <glibmm/fileutils.h>
/* derive the class from Gtk::ApplicationWindow base class */
class HelloWindow : public Gtk::ApplicationWindow {
public:
/* Conctructor */
HelloWindow();
/* Destructor */
~HelloWindow() override;
protected:
/* Signal handlers: */
void on_button_clicked();
/* Member widgets: */
Gtk::Box *cont; // Container
Gtk::Button *pButton; // Pointer to a Button
Glib::RefPtr<Gtk::Button> display_btn; // Smart pointer to a Button
Glib::RefPtr<Gtk::Builder> builder; // Builder
};
#endif // HELLOWINDOW_H
这是课程代码:
#include "hellowindow.h"
#include <iostream>
HelloWindow::HelloWindow() : builder(Gtk::Builder::create()){
try {
/* load window from glade file */
builder->add_from_file("glade/simple.glade");
}
catch(const Glib::FileError& ex) {
/* catch file errors */
std::cerr << "FileError: " << ex.what() << std::endl;
return;
}
/* ui builder created successfully from file */
/* add a container to the builder */
builder->get_widget<Gtk::Box>("cont",cont);
builder->get_widget<Gtk::Button>("display_button",pButton);
pButton->signal_clicked().connect(
sigc::mem_fun(*this,&HelloWindow::on_button_clicked)
);
/* add the container to the application window */
add(*cont);
/* set some parameters for the window */
set_title("Simple Gtk::Builder Demo"); // set the window title
set_default_size(500,500); // set the window size
show_all(); // show the window and all of the enclosed widgets
}
HelloWindow::~HelloWindow(){
}
void HelloWindow::on_button_clicked(){
std::cout << "Hello World" << std::endl;
}
这一切正常,我想我明白发生了什么。但是,我看到了一种在运行时添加小部件的不同方法 (https://sodocumentation.net/gtk3/topic/5579/using-glade-with-builder-api)。不同之处在于按钮对象的声明方式。在上面的代码中,它被声明为指向按钮对象的指针:
builder->get_widget<Gtk::Button>("display_button",pButton);
然而,上面的网站使用了一种指向按钮对象的智能指针的方法:
display_btn = Glib::RefPtr<Gtk::Button>::cast_dynamic(builder->get_object("display_button"));
第二种方法似乎不太清楚,特别是 cast_dynamic 方面,有人能解释一下这两种方法之间的区别吗?
我希望我已经包含了足够的信息。
谢谢
马丁
解决方法
首先,要了解区别,而且由于您是新手 C++,我建议阅读以下主题:
第一种方法:get_widget
通过这种方法,您将获得一个原始指针(而不是智能指针) 指针)指向从 ui 文件定义的 widget。示例:
Gtk::Grid* pGrid = nullptr;
refXml->get_widget("mygrid",pGrid);
此后,pGrid
指向一个 Gtk::Grid
小部件。请注意,没有
需要强制转换,您会立即获得 Gtk::Grid
。这是因为
Gtk::Builder::get_widget
方法是一个模板方法:
// T_Widget is like a placeholder for some widget type,// like Gtk::Grid for example.
template <class T_Widget >
void Gtk::Builder::get_widget(const Glib::ustring& name,T_Widget*& widget
)
通常在 C++ 中,例如
原始指针可能很危险,因为如果它们指向一个对象
在堆上分配(通常使用new
),必须记住使用
delete
完成后,否则会发生内存泄漏。在这
在这种情况下,pGrid
确实是指向分配在
堆,但是 documentation states:
请注意,您有责任删除顶级小部件(windows 和对话框)由 Builder 对象实例化。其他小部件是 实例化为托管,因此如果您将它们自动删除 将它们添加到容器小部件中。
所以大部分时间(即如果不是顶级小部件),您没有
调用 delete
,但有时你会这样做。这是因为 Gtkmm 有设施
自动 delete
销毁的对象。参见Gtk::manage
有关这方面的更多信息。
何时使用或不使用 delete
可能会随着代码的增长而变得困难,尤其是因为
您不必总是这样做(很容易忘记)。
第二种方法:get_object
通过这种方法,您将获得一个智能指针(Glib::RefPtr
)
需要一个 object 并转换为正确的类型,因此
cast_dynamic
// get_object returns a Glib::RefPtr<Glib::Object>,which is not a Glib::RefPtr<Gtk::Button>
// so a cast is performed. This works because Gtk::Button is a child class of
// Glib::Object.
display_btn = Glib::RefPtr<Gtk::Button>::cast_dynamic(builder->get_object("display_button"));
这样做的好处是一旦进行了演员表,
您不必管理对象的内存。它由
智能指针(即智能指针会自动调用 delete
为你。即使对于“顶级”小部件也是如此。
注意:这里使用的演员表 cast_dynamic
是一个 Gtkmm 特定的演员表,它包含一个 dynamic_cast
。
我的看法
我个人会采用第二种方法,因为你会自动 内存管理(即使是顶级小部件),因此没有内存泄漏。 但是,正如您已经注意到的那样,代码变得更难阅读了。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。