Собственные элементы интерфейса.
Часть 2
© 2009 Антон Петрушенков, Wiseman Softworks
Итак, продолжим начатое в статье “Собственные элементы интерфейса” обсуждение базового класса кнопки - нашего первого собственного элемента интерфейса.
Класс TCustomButton. Продолжаем разбор.
Не буду повторять здесь текст класса, дабы совсем уж не загромождать статью - кода ещё будет предостаточно. Обратитесь к предыдущей статье или к тексту исходников. В этой статье я, как и обещал, закончу разбор класса и опишу процесс “встраивания” собственных элементов в реальное приложение.
Разберём процедуры класса. Конструктору передаются две переменные. Они, как несложно догадаться, присваиваются полям ParentCanvas и PosRect соответственно. Там же в конструкторе указываем, что наша кнопка при создании не выделена и не нажата. В общем случае делать это не обязательно, т.к. false это значение по умолчанию любой переменной типа boolean. Однако, такой ортодоксальный подход часто себя окупает - потратив две строчки кода мы точно видим, что происходит с каждым полем нашего класса и знаем, что всё у нас под контролем :-) .
constructor TCustomButton.Create(Canvas: TCanvas; TheRect: TRect);
begin
ParentCanvas := Canvas;
PosRect := TheRect;
Selected := False;
Pressed := False;
end;
Следующие три процедуры служат для передвижения кнопки и динамического изменения её размеров. Все они изменяют поле PosRect, которое мы благоразумно поместили в private область нашего класса.
procedure TCustomButton.ChangeWidth(NewWidth: integer);
begin
PosRect.Right := PosRect.Left + NewWidth;
end;
/////*******
procedure TCustomButton.ChangeHeight(NewHeight: integer);
begin
PosRect.Bottom := PosRect.Top + NewHeight;
end;
/////*******
procedure TCustomButton.ChangePosition(NewLeft, NewTop: integer);
begin
PosRect.Left := NewLeft;
PosRect.Top := NewTop;
end;
Функция InRect служит для отслеживания попадания курсора в кнопку. В моём примере приведена простейшая её вариация - проверка попадания в прямоугольник PosRect. Однако, никто не мешает сделать её сложнее и правильно отслеживать попадание в круглую, треугольную, да вобщем-то любую кнопку.
function TCustomButton.InRect(X, Y: integer): boolean;
begin
Result := False;
if (X > PosRect.Left) AND (X < PosRect.Right) then
if (Y > PosRect.Top) AND (Y < PosRect.Bottom) then
Result := true;
end;
Процедура Draw самая интересная - в ней мы описываем внешний вид и поведение кнопки. В зависимости от текущего статуса кнопки (выделена? нажата?) мы рисуем в родительский Canvas, всё что хотим. Можно пользоваться стандартными средствами GUI, можно рисовать заранее загруженные в память bmp файлы, можно совмещать эти подходы. В моём примере я использовал GUI и не сильно морочился с дизайном - главное в данном случае - наглядность.
procedure TCustomButton.Draw;
begin
if Pressed then
begin
ParentCanvas.Brush.Color := clRed;
ParentCanvas.FillRect(PosRect);
Exit;
end;
if Selected then
begin
ParentCanvas.Brush.Color := clGreen;
ParentCanvas.FillRect(PosRect);
end
else
begin
ParentCanvas.Brush.Color := clGreen;
ParentCanvas.Pen.Color := clGreen;
ParentCanvas.Ellipse(PosRect);
end;
end;
Класс TExampleForm. Собственные элементы в реальном приложении.
Чтобы наша кнопка правильно отображалась в реальном приложении нам надо настроить обработчики её “родителя” для связанных с ней событий. В нашем случае родителем кнопки является простая форма, в примере всё максимально просто. Посмотрим, с какими событиями мы будем работать.
TExampleForm = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
end;
Далее мы подробно рассмотрим содержание и назначение каждого обработчика. В нашем примере для кнопки мы просто заводим глобальную переменную:
var
ExampleForm: TExampleForm;
CButton : TCustomButton;
Разумеется для реальных приложений этот подход применять не стоит. Как вариант, используйте глобальный объект-контейнер, который будет управлять иерархическими списками более мелких объектов… или ещё чего поинтереснее придумайте .
Конструктор формы максимально прост. Мы создаём объект CButton класса TCustomButton с нужными нам параметрами. Передаём объекту Canvas нашей формы, т.к. собираемся рисовать именно в него. Задаём размеры и положение кнопки. Заодно выставляем для формы свойство DoubleBuffered в true - это обеспечит нам отсутствие “мерцания” изображения при прямом выводе на форму.
procedure TExampleForm.FormCreate(Sender: TObject);
begin
DoubleBuffered := true;
CButton := TCustomButton.Create(Canvas, Rect(150,100,250,200));
end;
Обработчик события OnPaint посложнее. Перед каждой прорисовкой мы очищаем поверхность формы. Для этого пользуемся функцией InvalidateRect, выставив параметр bErase в true. В нашем примере мы очищаем всю форму, но при желании, можно это делать лишь частично.
После очистки мы рисуем нашу кнопку - выполняем ту саму процедуру TCustomButton.Draw. Если бы у нас было несколько кнопок, следовало бы вызвать процедуру Draw для каждой из них.
procedure TExampleForm.FormPaint(Sender: TObject);
var R : TRect;
begin
/// Cleaning the screen
R := ClientRect;
InvalidateRect(handle, @R, true);
/// Drawing our button
CButton.Draw;
end;
Событие OnMouseMove вызывается формой при движении над ней курсора мыши. При помощи функции InRect (описанной выше) мы отслеживаем положение курсора относительно кнопки и реагируем на наведение. Очень важно после каждого изменения статуса кнопки перерисовывать форму - иначе пользователь не увидит соответсвующей реакции.
procedure TExampleForm.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
CButton.Selected := CButton.InRect(X,Y);
OnPaint(Self);
end;
Следующее событие OnMouseDown - в нём мы обрабатываем нажатия кнопок мыши над формой. В нашем примере, мы следим только за левой кнопкой, и если при нажатии курсор мыши над нашей кнопкой, мы изменяем статус кнопки и перерисовываем форму.
procedure TExampleForm.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
begin
CButton.Pressed := CButton.InRect(X,Y);
onPaint(Self);
end;
end;
В последнем событии OnMouseUp мы обрабатываем отпускание кнопки мыши над формой. Если кнопка до отпускания была нажата - мы выполняем действие связанное с этой кнопкой, изменяем статус и перерисовываем форму.
Повторюсь, в нашем примере всё максимально просто - мы не рассматриваем пример кнопки “запоминающей” нажатие, не рассматриваем кластеры кнопок и т.п. но все эти поведения очень просто реализовать пользуясь описанной технологией.
procedure TExampleForm.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if CButton.Pressed then
begin
/// Do something here when the button is released...
/// ...
/// Stop doing.
CButton.Pressed := false;
OnPaint(Self);
end;
end;
Заключение.
Таким образом, мы видим, что создать собственную кнопку, задать её поведение и внешний вид - довольно просто. На всякий случай повторю исходный текст примера.
Я намереваюсь продолжить цикл статей, и опишу создание более сложных элементов интерфейса.
Если вы заинтересовались этой темой, или у вас есть вопросы - не стесняйтесь оставить комментарий. Я постараюсь помочь.
Copyright© 2009 Антон Петрушенков, Wiseman Softworks
| 2011 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2010 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2009 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2008 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2007 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2006 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2005 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2004 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2003 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2002 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2001 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2000 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 1999 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
- Компания по разработке программного обеспечения
- Услуги аутсорсинга в области программирования
- Как продлить срок службы картриджей
- Мошенничество во Всемирной Паутине. Осторожно: фишинг!
- Web-студия
- Как легально поднять уровень индекса цитирования.
- Мы реально сможем помочь вам в управлении предприятием
- Создание сайтов – популяризация вашего замысла
- Свой сайт. Управление ресурсом
- Семантическое ядро сайта или правила подбора ключевых фраз
- Программирование в среде Delphi 8 for .NET
- Практикум по Delphi для решения прикладных задач
- Фундаментальные алгоритмы и структуры данных в Delphi
- Delphi 6. Программирование на Object Pascal
- Delphi и технология COM
- Delphi в шутку и всерьез: что умеют хакеры
- Программирование в Delphi глазами хакера
- Delphi 2005. Секреты программирования
- Искусство создания компонентов Delphi
- Приемы программирования в Delphi на основе VCL
- Программирование баз данных в Delphi 7
- Программирование баз данных в Delphi
- Программирование в среде Delphi
- Программирование в Delphi 7
- Язык SQL в Delphi 5