Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.149.27.202] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
На форме на разных панелях есть TButton (допустим их 20). Перед обработкой нажатия кнопки нужно проверить одно и то же условие. Если оно выполняется - обработать нажатие, то есть вызывать 20 разных процедур в зависимости от нажатой кнопки. Вставлять в каждый обработчик проверку условия - не подходит по некоторым причинам. Предполагаю, что можно назначить один OnClick на все кнопки, в обработчике OnClick проверить условие и при помощи Win API каким-нибудь образом идентифицировать, какая кнопка была нажата. Подозреваю что при помощи хэндлов. Только вот как ?
|
Сообщ.
#2
,
|
|
|
Dmitry_Z
Все проще. У каждой кнопки задай свой уникальный номер Tag(есть у всех визуальных компонентов), обычно по номеру кнопки. Сделай 1 обработчик для всех кнопок, и так отслеживай номер нажатой: ShowMessage(IntToStr( (Sender as TButton).tag )); |
Сообщ.
#3
,
|
|
|
Возможно, легче проверку вынести в отдельную функцию и просто вызывать ее в обработчиках (если действия, которые они должны выполнять, сильно отличаются).
|
Сообщ.
#4
,
|
|
|
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; type TForm1 = class(TForm) Panel1: TPanel; Panel2: TPanel; Panel3: TPanel; Panel4: TPanel; Panel5: TPanel; Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Button7: TButton; Button8: TButton; Button9: TButton; Button10: TButton; procedure MyButtonClick(Sender: TObject); private public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} const my_condition:boolean=true; { TForm1 } procedure TForm1.MyButtonClick(Sender: TObject); begin if my_condition then if (Sender is TButton) then ShowMessage((Sender as TButton).Name + ' clicked'); end; end. Если нужно обработать нажатие какой-нить конкретной кнопки, можно сделать так: procedure TForm1.MyButtonClick(Sender: TObject); begin if my_condition then if ((Sender is TButton) and ((Sender as TButton).Name='Button5')) then ShowMessage((Sender as TButton).Name + ' clicked'); end; См. проект в аттаче. Прикреплённый файлButtons_Click_Handler.zip (646,13 Кбайт, скачиваний: 285) |
Сообщ.
#5
,
|
|
|
Спасибо всем за ответы.
В другом форуме мне просто рекомендовали назначить всем кнопкам один обработчик и анализировать Sender. Я думаю что как-то так: procedure TForm1.Button1Click(Sender: TObject); begin if Sender = Button1 then ... else if Sender = Button2 then ... else if Sender = Button3 then ... ... end; |
Сообщ.
#6
,
|
|
|
Dmitry_Z, посмотри пост #5 - там именно это и делается.
|
Сообщ.
#7
,
|
|
|
А зачем так сложно ?
if ((Sender is TButton) and ((Sender as TButton).Name='Button5')) |
Сообщ.
#8
,
|
|
|
>А зачем так сложно ?
Потому что в общем случае Sender может быть другого типа без свойства Name. IMHO, c Tag проще, быстрее, легче автоматизировать (программно создать полсотни кнопок, например) |
Сообщ.
#9
,
|
|
|
Цитата Dmitry_Z @ А зачем так сложно ? Ничего сложного - это стандартная проверка на тип объекта, потому как Цитата MBo @ в общем случае Sender может быть другого типа Можно обойтись и без "Name": if ((Sender is TButton) and ((Sender as TButton)=Button5)) then ... Цитата MBo @ IMHO, c Tag проще, быстрее, легче автоматизировать (программно создать полсотни кнопок, например) К тому же это будет оптимальнее - как по скорости, так и по размеру кода. Юзать можно, например, так: procedure TForm1.MyButtonClick(Sender: TObject); begin // if my_condition then if (Sender is TButton) then case (Sender as TButton).Tag of 1: begin // if my_condition then ShowMessage((Sender as TButton).Name + ' clicked'); end; 2: begin // if my_condition then ShowMessage((Sender as TButton).Name + ' clicked'); end; 3: begin // if my_condition then ShowMessage((Sender as TButton).Name + ' clicked'); end; ... end; end; или так: procedure TForm1.MyButtonClick(Sender: TObject); var i:integer; begin // if my_condition then if (Sender is TButton) then for i:=1 to 10 do if (Sender as TButton).Tag=i then begin // if my_condition then ShowMessage((Sender as TButton).Name + ' clicked'); end; end; |
Сообщ.
#10
,
|
|
|
Цитата Krid @ Ничего сложного - это стандартная проверка на тип объекта, потому как Цитата MBo @ в общем случае Sender может быть другого типа Это не стандартная проверка, а примитивно-перестраховочная и "масло-масляная". Во-первых, после проверки типа по is нет смысла делать приведение типа по as (т.к. по сути это приводит к вызову повторной проверки типа по is) - достаточно прямого приведения типа к заданному классу (см. справку). Во-вторых, из той же справки следует, что операторы is и as используются в случае, когда реальный тип объекта может принадлежать заданному классу либо одному из его наследников. Если же по условию задачи наследники нас не интересуют, то вместо навороченной\тормозной проверки типа по is, можно использовать прямую проверку типа по if Sender.ClassType = TButton. Ну и наконец, в-третьих, если делается проверка принадлежности объекта не просто определенному классу, а конкретному экземпляру класса, то проверки по is\as вообще не нужны, т.к. твой вариант без "Name" if ((Sender is TButton) and ((Sender as TButton) = Button5)) then ... Поэтому ТС прав - если он не обращается к общим свойствам Sender as Component типа Name или Tag, а сразу делает проверку на принадлежность Sender определенному экземпляру кнопки Button1 и т.п., то его вариант #6 с прямыми проверками if Sender = Button1 и т.п. является наиболее простым, быстрым и "самодостаточным" (в том смысле, что никакие доп. проверки по is\as тут не нужны). |
Сообщ.
#11
,
|
|
|
Можно также не привлекать Tag (за его актуальностью еще следить надо), а создать массив кнопок, выполнять поиск Sender в нём и по индексу уже запускать действие. Минус в том, что нет очевидного соответствия между кнопкой и индексом.
Buttons = TArray<TButton>.Create(Button1, Button2, ...); case IndexOf(Buttons, Sender) of ... Возможно, код со сравнением Sender с Button1/2/3... окажется нагляднее всего. Во избежание сложной структуры кода в обработчике (если действия для каждой кнопки больше пары строк) можно убрать конструкции else: if Sender = Button1 then begin ... Exit; end; if Sender = Button2 then begin ... Exit; end; |
Сообщ.
#12
,
|
|
|
Ещё проще:
1 Сделать ActionManager с акшинами равными количеству кнопок. 2 Назвать каждый акшон так-же как и кнопку+1 любой символ(например AButton1) 3 Все кнопки зациклить на 1 кнопку. 4 вызывать (FindComponent('A'+ (sender as TButton).Name) as TAction).Execute; |
Сообщ.
#13
,
|
|
|
Спасибо всем.
Дело в том что я кое-что переделываю в сотнях строк уже написанного кода. У меня уже есть обработчики десятка кнопок. Я разместил на форме еще одну кнопку с visible := false, в её обработчике разместил код procedure TForm1.SelectorButtonClick(Sender: TObject); begin if Sender = Button1 then Button1Click(Sender) else if Sender = Button2 then Button2Click(Sender) else if Sender = Button3 then Button3Click(Sender) ... else if Sender = Button10 then Button10Click(Sender); end; Так "не взлетит" ? Вроде бы пока всё работает... |
Сообщ.
#14
,
|
|
|
1. Невидимая кнопка зачем? Обработчик - это просто метод формы
2. Если есть уже нужные обработчики - зачем этот огород? Вообще конечно взлетит, но смысла в этом немного |
Сообщ.
#15
,
|
|
|
Цитата Dmitry_Z @ procedure TForm1.SelectorButtonClick(Sender: TObject); begin if Sender = Button1 then Button1Click(Sender) else if Sender = Button2 then Button2Click(Sender) else if Sender = Button3 then Button3Click(Sender) ... else if Sender = Button10 then Button10Click(Sender); end; а есть аналог findcomponent только для процедуры? Типа Button+'10'+Click(Sender)? |