Sl-Alex домашняя лаборатория

Руководство по WxWidgets: 4. Управление компоновкой

Просмотров: 3284Комментарии: 0
Статьи
Руководство по WxWidgets: 4. Управление компоновкой

Продолжаем публикацию перевода руководства по WxWidgets. На этот раз речь пойдёт о позиционировании элементов. Напоминаю, что в конце каждой главы размещены ссылки на остальные материалы руководства.

Стандартное приложение состоит из различных виджетов. Эти виджеты расположены внутри контейнера виджетов. Программист должен уметь управлять компоновкой этих элементов в окне программы. Это непростая задача. В wxWidgets существует два способа её осуществления.

  • absolute positioning (абсолютное позиционирование)
  • sizers (классификаторы)

Абсолютное позиционирование

Программист задаёт позицию и размер для каждого виджета в пикселях. Если вы используете абсолютное позиционирование, то должны помнить несколько вещей:

  • размер и позиция виджета не изменятся, если вы измените размеры окна
  • приложения будут выглядеть на разных платформах по-разному и достаточно паршиво
  • изменение шрифта в приложении может испортить компоновку элементов окна
  • если вы решите изменить компоновку, вам придётся переписать её по новой

Однако, встречаются ситуации, где допустимо использование абсолютного позиционирования. Например, мои учебные примеры. Я не хотел делать их слишком сложными, поэтому я часто использовал абсолютное позиционирование. Однако, в большинстве реальных программ программисты пользуются классификаторами.

В нашем примере мы реализуем простой набросок текстового редактора. Если мы изменим размеры окна, то размеры текстового поля вопреки нашим ожиданиям останутся неизменными.

Рисунок 4.1: До изменения размера окна

Рисунок 4.1: До изменения размера окна

Рисунок 4.2: После изменения размера окна

Рисунок 4.2: После изменения размера окна

absolute.h:
#include <wx/wx.h>
class Absolute : public wxFrame
{
public:
	Absolute(const wxString& title);
	wxMenuBar *menubar;
	wxMenu *file;
	wxMenu *edit;
	wxMenu *help;
	wxTextCtrl *textctrl;
};
absolute.cpp:
#include "absolute.h"
Absolute::Absolute(const wxString& title)
	: wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(250, 180))
{
	wxPanel *panel = new wxPanel(this, -1);
	menubar = new wxMenuBar;
	file = new wxMenu;
	edit = new wxMenu;
	help = new wxMenu;
	menubar->Append(file, wxT("&File"));
	menubar->Append(edit, wxT("&Edit"));
	menubar->Append(help, wxT("&Help"));
	SetMenuBar(menubar);
	textctrl = new wxTextCtrl(panel, -1, wxT(""), wxPoint(-1, -1),
		wxSize(250, 150));
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "absolute.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Absolute *absolute = new Absolute(wxT("Absolute"));
	absolute->Show(true);
	return true;
}

Это пример использования абсолютного позиционирования. Мы расположили виджет wxTextCtrl (текстовое поле) на виджете панели.

textctrl = new wxTextCtrl(panel, -1, wxT(""), wxPoint(-1, -1),
	wxSize(250, 150));

Мы используем абсолютное позиционирование в конструкторе виджета wxTextCtrl. В нашем случае мы задали основную позицию виджета по-умолчанию, ширину 250 пикселей и высоту 150 пикселей.

Использование классификаторов

Классификаторы в wxWidgets позволяют получить те же результаты, что и абсолютное позиционирование. Мы можем выбирать между следующими классификаторами:

  • wxBoxSizer (Прямоугольный классификатор)
  • wxStaticBoxSizer (Статический прямоугольный классификатор)
  • wxGridSizer (Табличный классификатор)
  • wxFlexGridSizer (Гибкий табличный классификатор)
  • wxGridBagSizer

Рисунок 4.3: До изменения размера окна

Рисунок 4.3: До изменения размера окна

Рисунок 4.4: После изменения размера окна

Рисунок 4.4: После изменения размера окна

sizer.h:
#include <wx/wx.h>
class Sizer : public wxFrame
{
public:
	Sizer(const wxString& title);
	wxMenuBar *menubar;
	wxMenu *file;
	wxMenu *edit;
	wxMenu *help;
	wxTextCtrl *textctrl;
};
sizer.cpp:
#include "sizer.h"
Sizer::Sizer(const wxString& title)
	: wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(250, 180))
{
	menubar = new wxMenuBar;
	file = new wxMenu;
	edit = new wxMenu;
	help = new wxMenu;
	menubar->Append(file, wxT("&File"));
	menubar->Append(edit, wxT("&Edit"));
	menubar->Append(help, wxT("&Help"));
	SetMenuBar(menubar);
	textctrl = new wxTextCtrl(this, -1, wxT(""), wxPoint(-1, -1),
		wxSize(250, 150));
    
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "sizer.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Sizer *sizer = new Sizer(wxT("Sizer"));
	sizer->Show(true);
	return true;
}

