JhekaSoft
Меню
 Главная
 Программы
 Мульты
 Музыка
 Гостевая книга
 О сайте
Счётчики
Посетители
Locations of visitors to this page
-=Кнопка произвольной формы=-
Статьи

Во многих приложениях можно заметить, что кнопки не прямоугольной формы (например, круглой) становятся активными тогда, когда указатель мыши ещё не находится на них:

Неправильная кнопка

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

Общая схема такая: создаём для кнопки регион и затем проверяем, находится ли указатель мыши (или другого манипулятора :)) в этом регионе.

Для написания примера воспользуемся средой Borland Delphi.

Сначала разместим на форме экземпляр компонента изображения TImage. Загрузим какое-нибудь изображение окружности (свойство Picture). Далее изменим следующие свойства:

Свойство Значение
AutoSize True
Transparent True

Таким образом, изображение будет прозрачным и размер подгонится по размеру изображения.

Я также добавил TStatusBar для отображения текста (понадобится далее).

Далее объявляем переменную региона кнопки и переменную булевого типа, которая показывает, находится ли указатель мыши в регионе:

//Круглый регион
RgnCircle: HRGN;
//Находится ли указатель (мыши) в круглом регионе
inRgnCircle: Bool;

Затем создаём регион (круглый) и инициируем переменную inRgnCircle (указывающую находится ли указатель мыши в регионе) значением False:

//Круглый регион
RgnCircle := CreateEllipticRgn(0, 0,
  ImgCircle.Width, ImgCircle.Height);
//Указатель (мыши) находится не в круглом регионе
inRgnCircle := False;

Теперь напишем метод для обработки события изображения TImage OnMouseMove (когда курсор мыши перемещается по изображению):

procedure TFrmMain.ImgCircleMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  //Если указатель (мыши) в круглом регионе
  if PtInRegion(RgnCircle, X, Y) then
  begin
    //Указатель (мыши) находится в круглом регионе
    inRgnCircle := True;
    //Курсор в виде руки
    Cursor := crHandPoint;
  end else
  begin
    //Указатель (мыши) находится не в круглом регионе
    inRgnCircle := False;
    //Стандартный курсор
    Cursor := crDefault;
    //Очищаем текст в строке состояния
    StsBrMain.SimpleText := '';
  end;
end;

В этом коде используется функция PtInRegion(), которая проверяет находятся ли указанные координаты точки внутри заданного региона. Если указатель мыши внутри региона, то вид указателя применят форму руки и переменная inRgnCircle принимает значение True (это пригодится нам далее).

Указатель мыши может покинуть сразу и заданный регион и само изображение, поэтому необходимо обработать событие OnMouseMove самой формы:

procedure TFrmMain.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  //Указатель (мыши) находится не в круглом регионе
  inRgnCircle := False;
  //Стандартный курсор
  Cursor := crDefault;
  //Очищаем текст в строке состояния
  StsBrMain.SimpleText := '';
end;

Теперь обработаем клик кнопкой мыши по изображению (событие OnClick):

procedure TFrmMain.ImgCircleClick(Sender: TObject);
begin
  //Если указатель (мыши) в круглом регионе
  if inRgnCircle then
  begin
    //Текст в строке состояния
    StsBrMain.SimpleText := 'Клик по круглому изображению.';
  end;
end;

Здесь проверяется состояние булевой переменной inRgnCircle Если указатель мыши находится в регионе, то в StatusBar'е появляется текст говорящий, что нажата кнопка.

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

//Круглый регион
RgnCircle := CreateEllipticRgn(-1, -1,
  ImgCircle.Width + 2, ImgCircle.Height + 2);

Разумеется, что регионы можно создавать произвольной формы, простые (да и сложные) регионы можно комбинировать в сложные. Для этого есть стандартные функции WinApi: CreateRectRgn(), CreateRoundRectRgn(), CreateEllipticRgn(), CreatePolygonRgn().

Если изображение кнопки слишком сложное, то можно воспользоваться функцией BitmapToRgn():

function BitmapToRgn(Image: TBitmap): HRGN;
var
  TmpRgn: HRGN;
  x, y: integer;
  ConsecutivePixels: integer;
  TranparentColor: TColor; //Прозрачный цвет
  CurrentPixel: TColor;
  CurrentColor: TColor;
begin
  Result := CreateRectRgn(0, 0, Image.Width, Image.Height);

  if (Image.Width = 0) or (Image.Height = 0) then
    exit;

  TranparentColor := Image.Canvas.Pixels[0, 0]; //Прозрачный цвет

  for y := 0 to Image.Height - 1 do
  begin
    CurrentColor := Image.Canvas.Pixels[0, y];
    ConsecutivePixels := 1;
    for x := 0 to Image.Width - 1 do
    begin
      CurrentPixel := Image.Canvas.Pixels[x, y];

      if CurrentColor = CurrentPixel then
        inc(ConsecutivePixels)
      else
      begin
        // Входим в новую зону
        if CurrentColor = TranparentColor then
        begin
          TmpRgn := CreateRectRgn(x - ConsecutivePixels, y, x, y + 1);
          CombineRgn(Result, Result, TmpRgn, RGN_DIFF);
          DeleteObject(TmpRgn);
        end;
        CurrentColor := CurrentPixel;
        ConsecutivePixels := 1;
      end;
    end;

    if (CurrentColor = TranparentColor) and (ConsecutivePixels > 0) then
    begin
      TmpRgn := CreateRectRgn(x - ConsecutivePixels, y, x, y + 1);
      CombineRgn(Result, Result, TmpRgn, RGN_DIFF);
      DeleteObject(TmpRgn);
    end;
  end;
end;

Эта функция популярна и публикуется во многих источниках. Я чучуть изменил её, добавив определение прозрачного цвета по точке (0, 0) изображения. В функции нет ничего сложного. Она просто комбинирует непрозрачные линии, которые находит в изображении.

Пример

Конечно, в приведённом примере есть некоторые недостатки. Но сама идея, думаю, ясна :).

EXE'шник: rgn_btn.zip (26.3KB).

Исходники: rgn_btn_c.zip (38.4KB). В них примеры с круглым изображением, изображением прямоугольника со скруглёнными краями и сложного изображения.

Исходные коды написаны в Delphi 7, должны легко переконвертироваться для BDS.

▲Вверх

Статьи
Bash
Время
Твиттер
JhekaSoft в Твиттере:
Twitter
Орфография
Система Orphus
Заходи
Информационно-программный проект, посвященный свободному софту
Стихи
© 2007-2010 Евгений Анатольевич Ефремов

Hosted by uCoz