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

Руководство по WxWidgets: 7. Виджеты часть 1

Просмотров: 3301Комментарии: 0
Статьи
Руководство по WxWidgets: 7. Виджеты часть 1

В этой главе мы рассмотрим небольшие примеры некоторых виджетов, доступных в wxWidgets. Виджеты являются строительными блоками наших приложений. wxWidgets содержит большое количество полезных виджетов. Виджет - это базовый GUI объект по определению. Виджеты дали название проекту wxWidgets. Термин виджет используется в UNIX системах. В Windows виджет называют элементом управления.

wxCheckBox (Чек Бокс)

У этого виджета есть два состояния: Вкл. и Выкл. Это бокс с меткой. Метка может находиться с правой или с левой стороны бокса. Если чек бокс взведён, то это отображается наличием галочки в боксе. Чек бокс может быть использован для реализации появления/скрытия заставки при запуске, переключения видимости панели инструментов, и т. д.

checkbox.h
#include <wx/wx.h>
class CheckBox : public wxFrame
{
public:
	CheckBox(const wxString& title);
	void OnToggle(wxCommandEvent& event);
	wxCheckBox *m_cb;
};
const int ID_CHECKBOX = 100;
checkbox.cpp
#include "checkbox.h"
CheckBox::CheckBox(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 150))
{
	wxPanel *panel = new wxPanel(this, wxID_ANY);
	m_cb = new wxCheckBox(panel, ID_CHECKBOX, wxT("Show title"), 
		wxPoint(20, 20));
	m_cb->SetValue(true);
	Connect(ID_CHECKBOX, wxEVT_COMMAND_CHECKBOX_CLICKED, 
		wxCommandEventHandler(CheckBox::OnToggle));
	Centre();
}
void CheckBox::OnToggle(wxCommandEvent& WXUNUSED(event))
{
	if (m_cb->GetValue()) {
		this->SetTitle(wxT("CheckBox"));
	} else {
		this->SetTitle(wxT(" "));
	}
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "checkbox.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	CheckBox *cb = new CheckBox(wxT("CheckBox"));
	cb->Show(true);
	return true;
}

В нашем примере мы реализуем один чек бокс в окне. Мы переключим заголовок окна нажатием на чек бокс.

m_cb = new wxCheckBox(panel, ID_CHECKBOX, wxT("Show title"), 
	wxPoint(20, 20));
m_cb->SetValue(true);

Мы создали чек бокс. По-умолчанию, заголовок отображается. Поэтому мы взводим чек бокс, вызывая метод SetValue().

Connect(ID_CHECKBOX, wxEVT_COMMAND_CHECKBOX_CLICKED, 
	wxCommandEventHandler(CheckBox::OnToggle));

Если мы кликнем на чек боксе, сгенерируется событие wxEVT_COMMAND_CHECKBOX_CLICKED. Мы соединим это событие с определённым пользователем методом OnToggle().

if (m_cb->GetValue()) {
	this->SetTitle(wxT("CheckBox"));
} else {
	this->SetTitle(wxT(" "));
}

Внутри метода OnToggle(), мы проверяем состояние чек бокса. Если он взведён, то мы отображаем строку "Check Box" в заголовке, если нет - не отображаем.

Рисунок 7.1: wxCheckBox

Рисунок 7.1: wxCheckBox

wxBitmapButton (Растровая кнопка)

Растровая кнопка - это кнопка отображающая растровую картинку. Может иметь три различных состояния: selected (при выборе), focused (при наведении) и displayed (отображаемое). Мы можем задать свою картинку для каждого из состояний.