Теперь вы можете сказать, что не видели никаких классификаторов в примере. На самом деле в этом примере содержится небольшая хитрость. Фактически мы поместили виджет wxTextCtrl внутри виджета wxFrame . Этот виджет (wxFrame) имеет специальный встроенный классификатор. Мы можем добавить только один виджет в контейнер wxFrame. Потомок виджета занимает всё свободное пространство кроме рамки окна, меню, панели инструментов, и строки состояния.

wxBoxSizer

Этот классификатор позволяет нам поместить несколько виджетов в строку или колонку. Мы можем поместить другой классификатор в уже существующий. Таким образом мы можем создавать очень сложные интерфейсы (компоновки).

wxBoxSizer(int orient)
 wxSizerItem* Add(wxWindow* window, int proportion = 0, int flag = 0, int border = 0)

Ориентация может быть вертикальной (wxVERTICAL) или горизонтальной wxHORIZONTAL. Добавление виджетов в wxBoxSizer осуществляется методом Add(). Для лучшего понимания рассмотрим его параметры.

Параметр proportion определяет коэффициент того как виджеты будут изменяться в заданной ориентации. Предположим у нас есть три кнопки, значение параметра proportion 0, 1 и 2 соответственно. Они добавлены в горизонтальный классификатор wxBoxSizer. Кнопка с proportion = 0 не будет изменяться вообще. Кнопка с proportion = 2 будет изменяться в два раза сильнее кнопки с proportion = 1 в горизонтальном направлении.

С помощью параметра flag вы можете точнее настроить поведение виджетов внутри wxBoxSizer. Параметр border позволяет задать пространство между виджетами в пикселях. Для работы параметра border нужно с помощью параметра flag определить стороны, где нужно его использовать. Мы можем объединить их оператором |. Например wxLEFT | wxBOTTOM. Мы можем использовать следующие значения для параметра flag:

  • wxLEFT
  • wxRIGHT
  • wxBOTTOM
  • wxTOP
  • wxALL

Рисунок 4.5: Рамка вокруг панели

Рисунок 4.5: Рамка вокруг панели

border.h:
#include <wx/wx.h>
class Border : public wxFrame
{
public:
	Border(const wxString& title);
};
border.cpp:
#include "border.h"
Border::Border(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 200))
{
	wxColour col1, col2;
	col1.Set(wxT("#4f5049"));
	col2.Set(wxT("#ededed"));
	wxPanel *panel = new wxPanel(this, -1);
	panel->SetBackgroundColour(col1);
	wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
	wxPanel *midPan = new wxPanel(panel, wxID_ANY);
	midPan->SetBackgroundColour(col2);
	vbox->Add(midPan, 1, wxEXPAND | wxALL, 20);
	panel->SetSizer(vbox);
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "border.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Border *border = new Border(wxT("Border"));
	border->Show(true);
	return true;
}

В этом примере мы создали две панели. Вторая панель окружена пустым пространством.

vbox->Add(midPan, 1, wxEXPAND | wxALL, 20);

Мы поместили границу шириной 20 пикселей вокруг панели midPan. wxALL применяет размер гарницы для четырёх сторон. Если мы используем wxEXPAND флаг, виджет будет использовать всё пространство, выделенное для него.

В заключении мы определили выравнивание наших виджетов. Мы сделали это используя следующие флаги:

  • wxALIGN_LEFT
  • wxALIGN_RIGHT
  • wxALIGN_TOP
  • wxALIGN_BOTTOM
  • wxALIGN_CENTER_VERTICAL
  • wxALIGN_CENTER_HORIZONTAL
  • wxALIGN_CENTER

Допустим, мы захотим добавить две кнопки в правой нижней части окна.

