GTKMM/C 11:如何从其他小部件中创建自定义的复合小部件

GTKMM/C++11: How to create a custom composite widget out of other widgets?

本文关键字:小部 创建 自定义 复合 其他 GTKMM      更新时间:2023-10-16

我想得出自己的小部件类,并在此类中添加标准小部件以创建一个复合的小部件。有人有关于如何执行此操作的例子或建议吗?例如,假设我想创建4个按钮的自定义复合小部件。我猜它类似于下面的代码:

//First Question:  Is this the best way to create composite widget? (see below)
//Second Question:  How do you make a widget container expand in 
// the horizontal direction while at the same time shrink in 
// the vertical direction?  because i wanted the boxes to expand horizontally
// to fill the window, and at the same time shrink to minimum width in the vertical
// direction

#include <iostream>
using namespace std;
#include <gtkmm.h>
class MyWidget : public Gtk::Frame {
  public:
    MyWidget() {
        add(m_hbox1);
        m_hbox1.pack_start  (m_vbox1,    Gtk::PackOptions::PACK_SHRINK);
        m_vbox1.pack_start  (m_hbox2,    Gtk::PackOptions::PACK_EXPAND_WIDGET);
        m_hbox2.pack_start  (m_btn_fwd,  Gtk::PackOptions::PACK_EXPAND_WIDGET);
        m_hbox2.pack_start  (m_btn_play, Gtk::PackOptions::PACK_EXPAND_WIDGET);
        m_hbox2.pack_start  (m_btn_stop, Gtk::PackOptions::PACK_EXPAND_WIDGET);
        m_hbox2.pack_start  (m_btn_back, Gtk::PackOptions::PACK_EXPAND_WIDGET);
        show_all_children();
    }
    ~MyWidget() {
    }
  private:
    Gtk::Box    m_vbox1    {Gtk::ORIENTATION_VERTICAL};
    Gtk::Box    m_hbox1    {Gtk::ORIENTATION_HORIZONTAL};
    Gtk::Box    m_hbox2    {Gtk::ORIENTATION_HORIZONTAL};
    Gtk::Button m_btn_fwd  {"Fwd"};
    Gtk::Button m_btn_back {"Back"};
    Gtk::Button m_btn_play {"Play"};
    Gtk::Button m_btn_stop {"Stop"};
};
class MyWindow : public Gtk::Window {
  public:
    MyWindow(string name) {
       set_title(name);
       add(m_vbox);
       // Shrink in Vertical Direction
       m_vbox.pack_start(m_mywidget, Gtk::PackOptions::PACK_SHRINK);
       show_all_children();
    }
  private:
    Gtk::Box    m_vbox      {Gtk::ORIENTATION_VERTICAL};
    MyWidget    m_mywidget;
};
int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create(argc, argv,
     "org.gtkmm.example.actionbar");
  MyWindow window {"Testing Custom Composite Widget"};
  // Shows the window and returns when it is closed.
  return app->run(window);
}

经过几周的实验,我的结论是,更好地避免使用C 从GTK :: widget继承以创建复合的小部件。相反,最好将GKTMM中的复合小部件作为纯容器类别,即。不是从任何类中得出的,而是要超载C 11函数运算符以返回由对象的构造函数预先包装的gtk :: box小部件,并使用制造复合组件所需的所有小部件。示例:

