Пропустить навигацию.
Главная

Специфика обработки событий кнопок

Выше упоминалось, что главным событием основных кнопок, на которое должен реагировать соответствующий обработчик, является щелчок мышью по кнопке (Click в VB, OnClick в BCB и Delphi). По времени событию Click предшествует переход фокуса к кнопке. В среде Visual Basic такая ситуация вызывает событие GotFocus, в средах BCB и Delphi аналогичное событие называется OnEnter. Когда кнопка теряет фокус, возникает событие LostFocus (в VB) или OnExit (в BCB и Delphi). Каждое из перечисленных выше событий передает сообщение выбранной кнопке (точнее — обработчику соответствующего события этой кнопки), не содержащее никаких параметров.

Однако одновременно с выбором кнопки и возникновением одного из трех упомянутых событий пользователь может нажать какую-нибудь клавишу или сочетание клавиш на клавиатуре. В этой ситуации последовательно возникают события KeyDown, KeyPress и KeyUp, которые адресуются кнопке, находящейся в фокусе. В этих сообщениях обработчики событий получают код нажатой клавиши и битовую шкалу с комбинацией одновременно нажатых управляющих клавиш <Alt>, <Ctrl> и <Shift>.

Приложение 5_09 (VB).

Довольно часто кнопки объединяют в группы с целью упрощения обработки однотипных событий. Рассмотрим в качестве примера VB-приложения наборную панель микрокалькулятора, где будут реализованы только две функции — сброс окна операнда и набор целочисленного значения с помощью цифровых кнопок (рис. 5.14).

Кнопки и меню

Рис. 5.14. Окно VB-приложения

Для формирования окна поместим рамку (Frame1), разместим на ней 10 командных кнопок (Command1, Command2, …). Выровняем их размеры и заменим стандартные заголовки на цифры от 0 до 9. Кнопки уже сгруппированы, но это выражается лишь в том, что перемещение рамки автоматически сдвигает и ее содержимое. Чтобы достичь большего, попробуем заменить значения свойств Name у всех кнопок на одно и то же имя, например, на Cif. Для первой кнопки такая замена проходит без замечаний. На второй — система предупредит нас о существовании объекта с таким же именем:

Кнопки и меню

Рис. 5.15. Запрос подтверждения на создание массива компонент

Так как мы действительно хотим создать массив кнопок, что облегчит процедуру написания обработчика событий, то отвечаем утвердительно, и дальнейшее переименование проходит без замечаний. Переименование разумно вести в порядке возрастания цифр, соответствующих надписям на кнопках. Дело в том, что появления массива с кнопками порождает у каждой кнопки новое свойство — Index. Совпадение индекса кнопки с ее надписью также поможет нам упростить структуру обработчика события Click, который в случае массива будет обслуживать одновременно все кнопки:

Private Sub Cif_Click(Index As Integer)

If Len(Text1.Text)=0 And Index=0 Then Exit Sub

Text1.Text=Text1.Text & Chr(Asc(0) + Index)

End Sub

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

Еще одна кнопка Command11 с надписью <Сброс> предназначена для очистки окна ввода:

Private Sub Command11_Click()

Text1.Text = ""

End Sub

Приложение 5_10 (BCB).

Создадим аналогичный проект в среде BCB. Для объединения кнопок разместим на форме объект GroupBox и положим на него одну кнопку типа TButton. Подберем разумные размеры выделенной кнопки и скопируем ее в Clipboard командой Copy из меню Edit (копировать можно не только выделенные фрагменты текста, но и выделенные объекты). Затем вставим скопированный объект и, зажав клавишу Ctrl, стрелками перемещения курсора отбуксируем кнопку на свое место. Повторим эти операции для каждой цифровой кнопки и заменим их заголовки (Caption) соответствующими цифрами. В качестве строки, предназначенной для индикации набираемого числа, придется выбрать объект Label. Более подходящее окно ввода Edit, к сожалению, не умеет прижимать текст к правой границе. Чтобы поле метки не потерялось на сером фоне формы, поменяем цвет метки (Color = clBtnHeighlight). Запретим метке подгонять свою ширину под размер текста (AutoSize=false) и установим правый прижим (Alignment=taRightJustify).

Для написания общего обработчика события OnClick на Си потребуется некоторая хитрость. Во-первых, надо выделить все цифровые кнопки и на закладке Events в Инспекторе Объектов щелкнуть по событию OnClick. Это позволит приписать всем кнопкам общую процедуру. Во-вторых, обработчик события получит указатель на объект Sender, пославший сообщение. Но этот указатель имеет обобщенный тип TObject. Поэтому нельзя напрямую обратиться за свойством Sender->Caption. Придется завести указатель типа TButton и выполнить приведение типа параметра Sender с помощью функции static_cast:

void __fastcall TForm1::Button10Click(TObject *Sender)

{//Прием цифры и отображение числа

AnsiString k;

TButton *pb=static_cast<TButton *>(Sender);

K = pb->Caption;

if(!(Label1->Caption == "" && k == '0'))

Label1->Caption = Label1->Caption + k;

}

//-----------------------------------------------------------

void __fastcall TForm1::Button11Click(TObject *Sender)

{//Сброс числа

Label1->Caption="";

}

//-----------------------------------------------------------

В приведенном примере для анализа нажатой кнопки было использовано свойство Caption, имеющее тип AnsiString. Такие данные удобно сравнивать, присоединять к другим текстовым величинам. В другой задаче более полезным могло оказаться целочисленное свойство Tag. По умолчанию его значение равно 0, но мы можем присвоить для каждой кнопки соответствующее значение.

Приложение 5_11 (Delphi).

Разработка аналогичного проекта в среде Delphi тоже связана с преобразованием типа данных для параметра Sender. Однако в Паскале это преобразование сделано существенно проще и не требует применения дополнительного указателя:

procedure TForm1.Button10Click(Sender: TObject);

begin

with Sender As TButton do

begin

if not((Label1.Caption='')and(Caption ='0')) then

Label1.Caption:=Label1.Caption + Caption;

end

end;

procedure TForm1.Button11Click(Sender: TObject);

begin

Label1.Caption:='';

end;