align.h:
#include <wx/wx.h>
class Align : public wxFrame
{
public:
	Align(const wxString& title);
};
align.cpp:
#include "align.h"
Align::Align(const wxString& title)
	: wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(300, 200))
{
	wxPanel *panel = new wxPanel(this, -1);
	wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL);
	wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL);
	wxButton *ok = new wxButton(panel, -1, wxT("Ok"));
	wxButton *cancel = new wxButton(panel, -1, wxT("Cancel"));
	hbox1->Add(new wxPanel(panel, -1));
	vbox->Add(hbox1, 1, wxEXPAND);
	hbox2->Add(ok);
	hbox2->Add(cancel);
	vbox->Add(hbox2, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);
	panel->SetSizer(vbox);
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "align.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
		Align *align = new Align(wxT("Align"));
		align->Show(true);
		return true;
}

Мы создали три классификатора. Один вертикальный и два горизонтальных. Мы поместили два горизонтальный классификатора в вертикальный.

hbox1->Add(new wxPanel(panel, -1));
vbox->Add(hbox1, 1, wxEXPAND);

Мы поместили wxPanel в первый горизонтальный классификатор. Установили параметр proportion равным 1 и флаг wxEXPAND. В этом случае классификатор заполнит всё пространство кроме hbox2.

vbox->Add(hbox2, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);

Мы поместили кнопки в классификатор hbox2, т.к. он находится по правую сторону окна, поэтому мы так же добавляем немного места сверху и справа от кнопок.

Рисунок 4.6: Выравниваем кнопки

Рисунок 4.6: Выравниваем кнопки

Go To Class

Следующий пример иллюстрирует несколько важных идей.

gotoclass.h:
#include <wx/wx.h>
class GotoClass : public wxFrame
{
public:
	GotoClass(const wxString& title);
};
gotoclass.cpp:
#include "gotoclass.h"
GotoClass::GotoClass(const wxString& title)
	: wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(450, 400))
{
	wxPanel *panel = new wxPanel(this, -1);
	wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL);
	wxStaticText *st1 =  new wxStaticText(panel, wxID_ANY, 
		wxT("Class Name"));
	hbox1->Add(st1, 0, wxRIGHT, 8);
	wxTextCtrl *tc = new wxTextCtrl(panel, wxID_ANY);
	hbox1->Add(tc, 1);
	vbox->Add(hbox1, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10);
	vbox->Add(-1, 10);
	wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL);
	wxStaticText *st2 = new wxStaticText(panel, wxID_ANY, 
		wxT("Matching Classes"));
	hbox2->Add(st2, 0);
	vbox->Add(hbox2, 0, wxLEFT | wxTOP, 10);
	vbox->Add(-1, 10);
	wxBoxSizer *hbox3 = new wxBoxSizer(wxHORIZONTAL);
	wxTextCtrl *tc2 = new wxTextCtrl(panel, wxID_ANY, wxT(""), 
		wxPoint(-1, -1), wxSize(-1, -1), wxTE_MULTILINE);
	hbox3->Add(tc2, 1, wxEXPAND);
	vbox->Add(hbox3, 1, wxLEFT | wxRIGHT | wxEXPAND, 10);
	vbox->Add(-1, 25);
	wxBoxSizer *hbox4 = new wxBoxSizer(wxHORIZONTAL);
	wxCheckBox *cb1 = new wxCheckBox(panel, wxID_ANY, 
		wxT("Case Sensitive"));
	hbox4->Add(cb1);
	wxCheckBox *cb2 = new wxCheckBox(panel, wxID_ANY, 
		wxT("Nested Classes"));
	hbox4->Add(cb2, 0, wxLEFT, 10);
	wxCheckBox *cb3 = new wxCheckBox(panel, wxID_ANY, 
		wxT("Non-Project Classes"));
	hbox4->Add(cb3, 0, wxLEFT, 10);
	vbox->Add(hbox4, 0, wxLEFT, 10);
	vbox->Add(-1, 25);
	wxBoxSizer *hbox5 = new wxBoxSizer(wxHORIZONTAL);
	wxButton *btn1 = new wxButton(panel, wxID_ANY, wxT("Ok"));
	hbox5->Add(btn1, 0);
	wxButton *btn2 = new wxButton(panel, wxID_ANY, wxT("Close"));
	hbox5->Add(btn2, 0, wxLEFT | wxBOTTOM , 5);
	vbox->Add(hbox5, 0, wxALIGN_RIGHT | wxRIGHT, 10);
	panel->SetSizer(vbox);
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "gotoclass.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	GotoClass *gotoclass = new GotoClass(wxT("GotoClass"));
	gotoclass->Show(true);
	return true;
}

Это сложный пример использования классификатора wxBoxSizer. Расположение строго сверху. Мы создали один вертикальный классификатор и поместили в него пять горизонтальных.

