Cross posting this from my post on Stack Overflow.  Thought it would be
useful discussion for this mailing list.

0down votefavorite
<http://stackoverflow.com/questions/41344241/gtkmm-c11-how-to-create-a-custom-composite-widget-out-of-other-widgets/41791719#>

I want to derive my own widget class and add standard widgets to this class
to create a composite widget. Does anybody have an examples or suggestions
on how to do this? For example, Suppose I want to create custom composite
widget of 4 buttons. I'm guessing its something like the code below:

//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);}


After a few weeks of experimentation, my conclusion is that its better to
avoid using c++ to inherit from a Gtk::Widget in order to create a
composite widget. Instead its better to make a composite widget in gktmm as
a pure container class, ie. not derived from any classes, and to overload
the C++11 Functor operator to return a Gtk::Box Widget that is pre-packed
by the object's constructor with all the widgets needed to make the
composite component. Example:

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);}

The reason for using pure container classes rather than inheritance from
Gtk::Widget to create a composite widget are as follows:

(1) the Widget api's for gtkmm are very numerous and tend to hide any new
public methods that you add to your composite widget in a mess of gtkmm
widget method's that you probably won't use anyways. For this reason. its
better to add all your container widget object into a public section of the
class including the toplevel box widget. You will still have access to all
the methods of each object widget without the gtkmm api clutter.

(2) Inheriting your class from a Gtk::Widget doesn't really get you
anything useful in terms of polymorphic behavior since the widgets of the
composite widget are already polymorphic objects derived from Gtk::Widget.
When you add your toplevel widget box to a parent widget all of children
widget of your composite widget, under box, are added to the children list
of the parent widget. Thus, there's really no need to have polymorphic
behavior for the composite widget container.

(3) If you need your composite widget derived from a Gtk:Widget its easy to
put a class wrapper around it that converts it back into a class derived
from Gtk::Widget. In fact this step is easily done with a oneline
instantiation of a a template class wrapper. The only reason I could think
of doing this is to insert a components back into glade (short of the Glade
Gui recognizing the C++11 functor operator as a standard way to returning
the toplevel widget of composite widget (possible for glade to support in
future? wishlist...))
(Afterthoughts: I was wondering if C++ has a way to implicitly convert from
one class type, example a composite widget type, to another class, example
Gtk:Widget&, simply by placing the class object in the context of needing a
different class type, example Gtk::Widgets?  I was doing this above using
functor operator.  So far I can only find examples of doing this with built
in variable types like int or char*.)
_______________________________________________
gtkmm-list mailing list
gtkmm-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtkmm-list

Reply via email to