using namespace std;
#include <gtkmm.h>
#include <iostream>
//======================================================
// SearchBar: An Example GTKMM Composite Widget / wmoore
//======================================================
class SearchBar {
  public:
     SearchBar();
     Gtk::Widget& operator()();
  public:
     Gtk::Box    box {Gtk::ORIENTATION_HORIZONTAL};
     Gtk::Label  label {"search: "};
     Gtk::Entry  entry;
     Gtk::Button BtnOk{"find"};
     Gtk::Button BtnNext{">"};
     Gtk::Button BtnPrev{"<"};
};
inline SearchBar::SearchBar() {
  box.pack_start(label);
  box.pack_start(entry, Gtk::PACK_EXPAND_WIDGET);
  box.pack_end(BtnNext);
  box.pack_end(BtnPrev);
  box.pack_end(BtnOk);
}
inline Gtk::Widget& SearchBar::operator()() {
  return box;
}
class MyWindow : public Gtk::Window {
  public:
    MyWindow(string name) {
       set_title(name);
       add(m_vbox);
       // Shrink in Vertical Direction
       m_vbox.pack_start(m_searchbar(), Gtk::PackOptions::PACK_SHRINK);  
                        // ^^^ NOTE use of C++11 functor operator "()"
                        // added to end of object name
                        // that makes it easy to tell difference between 
                        // Gtk::Widget and Composite widget's built 
                       // from many Gtk::Widget's
      ////Example Connecting of Signals to composite widget:
      // m_searchbar.BtnOk.signal_clicked.connect([]() {
      //     cout << "clicked button!n";})
       show_all_children();
    }
  private:
    Gtk::Box    m_vbox      {Gtk::ORIENTATION_VERTICAL};
    SearchBar   m_searchbar;
};
int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create(argc, argv,
     "org.gtkmm.example.actionbar");
  MyWindow window {"Testing Custom Composite Widget"};
  // Shows the window and returns when it is closed.
  return app->run(window);
}

使用纯容器类,而不是从GTK :: Widte创建复合小部件的纯粹的容器类别的原因如下:

(1)GTKMM的小部件API非常多,并且倾向于隐藏任何新的公共方法,您将其添加到复合窗口小部件中,以混乱的gtkmm widget方法,您可能无论如何都不会使用。为此原因。最好将所有您的容器小部件对象添加到类的公共部分中,包括Toplevel Box小部件。您仍然可以访问没有GTKMM API混乱的每个对象小部件的所有方法。

(2)从GTK ::窗口小部件遗传您的类并没有真正使您在多态性行为方面有用的东西,因为复合小部件的小部件已经是从GTK :: widget得出的多态性对象。当您将高级小部件框添加到父窗口小部件时,您的复合小部件的所有儿童小部件都将添加到父母小部件的孩子列表中。因此,对于复合小工具容器,实际上不需要具有多态性行为。

(3)如果您需要从GTK派生的复合小部件:窗口小部件很容易将类包装器围绕在其周围,将其转换为从GTK :: Widget派生的类。实际上,通过对模板类包装器的一条实例化可以轻松完成此步骤。我想这样做的唯一原因是将组件插入GLADE中(缺少GUI的GUI,识别C 11函子操作员是返回复合窗口小部件的高级小部件的标准方法(可以让Glade支持Glade In In In In未来?愿望清单...))

实际上可以从gtk :: widget in gtkmm 中派生一个自定义的C 小部件复合optote,但要粘附到GTK ::窗口小部件界面规范。

我指的是一组虚拟方法,这些方法应在您的实现中覆盖,特别是:

  • get_request_mode_vfunc() :(可选)返回what what gtk :: sizerequestmode小部件首选。
  • get_preferred_width_vfunc():计算最小和自然宽度小部件的。
  • get_preferred_height_vfunc():计算最小值和天然
    小部件的高度。
  • get_preferred_width_for_height_vfunc():计算最小值和如果给出指定的小部件的自然宽度身高。
  • get_preferred_height_for_width_vfunc():计算最小值和小部件的自然高度,如果给出了指定的宽度。
  • on_size_allocate():给定高度和实际上给出了它的宽度。
  • on_realize():将gdk ::窗口与窗口相关联。
  • on_unrealize() :(可选)打破与GDK :: Window。
  • on_map() :(可选)
  • on_unmap() :(可选)
  • on_draw():在提供的开罗:: context。

GTKMM文档在GTKMM-Tutorial部分中有一个可靠的示例。