Шаг 68 - Компонент TStatusBar

С этим компонентом мы уже встречались, и не раз. Обычная статусная панель... Правда, мы не рассмотрели возможности эой панели отоображать строки текста в разных разделах, как бы субпанельках. Для этого используется режим OwnerDraw, который предполагает реализацию механизма рисования содержимого программистом.

Небольшое отступление. Вообще для выведения произвольных графических элементов управления, не являющихся инкапсуляциями встроенных элементов Windows, используются механизмы обработки сообщений типа WM_PAINT. То есть когда объект нужно вывести - например, когда скрывавшее его окно более высокого уровня z-order убирается, возникает это событие. Это позволяет довольно эффективно использовать ресурсы. То есть зачем перерисовывать элемент, если он не виден. Надо сказать, что Windows вносит некоторую путаницу в это дело, поскольку есть еще встроенные элементы управления, которые можно при помощи того же события модифицировать, или изменить вовсе. Правда, подобные стандарты дают нам одинаковый (даже однообразный интерфейс). В других графических системах (например, XWindows для Linux) нет подобной стандартизации. Сервер предоставляет стандартные возможности рисования и создания простых окон, а также шрифты и например, элемент полосы прокрутки. Все другие элементы, разные списки, кнопочки, реализуются обычно в динамических, или, если места не жалко :), в статических библиотеках. Правда, тем не менее существуют наиболее распространенные библиотеки, такие как Qt и GTK+, которые используются большим количеством программ, так что стандартизация все же имеет место...

Немного ближе к делу. Этот самый механизм рисования реализуют в производных компонентных классах, обычно перегружая унаследованный метод типа Paint. Но подробно создание новых компонентов будет рассмотрено позже...

В данном случае для обработки сообщения WM_PAINT служит написание обработчика события OnDrawPanel. Собственно панели задаются в свойстве Panels, чаще всего встроенным редактором этой коллекции. Для панели, которая будет содержать не текст, нужно задать свойство Style = psOwnerDraw. Затем пишем обработчик OnDrawPanel. Он содержит достаточно параметров.

Пример пусть будет такой. Статусная панель по таймеру перерисовывается (вызовом метода Repaint), а заодно изменяется содержимое субпанелек. Да простят мне читатели некоторую кривоватость изображений, которые я использовал в примере. Народное программистское творчество :). Форма такая:

gif/68_1.gif (2178 b)

И код:

//---- sbmain.h-------------------------
#include <math.h>
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TStatusBar *StatusBar1;
	TTimer *Timer1;
	void __fastcall Timer1Timer(TObject *Sender);
	void __fastcall StatusBar1DrawPanel(TStatusBar *StatusBar,
	TStatusPanel *Panel, const TRect &Rect);
	void __fastcall FormDestroy(TObject *Sender);
private:	// User declarations
public:
Graphics::TBitmap* Images[4];
	__fastcall TForm1(TComponent* Owner);
};
//--------------------------------------------


//--- sbmain.cpp -----------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	for (int i=1;i < 5;i++)
	{
		Images[i-1] = new Graphics::TBitmap;
		Images[i-1]->LoadFromFile(IntToStr(i)+".bmp");
		Images[i-1]->Transparent = true;
	};
}
//-------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
	StatusBar1->Repaint();
}
//-------------------------------------------
void __fastcall TForm1::StatusBar1DrawPanel(TStatusBar *StatusBar,
	TStatusPanel *Panel, const TRect &Rect)
{
	static int ind = 0;
	static double angle = 0;
	static int time = 0;
	if (Panel->Index==2)
	{
		StatusBar->Canvas->Draw(Rect.Left, Rect.Top, Images[ind++]);
		if(ind==4)ind=0;
	};
	if (Panel->Index==0)
	{
		StatusBar->Canvas->MoveTo(Panel->Width/2, StatusBar->Height/2);
		StatusBar->Canvas->LineTo(Panel->Width/2+Panel->Width/2*cos(angle),
		StatusBar->Height/2+Panel->Width/2*sin(angle));
		angle += M_PI/16;
		if (angle == M_PI*2) angle = 0;
	}
	StatusBar->Panels->Items[1]->Text = 
		String().sprintf("Time passed: %02d", time++/2);
}
//-------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
	for (int i=0;i < 4;i++)
		delete Images[i];
}
//---------------------------------------

Четыре изображения, составляющие псевдоанимацию, должны находится в той же директории, что и исполнимый файл. Для разнообразия в первой секции сделано подобие секундомера. Вобщем, грузите проект, если что непонятно, разбирайтесь, пишите, etc. :)


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Аванесов Самвел - 28.03.2002