bitmapbutton.h
#include <wx/wx.h>
#include <wx/slider.h>
class BitmapButton : public wxFrame
{
public:
	BitmapButton(const wxString& title);
	wxSlider *slider;
	wxBitmapButton *button;
	int pos;
	void OnScroll(wxScrollEvent& event);
};
const int ID_SLIDER = 100;
bitmapbutton.cpp
#include "bitmapbutton.h"
BitmapButton::BitmapButton(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
	wxImage::AddHandler( new wxPNGHandler );
	wxPanel *panel = new wxPanel(this);
	slider = new wxSlider(panel, ID_SLIDER, 0, 0, 100, 
		wxPoint(10, 30), wxSize(140, -1));
	button = new wxBitmapButton(panel, wxID_ANY, wxBitmap(wxT("mute.png"), 
		wxBITMAP_TYPE_PNG), wxPoint(180, 20));
	Connect(ID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED, 
		wxScrollEventHandler(BitmapButton::OnScroll));  
	Center();
}
void BitmapButton::OnScroll(wxScrollEvent& event)
{
	pos = slider->GetValue(); 
	if (pos == 0) {
		button->SetBitmapLabel(wxBitmap(wxT("mute.png"), wxBITMAP_TYPE_PNG));
	} else if (pos > 0 && pos <= 30 ) {
		button->SetBitmapLabel(wxBitmap(wxT("min.png"), wxBITMAP_TYPE_PNG));
	} else if (pos > 30 && pos < 80 ) {
		button->SetBitmapLabel(wxBitmap(wxT("med.png"), wxBITMAP_TYPE_PNG));
	} else {
		button->SetBitmapLabel(wxBitmap(wxT("max.png"), wxBITMAP_TYPE_PNG));
	}
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "bitmapbutton.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	BitmapButton *bb = new BitmapButton(wxT("BitmapButton"));
	bb->Show(true);
	return true;
}

В нашем примере мы создали слайдер и растровую кнопку. Мы сэмитировали регулятор громкости. Перетаскивая ручку слайдера, мы можем менять картинку, отображаемую на кнопке.

wxImage::AddHandler( new wxPNGHandler );

Т.к. мы собираемся использовать PNG картинку, то нужно сначала инициализировать обработчик PNG изображений.

button = new wxBitmapButton(panel, wxID_ANY, wxBitmap(wxT("mute.png"), 
	wxBITMAP_TYPE_PNG), wxPoint(180, 20));

Мы создали растровую кнопку. Мы указали растровый тип, в нашем случае wxBITMAP_TYPE_PNG.

pos = slider->GetValue();

Мы получили значение слайдера. В зависимости от этой величины определяем одно из четырёх состояний громкости: минимальная, низкая, средняя, максимальная. Для каждого состояния мы указали растровую картинку для нашей кнопки. Для изменения картинки на кнопке мы использовали метод SetBitmapLabel().

Рисунок 7.2: wxBitmapButton

Рисунок 7.2: wxBitmapButton

wxToggleButton (Переключатель)

Переключатель - это кнопка, имеющая два состояния: нажата или не нажата. Переключение между этими состояниями происходит путём нажатия на кнопку. Существует множество ситуаций, где такая функциональность очень кстати. Вот например:

togglebutton.h
#include <wx/wx.h>
#include <wx/tglbtn.h>
class ToggleButton : public wxFrame
{
public:
	ToggleButton(const wxString& title);
	void OnToggleRed(wxCommandEvent& event);
	void OnToggleGreen(wxCommandEvent& event);
	void OnToggleBlue(wxCommandEvent& event);
protected:
	wxToggleButton *m_tgbutton1;
	wxToggleButton *m_tgbutton2;
	wxToggleButton *m_tgbutton3;
 
