簡體   English   中英

gtkmm 小部件 - 使用智能指針或指針?

[英]gtkmm widgets - use smartpointers or pointers?

我正在嘗試學習如何使用 gtkmm 對 C++ 有基本的了解(我喜歡挑戰。)。 我一直在努力完成教程(以及其他閱讀)。 我正在嘗試使用 glade 的方法來設計 UI,然后編寫代碼來完成這項工作。

所以我構建了一個非常簡單的 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 class 的 header

#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

這是 class 代碼:

#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 )。 不同之處在於按鈕 object 的聲明方式。 在上面的代碼中,它被聲明為指向按鈕 object 的指針:

builder->get_widget<Gtk::Button>("display_button", pButton);

但是,上面的網站使用智能指針的方法指向按鈕 object:

display_btn = Glib::RefPtr<Gtk::Button>::cast_dynamic(builder->get_object("display_button"));

第二種方法似乎不太清楚,特別是 cast_dynamic 方面,有人可以解釋這兩種方法之間的區別嗎?

我希望我已經包含了足夠的信息。

謝謝

馬丁

首先,要了解區別,並且由於您是 C++ 的新手,我建議您閱讀以下主題:

第一種方法: get_widget

使用這種方法,您將獲得指向從 ui 文件定義的小部件的原始指針(而不是智能指針)。 例子:

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++ 中,這樣的原始指針可能是危險的,因為如果它們指向分配在堆上的 object(通常使用new ),必須記住在完成時對它們使用delete ,否則會發生 ZCD69B4957F06CD818D7BF3D61980E 泄漏。 在這種情況下, pGrid確實是指向在堆上分配的 object 的原始指針,但文檔指出

請注意,您負責刪除由 Builder object 實例化的頂級小部件(窗口和對話框)。 其他小部件被實例化為托管,因此如果您將它們添加到容器小部件,它們將被自動刪除。

所以大多數時候(即如果不是頂級小部件),您不必調用delete ,但有時您會這樣做。 這是因為 Gtkmm 具有自動delete被破壞對象的功能。 有關這方面的更多信息,請參閱Gtk::manage

隨着代碼的增長,何時使用或不使用delete可能會變得困難,尤其是因為您不必總是這樣做(它很容易忘記)。

第二種方法: get_object

使用這種方法,您將獲得指向 object 的智能指針( Glib::RefPtr ,並且需要轉換為正確的類型,因此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"));

這樣做的好處是,一旦執行了轉換,您就不必管理對象的 memory。 它由智能指針管理(即智能指針會自動為您調用delete 。即使對於“頂級”小部件也是如此。

注意:這里使用的演員cast_dynamic是一個 Gtkmm 特定的演員表,它包裝了一個dynamic_cast

我的意見

我個人會使用第二種方法 go 因為您可以獲得自動 memory 管理(即使對於頂級小部件),因此沒有 memory 泄漏。 但是,正如您已經注意到的那樣,代碼變得更難閱讀。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM