Приветствую вас, уважаемые читатели. Вместе с вами на протяжении неопределенно долгого времени мы будем рассматривать различные интересные темы и возможности Delphi.
Прежде всего мне хотелось бы поблагодарить администратора клуба программистов - Грома. Именно благодаря ему наше с вами общение стало возможным и впоследствии будет приносить всеобщую пользу.
Вы читаете мою первую статью. Ее я решил посвятить созданию непрямоугольных форм, а также форм на основе растровой картинки (имеется в виду формат BMP), в связи с популярностью этой темы среди программистов Delphi. По своей востребованности данную тему
можно сравнить, пожалуй, лишь с проблемой помещения значка приложения на панель задач (там, где часы). Кстати, об этом будет моя следующая статья, которая появится на свет очень скоро.
Посмотрим, с какими сложностями нам придется столкнуться и каким образом их разрешить.
Внешний вид формы можно изменить используя всего лишь одну API функцию
SetWindowRgn(Form1.Handle, True); // Второй параметр всегда равен True
Правда, перед этим потребуется создать подходящий регион. Большинство из тех, кто работает на Delphi, не знают, что такое регион; главным образом потому, что эта вещь не нашла своего отражения в VCL.
Документация утверждает, что регион, это "прямоугольник, многоугольник, эллипс или комбинация двух или более фигур из приведённого списка". Регионы используются для "заливки, отсечения (то, что по английски называется clipping)" и других, не менее полезных операций.
По поводу вышеуказанной функции в help'е говорится следующее:
The
SetWindowRgn function sets the window region of a window. The window region determines the area within the window where the operating system permits drawing. The operating system does not display any portion of a window that lies outside of the window region
int SetWindowRgn(
HWND hWnd, // handle to window whose window region is to be set
HRGN hRgn, // handle to region
BOOL bRedraw // window redraw flag
);
ParametershWnd Handle to the window whose window region is to be set
hRgn Handle to a region. The function sets the window region of the window to this region. If hRgn is NULL, the function sets the window region to NULL.
bRedraw Boolean value that specifies whether the operating system redraws the window after setting the window region. If bRedraw is TRUE, the operating system does so; otherwise, it does not.
Typically, you set bRedraw to TRUE if the window is visible.
Что в переводе с буржуйского примерно означает:
Функция
SetWindowRgn устанавливает регион для окна (формы). Регион окна определяется областью внутри нее, на
прорисовку которой операционная система получает разрешение. Операционная система не отображает другие части окна,
находящиеся за пределами региона
int SetWindowRgn(
HWND hWnd, // хендл (Handle) окна, регион для которого требуется установить
HRGN hRgn, // хендл непосредственно самого региона
BOOL bRedraw // флаг перерисовки окна
);
Другими словами, функция
SetWindowRgn определяет область, которая будет выведена
на экран. Все, что находится вне этой области, естественно, выведено на экран не будет.
То есть остается только одна сложность: сформировать нужный регион и подставить его хендл в функцию
SetWindowRgn в качестве параметра.
Для создания регионов существуют следующие функции:
CreateRectRgn - как видно из названия, создание прямоугольного региона,
CreateEllipticRgn - создание региона в форме эллипса,
CreatePolygonRgn - регион, определяемый пользователем (вручную).
Также существует возможность объединения нескольких регионов путем использования функции и несколько других. Объединять регионы между собой можно при помощи функции
CombineRgn, но в данной статье эта функция рассмотрена не будет. Мы с вами воспользуемся немного более простым методом, а именно следующей функцией, которую напишем вручную.
function BitmapToRegion(Bitmap: TBitmap; TransColor: TColor): HRGN;
Итак, приступим! Напишем функцию, которая сделает прозрачной (невидимой) область указанного цвета (в нашем случае белого) в параметре
TransColor и вернет нам хендл (указатель) на вновь созданный регион...
function BitmapToRegion(Bitmap: TBitmap; TransColor: TColor): HRGN;
var X, Y: Integer;
XStart: Integer;
begin
Result := 0;
with Bitmap do
for Y := 0 to Height - 1 do
begin
X := 0;
while X < Width do
begin
// Пропускаем прозрачные точки
while (X < Width) and (Canvas.Pixels[X, Y] = TransColor) do
Inc(X);
if X >= Width then
Break;
XStart := X;
// Пропускаем непрозрачные точки
while (X < Width) and (Canvas.Pixels[X, Y] <> TransColor) do
Inc(X);
// Создаём новый прямоугольный регион и добавляем его к
// региону всей картинки
if Result = 0 then
Result := CreateRectRgn(XStart, Y, X, Y + 1)
else
CombineRgn(Result, Result,
CreateRectRgn(XStart, Y, X, Y + 1), RGN_OR);
end;
end;
end;
По сути, ничего сложного. Есть растровая картинка. Она может быть нарисована с использованием различных цветов, но область, которую необходимо сделать прозрачной, должна быть одного цвета (к примеру, белого). Для того, чтобы наиболее точно произвести построение результативного региона, цвет самой формы поставим аналогично цвету прозрачной области (в данном случае clWhite).
Регион создан, и нам остается лишь установить его для формы. Вызовем необходимые функции в момент создания формы:
procedure TForm1.FormCreate(Sender: TObject);
Var RGN : HRGN;
begin
// создаем регион для картинки
RGN:= BitmapToRegion(Image1.Picture.Bitmap, clWhite);
// устанавливаем новый регион
SetWindowRgn(Form1.Handle, RGN, True); // второй параметр всегда равен True
end;
Для простоты понимания я написал простенькую
программу - region.zip, в которой реализуются вышеуказанные функции. Естественно, вы можете создать свой рисунок, на основе которого будет построена форма.
В завершение хотелось бы подчеркнуть тот факт, что направленность и контент публикуемых здесь статей определяется в первую очередь определяются вашими интересами. Поэтому жду ваших предложений.
До новых встреч! Удачи!
С уважением, Ремин Максим.