vbox->Add(hbox3, 1, wxLEFT | wxRIGHT | wxEXPAND, 10);
vbox->Add(-1, 25);

Мы знаем, что можем контролировать расстояние межу виджетами, комбинируя значения параметров flag и border. Но тут существует одно серьёзное ограничение. В методе Add() мы можем указать только одну границу (border) для всех заданных сторон. В нашем примере мы задали 10 пикселей справа и слева, но мы не можем тут же задать 25 пикселей снизу. Все что мы можем сделать так это добавить сверху так же 10 пикселей или вообще их не добавлять (если опустим флаг wxBOTTOM). Поэтому если нам нужна другая величина, то мы можем добавить немного дополнительного пространства. Ведь с помощью метода Add() мы можем добавлять как виджеты, так и пространство.

vbox->Add(hbox5, 0, wxALIGN_RIGHT | wxRIGHT, 10);

Мы поместили две кнопки с правой стороны окна. Как мы это сделали? Три вещи необходимы, чтобы этого добиться. Параметр proportion, флаг wxALIGN_RIGHT и флаг wxEXPAND. Proportion должен быть равен 0. Кнопки не должны изменять своего размера, когда мы растягиваем окно. Мы не должны указывать флаг wxEXPAND. Кнопки должны занимать только то место, которое для них выделено. И в завершении нужно указать флаг wxALIGN_RIGHT. Горизонтальный классификатор растягивается на всю ширину окна. Поэтому если мы укажем флаг wxALIGN_RIGHT, то кнопки будут помещены справа, как раз так как мы и хотели.

Рисунок 4.7: GotoClass

Рисунок 4.7: GotoClass

wxGridSizer

Этот классификатор располагает виджеты в двумерной таблице. Ячейки внутри таблицы имеют одинаковый размер.

wxGridSizer(int rows, int cols, int vgap, int hgap)

В конструкторе мы указываем количество строк и столбцов таблицы. А так же пространство между ячейками по вертикали и горизонтали.

В нашем примере мы создадим скелет калькулятора. Это прекрасный образец использования wxGridSizer.

gridsizer.h:
#include <wx/wx.h>
class GridSizer : public wxFrame
{
public:
	GridSizer(const wxString& title);
	wxMenuBar *menubar;
	wxMenu *file;
	wxBoxSizer *sizer;
	wxGridSizer *gs;
	wxTextCtrl *display;
};
gridsizer.cpp:
#include "gridsizer.h"
GridSizer::GridSizer(const wxString& title)
	: wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(270, 220))
{
	menubar = new wxMenuBar;
	file = new wxMenu;
	SetMenuBar(menubar);
	sizer = new wxBoxSizer(wxVERTICAL);
 
	display = new wxTextCtrl(this, -1, wxT(""), wxPoint(-1, -1),
		wxSize(-1, -1), wxTE_RIGHT);
	sizer->Add(display, 0, wxEXPAND | wxTOP | wxBOTTOM, 4);
	gs = new wxGridSizer(4, 4, 3, 3);
	gs->Add(new wxButton(this, -1, wxT("Cls")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("Bck")), 0, wxEXPAND);
	gs->Add(new wxStaticText(this, -1, wxT("")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("Close")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("7")), 0, wxEXPAND); 
	gs->Add(new wxButton(this, -1, wxT("8")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("9")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("/")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("4")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("5")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("6")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("*")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("1")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("2")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("3")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("-")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("0")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT(".")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("=")), 0, wxEXPAND);
	gs->Add(new wxButton(this, -1, wxT("+")), 0, wxEXPAND);
	sizer->Add(gs, 1, wxEXPAND);
	SetSizer(sizer);
	SetMinSize(wxSize(270, 220));
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "gridsizer.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	GridSizer *gs = new GridSizer(wxT("GridSizer"));
	gs->Show(true);
	return true;
}

В этом примере мы использовали вертикальный классификатор для wxFrame. Так же мы поместили статический текст и табличный классификатор в вертикальный классификатор.

Кстати, обратите внимание на то, как мы добавили пространство между клавишами Bck и Close. Мы просто вставили между ними пустой wxStaticText. Такие трюки очень распространены.

gs->Add(new wxButton(this, -1, wxT("Cls")), 0, wxEXPAND);

Метод Add() вызывается много раз. Виджеты располагаются внутри таблицы в порядке добавления. Первый ряд заполняется первым, второй - вторым и т.д.

Рисунок 4.8: После изменения размера окна

Рисунок 4.8: После изменения размера окна

wxFlexGridSizer