	wxPanel *m_panel;
	wxColour *colour;
};
const int ID_TGBUTTON1 = 101;
const int ID_TGBUTTON2 = 102;
const int ID_TGBUTTON3 = 103;
togglebutton.cpp
#include "togglebutton.h"
ToggleButton::ToggleButton(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(280, 180))
{
	wxPanel *panel = new wxPanel(this, wxID_ANY);
	colour = new wxColour(0, 0, 0);
	m_tgbutton1 = new wxToggleButton(panel, ID_TGBUTTON1, 
		wxT("Red"), wxPoint(20, 20));
	m_tgbutton2 = new wxToggleButton(panel, ID_TGBUTTON2, 
		wxT("Green"), wxPoint(20, 70));
	m_tgbutton3 = new wxToggleButton(panel, ID_TGBUTTON3, 
		wxT("Blue"), wxPoint(20, 120));
	Connect(ID_TGBUTTON1, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, 
		wxCommandEventHandler(ToggleButton::OnToggleRed));
	Connect(ID_TGBUTTON2, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, 
		wxCommandEventHandler(ToggleButton::OnToggleGreen));
	Connect(ID_TGBUTTON3, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED,  
		wxCommandEventHandler(ToggleButton::OnToggleBlue));
	m_panel = new wxPanel(panel, wxID_NEW, wxPoint(150, 20), 
		wxSize(110, 110), wxSUNKEN_BORDER);
	m_panel->SetBackgroundColour(colour->GetAsString());
}
void ToggleButton::OnToggleRed(wxCommandEvent& WXUNUSED(event))
{
	unsigned char green = colour->Green(); 
	unsigned char blue = colour->Blue(); 
	if ( colour->Red() ) {
		colour->Set(0, green, blue);
	} else { 
		colour->Set(255, green, blue);
	}
	m_panel->SetBackgroundColour(colour->GetAsString());
}
void ToggleButton::OnToggleGreen(wxCommandEvent& WXUNUSED(event))
{
	unsigned char red = colour->Red(); 
	unsigned char blue = colour->Blue(); 
	if ( colour->Green() ) {
		colour->Set(red, 0, blue);
	} else { 
		colour->Set(red, 255, blue);
	}
	m_panel->SetBackgroundColour(colour->GetAsString());
}
void ToggleButton::OnToggleBlue(wxCommandEvent& WXUNUSED(event))
{
	unsigned char red = colour->Red(); 
	unsigned char green = colour->Green(); 
	if ( colour->Blue() ) {
		colour->Set(red, green, 0);
	} else { 
		colour->Set(red, green, 255);
	}
	m_panel->SetBackgroundColour(colour->GetAsString());
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "togglebutton.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	ToggleButton *button = new ToggleButton(wxT("ToggleButton"));
	button->Centre();
	button->Show(true);
	return true;
}

В нашем примере мы создали три переключателя и панель. Мы установили цвет фона панели черным. Переключатели же переключают красную, зелёную и синюю части цветового кода. Цвет фона зависит от того, какие переключатели нажаты.

colour = new wxColour(0, 0, 0);

Это начальный цветовой код. Нет ни красного, ни синего, ни зелёного - в итоге имеем чёрный. По правде говоря, чёрный вообще не является цветом.

m_tgbutton1 = new wxToggleButton(panel, ID_TGBUTTON1, 
	wxT("Red"), wxPoint(20, 20));

Здесь мы создали переключатель.

Connect(ID_TGBUTTON1, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, 
	wxCommandEventHandler(ToggleButton::OnToggleRed));

Если мы нажмём на переключатель, то сгенерируем событие wxEVT_COMMAND_TOGGLEBUTTON_CLICKED. Мы соединим его с обработчиком событий. Помните, нельзя соединять события с методами кнопки. Используйте для этого wxFrame.widget, являющийся прародителем переключателя. Это вполне допустимо, так как командные события репродуцируются к своим предкам. В нашем случае это выглядит так кнопка -> панель -> рамка. Если мы хотим соединить событие с кнопкой, мы должны создать свой производный класс кнопок, а это достаточно трудоёмкий процесс.

if ( colour->Blue() ) {
	colour->Set(red, green, 0);
} else { 
	colour->Set(red, green, 255);
}

В обработчике событий мы установили соответствующие параметры wxColour.

m_panel->SetBackgroundColour(colour->GetAsString());

Установили фон панели.

Рисунок 7.3: wxToggleButton

Рисунок 7.3: wxToggleButton

wxStaticLine (Статическая линия)

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

