Сообщений 51    Оценка 55 [+0/-2]         Оценить  
Система Orphus

SWL – Small Windows Library

Автор: Alexander Kluev
Pragmaworks Group
Опубликовано: 05.02.2003
Исправлено: 13.03.2005
Версия текста: 1.0

Исходные тексты и демонстрационный проект

Small Windows Library – это экспериментальная оконная библиотека вокруг win32. Особой практической ценности она не представляет ввиду неизбежности ухода win32 со сцены, но тем не менее иллюстрирует еще один способ организации оконной библиотеки. Она предназначена показать красоту С++ и убожество win32.

В основном для создания оконных библиотек под win32 используются либо базовый класс с множеством виртуальных функций обработчиков, либо карты сообщений. Известно, что второй способ лучше первого. SWL – это библиотека на базе карт сообщений, только в отличии от MFC\ATL и других в ней не используются макросы, вместо них используется язык С++.

Итак простая программа с простым окном на базе SWL:

#include "stdafx.h"
#include "swl.h"

using namespace SWL;

// простое окно с кнопкой на базе SWL
class MyWindow : public SWL::Wnd {
	SWL::Button		_btnTest;	// кнопка

public:
// msg_handle виртуальная функция обработки сообщений:
	void msg_handle( MsgBase *msg ) {
		// карта сообщений (должна быть static).	
		static Handler mmp[] = {
			Handler::begin(),                       // начало карты
				Handler( &MyWindow::wm_paint ),  // WM_PAINT
				Handler( &MyWindow::wm_close ),  // WM_CLOSE
				Handler( &MyWindow::wm_create ), // WM_CREATE
			Handler::end()                          // конец карты
		};

		// поиск обработчика в карте
		if ( Handler::call( mmp, this, msg ) )
			Wnd::msg_handle( msg ); // если не обработано вызываем базовый класс
	}

// обработчики сообщений:
	void wm_paint( Msg<WM_PAINT> &msg ) { // Msg<WM_PAINT> - теперь вы поняли в чем хитрость? Код сообщения в аргументе
		HDC hdc = msg.paint_begin( hwnd() ); // внимание: Msg<WM_PAINT>::paint_begin
		
		RECT rc;
		GetClientRect( hwnd(), &rc );
		DrawText( hdc, "Hello SWL!", -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
		
		msg.paint_end( hwnd() );
	}

	void wm_close( Msg<WM_CLOSE> &msg ) {
		PostQuitMessage( 0 );
	}

	void wm_create( Msg<WM_CREATE> &msg ) {
		CREATESTRUCT &cs = msg.cs(); // внимание: используем Msg<WM_CREATE>::cs для получения CREATESTRUCT&
		_btnTest.create( "Test", Rect( 20, 20, 80, 40 ), this );	// создадим кнопку
		_btnTest.onClick.set( &MyWindow::btnTest_onClick );		// установим обработчик нажатия
	}

// нажатие кнопки:
	void btnTest_onClick( Wnd* ) {
		MessageBox( *this, "MyWindow::btnTest_onClick", "Hello SWL", MB_OK );
	}
};

// точка входа
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int ) {
	MSG msg;
	MyWindow wnd; // наше окно

	wnd.create( NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, "Hello SWL!" ); // создадим окно

	while ( GetMessage( &msg, NULL, 0, 0 ) ) { // стандартный цикл сообщений
		TranslateMessage( &msg );
		DispatchMessage( &msg );
	}

	return 0;
}

Приведу краткое описание основных компонентов библиотеки. Базовым классом для всех окон является класс SWL::Wnd. Обработка сообщений осуществляется виртуальной функцией msg_handle. Ее следует переопределить в дочерних классах поместив в нее карту сообщений:

void MyWindow::msg_handle( MsgBase *msg ) {
	// карта сообщений (должна быть static).	
	static Handler mmp[] = {
		Handler::begin(),                       // начало карты
			Handler( &MyWindow::wm_paint ),  // WM_PAINT
			Handler( &MyWindow::wm_close ),  // WM_CLOSE
			Handler( &MyWindow::wm_create ), // WM_CREATE
		Handler::end()                          // конец карты
	};
	// поиск обработчика в карте
	if ( Handler::call( mmp, this, msg ) )
		Wnd::msg_handle( msg ); // если не обработано вызываем базовый класс
}

Карта сообщений представляет из себя статический (дабы избежать многократной инициализации) массив обьектов типа Handler. Класс Handler – это хитрость библиотеки SWL. Он имеет шаблонный конструктор который вытаскивает код сообщения из аргумента функции обработчика.

Функции-обработчики обьявляются следующим способом

void MyWindow::wm_create( Msg<WM_CREATE> &msg ) { // аргумент функции содержит код сообщения 
	CREATESTRUCT &cs = msg.cs(); // внимание: используем Msg<WM_CREATE>::cs для получения CREATESTRUCT&
	_btnTest.create( "Test", Rect( 20, 20, 80, 40 ), this );	// создадим кнопку
	_btnTest.onClick.set( &MyWindow::btnTest_onClick );		// установим обработчик нажатия
}

Аргумент функции обработчика - шаблонный класс Msg – изюминка библиотеки. Классы Msg могут быть специализироваными для конкретных сообщений. Некоторые из них я специализировал в файле SwlMsg.h. Например Msg<WM_CREATE> содержит функцию для извлечения LPCREATESTRUCT из параметров сообщения:

template <> struct Msg<WM_CREATE> : MsgBase {
	Msg( MsgBase &msg ) : MsgBase(msg) {}
public:
	// извлечение LPCREATESTRUCT из LPARAM
	CREATESTRUCT& cs() const { 
		return *(LPCREATESTRUCT)lprm; 
	}
};

Кроме всего прочего в классе SWL::Wnd есть две функции создания окна: create – создать новое SWL окно и subclass – создать окно на базе оконного класса win32. Все остальные хитрости можно посмотреть прямо в исходном коде.

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


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 51    Оценка 55 [+0/-2]         Оценить