Этот классификатор похож на wxGridSizer, он так же размещает виджеты внутри двумерной таблицы. Но он делает это размещение более гибким. В wxGridSizer все ячейки одного размера. В wxFlexGridSizer ячейки имеют одинаковую высоту внутри строки и одинаковую ширину внутри столбца. Но в разных строках и столбцах высота и ширина могут различаться.

wxFlexGridSizer(int rows, int cols, int vgap, int hgap)

Параметры rows и cols задают количество строк и столбцов в классификаторе. vgap и hgap определяют пространство между виджетами в обоих направлениях.

Много времени разработчики тратят на разработку диалогов для ввода и изменения данных. Я нахожу wxFlexGridSizer очень удобным для реализации подобных вещей. Программист может без труда создать диалоговое окно с помощью этого классификатора. Правда, можно сделать то же самое и с помощью wxGridSizer, но выглядеть это будет не так хорошо, из-за того, что все ячейки имеют одинаковый размер.

flexgridsizer.h:
#include <wx/wx.h>
class FlexGridSizer : public wxFrame
{
public:
	FlexGridSizer(const wxString& title);
};
flexgridsizer.cpp:
#include "flexgridsizer.h"
FlexGridSizer::FlexGridSizer(const wxString& title)
	: wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(270, 220))
{ 
	wxPanel *panel = new wxPanel(this, -1);
	wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);
	wxFlexGridSizer *fgs = new wxFlexGridSizer(3, 2, 9, 25);
	wxStaticText *thetitle = new wxStaticText(panel, -1, wxT("Title"));
	wxStaticText *author = new wxStaticText(panel, -1, wxT("Author"));
	wxStaticText *review = new wxStaticText(panel, -1, wxT("Review"));
	wxTextCtrl *tc1 = new wxTextCtrl(panel, -1);
	wxTextCtrl *tc2 = new wxTextCtrl(panel, -1);
	wxTextCtrl *tc3 = new wxTextCtrl(panel, -1, wxT(""),
		wxPoint(-1, -1), wxSize(-1, -1), wxTE_MULTILINE);
	fgs->Add(thetitle);
	fgs->Add(tc1, 1, wxEXPAND);
	fgs->Add(author);
	fgs->Add(tc2, 1, wxEXPAND);
	fgs->Add(review, 1, wxEXPAND);
	fgs->Add(tc3, 1, wxEXPAND);
	fgs->AddGrowableRow(2, 1);
	fgs->AddGrowableCol(1, 1);
	hbox->Add(fgs, 1, wxALL | wxEXPAND, 15);
	panel->SetSizer(hbox);
	Centre();
}
main.h:
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp:
#include "main.h"
#include "flexgridsizer.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	FlexGridSizer *fgs = new FlexGridSizer(wxT("FlexGridSizer"));
	fgs->Show(true);
	return true;
}

В нашем примере мы создали простой диалог. Он может быть использован для ввода данных в базу данных.

wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);
...
hbox->Add(fgs, 1, wxALL | wxEXPAND, 15);

Мы создали горизонтальный классификатор с целью добавить немного пространства (15 пикс) вокруг таблицы виджетов.

fgs->Add(thetitle);

Мы добавили виджеты в классификатор точно так же как и в GridSizer.

fgs->AddGrowableRow(2, 1);
fgs->AddGrowableCol(1, 1);

Мы создали третью строку и второй столбец масштабируемыми. Точно так мы создали масшабируемые текстовые элементы управления, которые изменяются в размерах при изменении размеров окна. Первые два текстовых элемента управления увеличиваются в горизонтальном направлении, а третий в обоих. Так же помните, что нужно сделать виджеты растяжимыми (wxEXPAND) для того, чтобы всё заработало.

Рисунок 4.9: FlexGridSizer

Рисунок 4.9: FlexGridSizer

Остальные материалы курса:

Вступление

1. Вспомогательные классы

2. Первые программы

3. Меню и панели инструментов

4. Управление компоновкой

5. События

6. Диалоги

7. Виджеты часть 1

8. Виджеты часть 2

9. Перетаскивание

10. Контексты устройств

11. Самодельные виджеты

12. Тетрис в wxWidgets

Примечание

Оригинал руководства расположен здесь. Автор оригинала - Jan Bodnar.

Перевод (без разметки и картинок) был выполнен пользователем ber113 с сайта translated.by. К сожалению, сайт сейчас не работает.

Данный документ представляет собой компиляцию указанных документов с сохранением оригинальной разметки и иллюстраций.