На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Обработчик нажатия нескольких кнопок, Собрать обработку нажатия нескольких кнопок в одну функцию
На форме на разных панелях есть TButton (допустим их 20). Перед обработкой нажатия кнопки нужно проверить одно и то же условие. Если оно выполняется - обработать нажатие, то есть вызывать 20 разных процедур в зависимости от нажатой кнопки. Вставлять в каждый обработчик проверку условия - не подходит по некоторым причинам. Предполагаю, что можно назначить один OnClick на все кнопки, в обработчике OnClick проверить условие и при помощи Win API каким-нибудь образом идентифицировать, какая кнопка была нажата. Подозреваю что при помощи хэндлов. Только вот как ?
Dmitry_Z
Все проще. У каждой кнопки задай свой уникальный номер Tag(есть у всех визуальных компонентов), обычно по номеру кнопки.
Сделай 1 обработчик для всех кнопок, и так отслеживай номер нажатой:
ExpandedWrap disabled
      ShowMessage(IntToStr(  (Sender as TButton).tag  ));
"Воля - это то, что заставляет тебя побеждать, когда твой рассудок говорит тебе, что ты повержен" Карлос Кастанеда
Возможно, легче проверку вынести в отдельную функцию и просто вызывать ее в обработчиках (если действия, которые они должны выполнять, сильно отличаются).
Codero ergo sum
// Программирую — значит, существую
ExpandedWrap disabled
    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.


Если нужно обработать нажатие какой-нить конкретной кнопки, можно сделать так:

ExpandedWrap disabled
    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 Кбайт, скачиваний: 7)
Кто рано встает, тому целый день спать хочется
Спасибо всем за ответы.
В другом форуме мне просто рекомендовали назначить всем кнопкам один обработчик и анализировать Sender.
Я думаю что как-то так:
ExpandedWrap disabled
    procedure TForm1.Button1Click(Sender: TObject);
    begin
     if Sender = Button1 then ...
     else if Sender = Button2 then ...
          else if Sender = Button3 then ...
    ...
    end;
Сообщение отредактировано: Dmitry_Z -
Dmitry_Z, посмотри пост #5 - там именно это и делается.
Кто рано встает, тому целый день спать хочется
А зачем так сложно ?
ExpandedWrap disabled
    if ((Sender is TButton) and ((Sender as TButton).Name='Button5'))
>А зачем так сложно ?
Потому что в общем случае Sender может быть другого типа без свойства Name.

IMHO, c Tag проще, быстрее, легче автоматизировать (программно создать полсотни кнопок, например)
Цитата Dmitry_Z @
А зачем так сложно ?

Ничего сложного - это стандартная проверка на тип объекта, потому как
Цитата MBo @
в общем случае Sender может быть другого типа


Можно обойтись и без "Name":
ExpandedWrap disabled
    if ((Sender is TButton) and ((Sender as TButton)=Button5)) then ...


Цитата MBo @
IMHO, c Tag проще, быстрее, легче автоматизировать (программно создать полсотни кнопок, например)

:yes: К тому же это будет оптимальнее - как по скорости, так и по размеру кода.

Юзать можно, например, так:
ExpandedWrap disabled
    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;

или так:
ExpandedWrap disabled
    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;
Кто рано встает, тому целый день спать хочется
Цитата Krid @
Ничего сложного - это стандартная проверка на тип объекта, потому как
Цитата MBo @
в общем случае Sender может быть другого типа

Это не стандартная проверка, а примитивно-перестраховочная и "масло-масляная".
Во-первых, после проверки типа по is нет смысла делать приведение типа по as (т.к. по сути это приводит к вызову повторной проверки типа по is) - достаточно прямого приведения типа к заданному классу (см. справку).
Во-вторых, из той же справки следует, что операторы is и as используются в случае, когда реальный тип объекта может принадлежать заданному классу либо одному из его наследников. Если же по условию задачи наследники нас не интересуют, то вместо навороченной\тормозной проверки типа по is, можно использовать прямую проверку типа по if Sender.ClassType = TButton.
Ну и наконец, в-третьих, если делается проверка принадлежности объекта не просто определенному классу, а конкретному экземпляру класса, то проверки по is\as вообще не нужны, т.к. твой вариант без "Name"
ExpandedWrap disabled
    if ((Sender is TButton) and ((Sender as TButton) = Button5)) then ...
срабатывает в одном единственном случае, когда pointer(Sender) = pointer(Button5) независимо от класса объекта. Поэтому проверка по is тут является излишней, а приведение типа по as вообще не имеет смысла, т.к. as меняет только формальный тип указателя на объект (для возможности обращения к его свойствам и методам), а не значение самого указателя.

Поэтому ТС прав - если он не обращается к общим свойствам Sender as Component типа Name или Tag, а сразу делает проверку на принадлежность Sender определенному экземпляру кнопки Button1 и т.п., то его вариант #6 с прямыми проверками if Sender = Button1 и т.п. является наиболее простым, быстрым и "самодостаточным" (в том смысле, что никакие доп. проверки по is\as тут не нужны).
Сообщение отредактировано: leo -
Можно также не привлекать Tag (за его актуальностью еще следить надо), а создать массив кнопок, выполнять поиск Sender в нём и по индексу уже запускать действие. Минус в том, что нет очевидного соответствия между кнопкой и индексом.
ExpandedWrap disabled
    Buttons = TArray<TButton>.Create(Button1, Button2, ...);
    case IndexOf(Buttons, Sender) of
    ...


Возможно, код со сравнением Sender с Button1/2/3... окажется нагляднее всего. Во избежание сложной структуры кода в обработчике (если действия для каждой кнопки больше пары строк) можно убрать конструкции else:
ExpandedWrap disabled
    if Sender = Button1 then
    begin
      ...
      Exit;
    end;
     
    if Sender = Button2 then
    begin
      ...
      Exit;
    end;
Сообщение отредактировано: Fr0sT -
Codero ergo sum
// Программирую — значит, существую
Ещё проще:
1 Сделать ActionManager с акшинами равными количеству кнопок.
2 Назвать каждый акшон так-же как и кнопку+1 любой символ(например AButton1)
3 Все кнопки зациклить на 1 кнопку.
4 вызывать
ExpandedWrap disabled
      (FindComponent('A'+ (sender as TButton).Name) as TAction).Execute;
"Воля - это то, что заставляет тебя побеждать, когда твой рассудок говорит тебе, что ты повержен" Карлос Кастанеда
Спасибо всем.
Дело в том что я кое-что переделываю в сотнях строк уже написанного кода. У меня уже есть обработчики десятка кнопок. Я разместил на форме еще одну кнопку с visible := false, в её обработчике разместил код
ExpandedWrap disabled
    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;

Так "не взлетит" ? Вроде бы пока всё работает...
Сообщение отредактировано: Dmitry_Z -
1. Невидимая кнопка зачем? Обработчик - это просто метод формы
2. Если есть уже нужные обработчики - зачем этот огород?

Вообще конечно взлетит, но смысла в этом немного
Codero ergo sum
// Программирую — значит, существую
Цитата 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)?
"Воля - это то, что заставляет тебя побеждать, когда твой рассудок говорит тебе, что ты повержен" Карлос Кастанеда
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:


Рейтинг@Mail.ru
[ Script Execution time: 0,1601 ]   [ 21 queries used ]   [ Generated: 26.07.17, 12:36 GMT ]