Я хочу получить свой собственный класс виджетов и добавить стандартные виджеты в этот класс для создания составного виджета. У кого-нибудь есть примеры или предложения, как это сделать? Например, предположим, я хочу создать собственный составной виджет из 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 как чистый контейнерный класс, т.е. не производные от каких-либо классов, и для перегрузки оператора Functor 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 :: Widget для создания составного виджета заключается в следующем:
(1) API виджетов для gtkmm очень многочисленны и, как правило, скрывают любые новые публичные методы, которые вы добавляете в составной виджет, в беспорядке методов виджетов gtkmm, которые вы, вероятно, не будете использовать в любом случае. По этой причине. Лучше добавить все ваши объекты виджета-контейнера в публичную секцию класса, включая виджет верхнего уровня. Вы по-прежнему будете иметь доступ ко всем методам каждого виджета объекта без беспорядка API gtkmm.
(2) Наследование вашего класса от Gtk :: Widget на самом деле не дает вам ничего полезного с точки зрения полиморфного поведения, так как виджеты составного виджета уже являются полиморфными объектами, производными от Gtk :: Widget. Когда вы добавляете свой виджет верхнего уровня в родительский виджет, все дочерние виджеты вашего составного виджета под полем добавляются в список детей родительского виджета. Таким образом, действительно нет необходимости иметь полиморфное поведение для контейнера составного виджета.
(3) Если вам нужен ваш составной виджет, производный от Gtk: Widget, его легко обернуть классом-оберткой, который преобразует его обратно в класс, производный от Gtk :: Widget. На самом деле этот шаг легко сделать с помощью единственного экземпляра обертки класса шаблона. Единственная причина, по которой я мог думать об этом, — это вставить компоненты обратно на поляну (если не считать Glade Gui, распознающего оператор функтора C ++ 11 в качестве стандартного способа возврата верхнего уровня составного виджета (возможно для поддержки glade в будущее? список желаний …))
Других решений пока нет …