staticline.h
#include <wx/wx.h>
class Staticline : public wxDialog
{
public:
	Staticline(const wxString& title);
};
staticline.cpp
#include "staticline.h"
#include <wx/stattext.h>
#include <wx/statline.h>
Staticline::Staticline(const wxString& title) : wxDialog(NULL, wxID_ANY, title, 
	wxDefaultPosition, wxSize(360, 350))
{
	wxFont font(10, wxDEFAULT, wxNORMAL, wxBOLD);
	wxStaticText *heading = new wxStaticText(this, wxID_ANY, wxT("The Central Europe"), 
		wxPoint(30, 15));
	heading->SetFont(font);
	wxStaticLine *sl1 = new wxStaticLine(this, wxID_ANY, wxPoint(25, 50), 
		wxSize(300,1));
	wxStaticText *st1 = new wxStaticText(this, wxID_ANY, wxT("Slovakia"), 
		wxPoint(25, 80));
	wxStaticText *st2 = new wxStaticText(this, wxID_ANY, wxT("Hungary"), 
		wxPoint(25, 100));
	wxStaticText *st3 = new wxStaticText(this, wxID_ANY, wxT("Poland"), 
		wxPoint(25, 120));
	wxStaticText *st4 = new wxStaticText(this, wxID_ANY, wxT("Czech Republic"), 
		wxPoint(25, 140));
	wxStaticText *st5 = new wxStaticText(this, wxID_ANY, wxT("Germany"), 
		wxPoint(25, 160));
	wxStaticText *st6 = new wxStaticText(this, wxID_ANY, wxT("Slovenia"), 
		wxPoint(25, 180));
	wxStaticText *st7 = new wxStaticText(this, wxID_ANY, wxT("Austria"), 
		wxPoint(25, 200));
	wxStaticText *st8 = new wxStaticText(this, wxID_ANY, wxT("Switzerland"), 
		wxPoint(25, 220));
	wxStaticText *st9  = new wxStaticText(this, wxID_ANY, wxT("5 379 000"), 
		wxPoint(220, 80), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st10 = new wxStaticText(this, wxID_ANY, wxT("10 084 000"), 
		wxPoint(220, 100), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st11 = new wxStaticText(this, wxID_ANY, wxT("38 635 000"), 
		wxPoint(220, 120), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st12 = new wxStaticText(this, wxID_ANY, wxT("10 240 000"), 
		wxPoint(220, 140), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st13 = new wxStaticText(this, wxID_ANY, wxT("82 443 000"), 
		wxPoint(220, 160), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st14 = new wxStaticText(this, wxID_ANY, wxT("2 001 000"),  
		wxPoint(220, 180), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st15 = new wxStaticText(this, wxID_ANY, wxT("8 032 000"),  
		wxPoint(220, 200), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticText *st16 = new wxStaticText(this, wxID_ANY, wxT("7 288 000"),  
		wxPoint(220, 220), wxSize(90, -1), wxALIGN_RIGHT);
	wxStaticLine *sl2 = new wxStaticLine(this, wxID_ANY, wxPoint(25, 260), 
		wxSize(300, 1));
	wxStaticText *sum = new wxStaticText(this, wxID_ANY, wxT("164 102 000"), 
		wxPoint(220, 280));
	wxFont sum_font = sum->GetFont();
	sum_font.SetWeight(wxBOLD);
	sum->SetFont(sum_font);
	this->Centre();
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "staticline.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Staticline *sl = new Staticline(wxT("The Central Europe"));
	sl->ShowModal();
	sl->Destroy();
	return true;
}

В этом примере, мы отобразили страны центральной Европы и их население. Использование wxStaticLine сделало текст более визуально привлекательным.

wxStaticLine *sl1 = new wxStaticLine(this, wxID_ANY, wxPoint(25, 50), 
	wxSize(300,1));

Здесь мы создали горизонтальную статическую линию шириной 300 пикселей, высотой 1 пиксель.

Рисунок 7.4: wxStaticLine

Рисунок 7.4: wxStaticLine

wxStaticText (Статический текст)

Статический текст отображает одну или больше строк доступного только для чтения текста.

statictext.h
#include <wx/wx.h>
class StaticText : public wxFrame
{
public:
	StaticText(const wxString& title);
};
statictext.cpp
#include "statictext.h"
StaticText::StaticText(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title)
{
	wxPanel *panel = new wxPanel(this, wxID_ANY);
	wxString  text = wxT("'Cause sometimes you feel tired,\n\
feel weak, and when you feel weak,\
you feel like you wanna just give up.\n\
But you gotta search within you,\
you gotta find that inner strength\n\
and just pull that shit out of you\
and get that motivation to not give up\n\
and not be a quitter,\
no matter how bad you wanna just fall flat on your face and collapse.");
	wxStaticText *st = new wxStaticText(panel, wxID_ANY, text, 
		wxPoint(10, 10), wxDefaultSize, wxALIGN_CENTRE);
	this->SetSize(600, 110);
	this->Centre();
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "statictext.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	StaticText *st = new StaticText(wxT("StaticText"));
	st->Show(true);
	return true;
}

В нашем примере мы вывели в окне часть текста песни Эминема "Till I Collapse".

wxStaticText *st = new wxStaticText(panel, wxID_ANY, text, 
	wxPoint(10, 10), wxDefaultSize, wxALIGN_CENTRE);

Здесь мы создали wxStaticText виджет. Статический текст выровнен по середине.

Рисунок 7.5: wxStaticText

Рисунок 7.5: wxStaticText

wxSlider (Слайдер)

Слайдер - это виджет, который снабжён простым ползунком. Его можно перемещать вперёд и назад. Таким образом мы можем выбирать значение для конкретной задачи. Иногда использование слайдера более привычно, чем введение числа или использование спин регулятора.

Slider.h
#include <wx/wx.h>
#include <wx/slider.h>
class MyPanel : public wxPanel
{
public:
	MyPanel(wxFrame *parent);
	void OnPaint(wxPaintEvent& event);
	void OnScroll(wxScrollEvent& event);
	wxSlider *slider;
	int fill;
};
class Slider : public wxFrame
{
public:
	Slider(const wxString& title);
	MyPanel *panel;
};
const int ID_SLIDER = 100;
Slider.cpp
#include "Slider.h"
Slider::Slider(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, 
    wxSize(270, 200))
{
	panel = new MyPanel(this);
	Center();
}
MyPanel::MyPanel(wxFrame * parent)
	: wxPanel(parent, wxID_ANY)
{
	fill = 0;
	slider = new wxSlider(this, ID_SLIDER, 0, 0, 140, wxPoint(50, 30), 
		wxSize(-1, 140), wxSL_VERTICAL);
	Connect(ID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED, 
		wxScrollEventHandler(MyPanel::OnScroll));  
	Connect(wxEVT_PAINT, wxPaintEventHandler(MyPanel::OnPaint));
}
void MyPanel::OnScroll(wxScrollEvent& event)
{
	fill = slider->GetValue();
	Refresh();
}
void MyPanel::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);
	wxPen pen(wxColour(212, 212, 212));
	dc.SetPen(pen);
	dc.DrawRectangle(wxRect(140, 30, 80, 140));  
	wxBrush brush1(wxColour(197, 108, 0));
	dc.SetBrush(brush1);
	dc.DrawRectangle(wxRect(140, 30, 80, fill));
}
main.h
#include <wx/wx.h>
class MyApp : public wxApp
{
	public:
		virtual bool OnInit();
};
main.cpp
#include "main.h"
#include "Slider.h"
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
	Slider *slider = new Slider(wxT("Slider"));
	slider->Show(true);
	return true;
}

В нашем примере мы создали слайдер. Перемещая ползунок слайдера мы изменяем цвет фона панели. В данном примере использование слайдера более привычно, чем, скажем, спин регулятора.

slider = new wxSlider(this, ID_SLIDER, 0, 0, 140, wxPoint(50, 30), 
	wxSize(-1, 140), wxSL_VERTICAL);

Мы создали вертикальный слайдер. Начальное значение равно 0, минимальное значение тоже, максимальное равно 140. Мы не выводим никаких галочек или меток.

Connect(ID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED, 
	wxScrollEventHandler(MyPanel::OnScroll));

Здесь мы соединили событие wxEVT_COMMAND_SLIDER_UPDATED с определённым пользователем методом OnScroll().

Connect(wxEVT_PAINT, wxPaintEventHandler(MyPanel::OnPaint));

Так как мы собираемся немного порисовать, то соединяем метод OnPaint() с событием wxEVT_PAINT.

fill = slider->GetValue();
Refresh();

В методе OnScroll() мы получаем текущее значение слайдера. Мы вызываем метод Refresh(), который генерирует событие wxEVT_PAINT.

dc.DrawRectangle(wxRect(140, 30, 80, 140)); 
...
dc.DrawRectangle(wxRect(140, 30, 80, fill));

Внутри обработчика событий OnPaint(), мы рисуем два прямоугольника. Первый метод рисует белый прямоугольник с серой окантовкой. Второй - коричневый прямоугольник, высота которого регулируется значением fill, которое в свою очередь задаётся слайдером.

Рисунок 7.6: wxSlider

Рисунок 7.6: wxSlider

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

Вступление

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

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

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

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

5. События

6. Диалоги

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

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

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

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

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

12. Тетрис в wxWidgets

Примечание

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

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

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