Delphi – кнопка на основе TPanel

Для чего мы используем компонент TPanel, неужели для компоновки элементов интерфейса, или может кто использует для надписей. Конечно это прямое назначение компонента TPanel, по крайней мере про компоновку элементов.

Ну, а что если TPanel, можно использовать как-то по другому?Да, действительно можно. Эта замечательная идея мне пришла, когда я писал очередной проект и мне захотелось чтобы пользователь смог сам настраивать вид столбцов TDBGrid, а именно выбирать раскраску столбцов. Конечно это можно было бы достичь и другим путем, например использовать TRadioButton, TRadioGroup, TCheckBox или TListBox, ну или на крайний случай обычную кнопку для того чтобы выбирать столбец, который мы хотим раскрасить. Но все это было бы достаточно просто и некрасиво в моей ситуации. Мне было нужно чтобы пользователь на что-то нажимал (типа кнопки) и эффект был как у TSpeedButton со свойством Down установленным в true. Конечно можно было бы и использовать ту самую кнопку – TSpeedButton. Вроде все бы и хорошо, есть у кнопки и свойство Down и группировать можно, но нельзя присваивать ей цвет. Т.е. по любому надо было бы применять нестандартные методы, но кнопку нельзя отжать обратно, пока не нажмешь кнопку из той же группы, что мне тоже не очень нравилось.

Но поскольку вариант с кнопкой тоже не очень подходил, я решил посмотреть, что можно сделать  с TPanel, какую комбинацию стилей подобрать, чтобы при клике на ней она выглядела как кнопка TSpeedButton со свойством Down установленным в true. Оказалось, что достаточно изменять стиль: типа TBorderStyle с bsNone на bsSingle и обратно. Осталось все это реализовать.

Первым делом бросаем на форму пару TPanel. У меня их для примера четыре штуки:

Нестандартные кнопки на основе компонента TPanel

Затем объявляем тип:

type
  TypeStyle = record
    Flag: Byte;
end;

Flag – это состояние панели на данный момент (какой стиль к ней применен).

Можно конечно и простой переменной воспользоваться было.

Затем объявляем константу как массив типа TBorderStyle с перечислением нужных нам значений:

const
PanelStyle: array[1..2] of TBorderStyle = (bsNone, bsSingle);

И две переменные:

var
Number: Byte;
massiv: array[1..5] of TypeStyle;

Number – Номер панели (вернее ее Tag)

massiv: array[1..5] of TypeStyle – массив со стилями, на один элемент массива должно быть больше чем количество панелей. В нашем случае massiv[5] будет означать, что ни одна панель не нажата. Продолжаем…

Теперь установите свойство Tag у каждой панели по возрастающей начиная с 1.

У меня:

TPanel1.Tag = 1;
TPanel2.Tag = 2;
TPanel3.Tag = 3;
TPanel4.Tag = 4;

Сразу напишем процедуру по смене стиля:

procedure TForm1.SetDown(Index: Integer);
begin
massiv[Index].Flag := massiv[Index].Flag xor 1;

case Index of
1: Panel1.BorderStyle := PanelStyle[massiv[Index].Flag + 1];
2: Panel2.BorderStyle := PanelStyle[massiv[Index].Flag + 1];
3: Panel3.BorderStyle := PanelStyle[massiv[Index].Flag + 1];
4: Panel4.BorderStyle := PanelStyle[massiv[Index].Flag + 1];
  end;
end;

При клике на панель у нее сменяется стиль, и она выглядит нажатой. При повторном клике стиль сменяется снова, и панель приобретает нормальный вид.

Далее напишем общую процедуру для всех панелей по обработке события OnMouseDown:

procedure TForm1.AllPanel(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
P: TPanel;
begin
P := Sender as TPanel;

SetDown(Number);

if Number <> P.Tag then
begin
Number := P.Tag;
SetDown(Number);
end
 else
Number := 5;
end;

Вот в принципе и все.

Сам процесс смены цвета я не описывал, все это вы можете посмотреть в прилагаемых исходниках.