C++ GTKMM/C++;11:如何用其他小部件创建自定义复合小部件?

C++ GTKMM/C++;11:如何用其他小部件创建自定义复合小部件?,c++,c++11,widget,gtkmm,gtkmm3,C++,C++11,Widget,Gtkmm,Gtkmm3,我想派生我自己的小部件类,并将标准小部件添加到这个类中,以创建一个复合小部件。有没有人有关于如何做到这一点的例子或建议?例如,假设我想创建由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 // t

我想派生我自己的小部件类,并将标准小部件添加到这个类中,以创建一个复合小部件。有没有人有关于如何做到这一点的例子或建议?例如,假设我想创建由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);
}
//第一个问题:这是创建复合小部件的最佳方法吗?(见下文)
//第二个问题:如何使小部件容器在中展开
//水平方向,同时收缩
//垂直方向?因为我想让盒子水平扩展
//填充窗口,同时在垂直方向收缩到最小宽度
//方向
#包括
使用名称空间std;
#包括
类MyWidget:publicGTK::Frame{
公众:
MyWidget(){
添加(m_hbox1);
m_hbox1.pack_启动(m_vbox1,Gtk::PackOptions::pack_收缩);
m_vbox1.pack_start(m_hbox2,Gtk::PackOptions::pack_EXPAND_小部件);
m_hbox2.pack_start(m_btn_fwd,Gtk::PackOptions::pack_EXPAND_小部件);
m_hbox2.pack_start(m_btn_play,Gtk::PackOptions::pack_EXPAND_小部件);
m_hbox2.pack_start(m_btn_stop,Gtk::PackOptions::pack_EXPAND_小部件);
m_hbox2.pack_start(m_btn_back,Gtk::PackOptions::pack_EXPAND_小部件);
显示所有子项();
}
~MyWidget(){
}
私人:
Gtk::Box m_vbox1{Gtk::ORIENTATION_VERTICAL};
Gtk::Box m_hbox1{Gtk::ORIENTATION_HORIZONTAL};
Gtk::Box m_hbox2{Gtk::方向_水平};
Gtk::按钮m_btn_fwd{“fwd”};
Gtk::按钮m_btn_back{“back”};
Gtk::按钮m_btn_play{“play”};
Gtk::按钮m_btn_停止{“停止”};
};
类MyWindow:公共Gtk::Window{
公众:
MyWindow(字符串名称){
设置标题(名称);
添加(m_vbox);
//垂直收缩
m_vbox.pack_start(m_mywidget,Gtk::PackOptions::pack_SHRINK);
显示所有子项();
}
私人:
Gtk::Box m_vbox{Gtk::ORIENTATION_VERTICAL};
MyWidget m_MyWidget;
};
int main(int argc,char*argv[])
{
自动应用程序=Gtk::应用程序::创建(argc、argv、,
“org.gtkmm.example.actionbar”);
MyWindow窗口{“测试自定义组合小部件”};
//显示窗口并在关闭时返回。
返回应用程序->运行(窗口);
}

经过几周的实验,我的结论是,最好避免使用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);
}
使用名称空间std;
#包括
#包括
//======================================================
//搜索栏:一个示例GTKMM复合小部件/wmoore
//======================================================
类搜索栏{
公众:
搜索栏();
Gtk::Widget和operator();
公众:
Gtk::长方体{Gtk::方向_水平};
标签标签{“搜索:”};
Gtk::入口;
Gtk::按钮BtnOk{“find”};
Gtk::按钮BtnNext{“>”};

GTK::Button BtnPrev {“p>”,实际上可以从GTK:GTKMM中的GTK::WIDGET派生自定义的C++部件,虽然库需要相当多的附加代码,不仅用于合成复合文件,而且还用于遵循GTK::WIDGET接口规范。 我指的是一组虚拟方法,它们应该在您的实现中被覆盖,特别是:

  • 获取请求模式\u vfunc():(可选)返回什么Gtk::SizeRequestMode 是小部件的首选
  • 获取首选宽度\u vfunc():计算最小宽度和自然宽度 小部件的名称
  • 获取首选高度(vfunc():计算最小和自然高度
    小部件的高度
  • 为高度vfunc()获取首选宽度:计算最小值和 小部件的自然宽度,如果将其指定为 高度
  • 获取宽度vfunc()的首选高度::计算最小值和 小部件的自然高度,如果将其指定为 宽度
  • on\u size\u allocate():根据高度和位置定位小部件 实际给定的宽度
  • on_realize():将Gdk::窗口与小部件关联
  • on_unreaze():(可选)断开与 Gdk::窗口
  • 在地图上():(可选)
  • 取消映射()上的:(可选)
  • on_draw():在提供的Cairo::Context上绘制

gtkmm文档在gtkmm教程部分有一个很好的例子。

operator Gtk::Widget&
operator()更合适。