На главную
ПРАВИЛА 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]  все  ( Перейти к последнему сообщению )  
> Обработчик нажатия нескольких кнопок, Собрать обработку нажатия нескольких кнопок в одну функцию
    Цитата Fr0sT @
    Невидимая кнопка зачем? Обработчик - это просто метод формы

    Видимо Dmitry_Z не в курсе, что метод формы можно создать самому, ручками - вот и использовал клик на кнопке для автосоздания заготовки метода.
    Теперь осталось только удалить эту кнопку за ненадобностью :)

    Цитата ^D^ima @
    а есть аналог findcomponent только для процедуры?
    Типа Button+'10'+Click(Sender)

    Для published методов есть class function TObject.MethodAddress(MethodName):Pointer.
    Правда придется немного пошаманить с приведением TNotifyEvent к записи TMethod
    ExpandedWrap disabled
      //метод формы
      var
        p:pointer;
        m:TNotifyEvent;
      begin
        ...
        p:=MethodAddress(...); //адрес метода
        if p <> nil then
        begin
          TMethod(m).code:=p;
          TMethod(m).data:=Self;
          m(Sender); //вызов метода
        end;

    Единственный вопрос - что это дает? Или цитируя Fr0sT
    Цитата Fr0sT @
    зачем этот огород?
    Вообще конечно взлетит, но смысла в этом немного

    :yes:
      Цитата leo @
      зачем этот огород?

      Чтобы в 1 строку записать для 100 кнопок код, который бы вызывал Button+'номер кнопки'+Click(Sender)
      "Воля - это то, что заставляет тебя побеждать, когда твой рассудок говорит тебе, что ты повержен" Карлос Кастанеда
        Вот вам ещё вариант.
        Чтобы не заморачиваться с if/case и т.п. Так даже проще менять кол-во кнопок/процедур.
        (у каждой кнопки прописан номер процедуры в Tag)
        ExpandedWrap disabled
          unit Main;
           
          interface
           
          uses
            Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
            Dialogs, StdCtrls;
           
          type
            TForm1 = class(TForm)
              Button1: TButton;
              Button2: TButton;
              Button3: TButton;
              Button4: TButton;
              Button5: TButton;
              procedure Button1Click(Sender: TObject);
            private
              { Private declarations }
            public
              { Public declarations }
            end;
           
          var
            Form1: TForm1;
           
          implementation
           
          {$R *.dfm}
           
          procedure Click1;
          begin
            ShowMessage('One')
          end;
           
          procedure Click2;
          begin
            ShowMessage('Two')
          end;
           
          procedure Click3;
          begin
            ShowMessage('Three')
          end;
           
          procedure Click4;
          begin
            ShowMessage('Four')
          end;
           
          procedure Click5;
          begin
            ShowMessage('Five')
          end;
           
          const
            ProcAddr: array [1..5] of TProcedure = (Click1, Click2, Click3, Click4, Click5);
           
          procedure TForm1.Button1Click(Sender: TObject);
          var N: Integer;
          begin
            N := (Sender as TButton).Tag;
            if N in [Low(ProcAddr)..High(ProcAddr)] then ProcAddr[N]
          end;
           
          end.

        p.s. Делать проверку через is не вижу смысла, т.к. процедура сделана специально под TButton.OnClick.
        Можно было бы даже вместо (Sender as TButton) написать просто TButton(Sender), ну да ладно...

        Прикреплённый файлПрикреплённый файлClick.zip (3,19 Кбайт, скачиваний: 4)
        Tell me would you kill to save a life?
        Tell me would you kill to prove you're right?
        Crash, crash, burn, let it all burn
        This hurricane's chasing us all underground...
          Цитата ^D^ima @
          Чтобы в 1 строку записать для 100 кнопок код, который бы вызывал Button+'номер кнопки'+Click(Sender)

          Я по-прежнему не понимаю, накой? Если уже есть эти 100 обработчиков - что мешает использовать их? Добавить первой строкой if not Condition then Exit и всё.
          А если уж так хочется краткости - можно вклиниться в обработчик.
          ExpandedWrap disabled
            for Button in TArray<TButton>.Create(Button1, Button2, ...) do
            begin
              Button.Tag := NativeUInt(Button.OnClick);
              Button.OnClick := ButtonPreHandler;
            end;
             
            procedure TForm1.ButtonPreHandler(Sender);
            begin
              if Condition then
                TNotifyEvent(TButton(Sender).Tag)(Sender);
            end;


          Добавлено
          Также можно сохранять обработчики в Dictionary<TButton, TNotifyEvent>, если не хочется применять Tag
          Codero ergo sum
          // Программирую — значит, существую
            Цитата Fr0sT @
            TNotifyEvent(TButton(Sender).Tag)(Sender);

            Тут Invalid typecast, т.к. TNotifyEvent - это не один указатель, а два (см.TMethod). Поэтому тут нужны такие же извращения с приведением типа TNotifyEvent к TMethod, как в #16 (или же с приведением типа указателя к type TNotifyEventProc = procedure(Self,Sender:TObject) )

            Но если заниматься подобными хаками, то можно использовать и другие варианты. Например,
            1) Объявить тип TMyButton c переопределенным методом Click (типа if Condition then inherited;) и в FormCreate заменить классы нужных кнопок (PClass(Button)^ = TMyButton, где type PClass = ^TClass);
            2) Задействовать неиспользуемое в TButton события, например OnDblClick - объявить тип TButtonHook (= class(TButton) end) для доступа к protected свойствам, а затем по твоей схеме сохранить OnClick в TButtonHook(Button).OnDblClick и затем в обработчике вызвать TButtonHook(Sender).OnDblClick(Sender).

            =======================
            Однако, думается, что сама постановка задачи и все предлагаемые варианты ее решения - это извращение в стиле саги об X,Y,Z. По хорошему, если условия для запуска процедуры по кнопке не выполнены, то сама кнопка должны быть не активна (Enabled = false). Поэтому для создания нормального юзер-интерфейса нужно не полениться и обеспечить блокировку\разблокировку всех кнопок при выполнении заданного условия по некоторым другим событиям.

            PS: Вообще, не понятно почему 10-20 кнопок реализуются на обычных TButton (какого они должны быть размера или как нужно зашифровать\сократить их надписи, чтобы это выглядело нормально)? Может лучше использовать меню или панель инструментов?
            Сообщение отредактировано: leo -
              Цитата leo @
              1) Объявить тип TMyButton c переопределенным методом Click (типа if Condition then inherited;) и в FormCreate заменить классы нужных кнопок (PClass(Button)^ = TMyButton, где type PClass = ^TClass);

              Можно также привлечь "шаманский метод Geo" (TButton = class(Buttons.TButton)), чтобы не переопределять класс.

              Цитата leo @
              Однако, думается, что сама постановка задачи и все предлагаемые варианты ее решения - это извращение в стиле саги об X,Y,Z.

              :yes:
              Codero ergo sum
              // Программирую — значит, существую
                Цитата leo @
                Вообще, не понятно почему 10-20 кнопок реализуются на обычных TButton (какого они должны быть размера или как нужно зашифровать\сократить их надписи, чтобы это выглядело нормально)? Может лучше использовать меню или панель инструментов?

                Может это игра в крестики нолики.
                Цель - ничто , процесс - все.
                  Цитата Bas @
                  Может это игра в крестики нолики.

                  Едва ли, там у каждой кнопки свой обработчик
                  Codero ergo sum
                  // Программирую — значит, существую
                    "Обработчик - это просто метод формы" - и этот метод вызывается по определенному СОБЫТИЮ. Какое событие придумать для селектора из 10 кнопок ? С удовольствиеем выслушаю...
                    "Если есть уже нужные обработчики - зачем этот огород?" - просто так нагляднее и не запутаешься. В принципе можно было и в Button1Click сделать селектор, но в этом обработчике начинаются всякие разные обращения к USB портам и так далее... Зачем усложнять отладку и вылавливание возможных в процессе эксплуатации ошибок ? Любое ветвление - уже само по себе потенциальный источник ошибок, если не предусмотрены все случаи , включая деление на ноль :-)

                    Добавлено
                    "Вообще, не понятно почему 10-20 кнопок реализуются на обычных TButton"
                    На форме 5-7 панелей, одна наложена на другую, на каждой панели по 1-2 TButton, панели в определенный момент делаются visible. В результате форма не перегружается контролами, в видимой области в данный момент времени есть только то что нужно для работы. Что не так ?
                    Да, редактирование формы в процессе отладки - еще тот процесс (растаскивание панелей по углам экрана), но что делать, кому сейчас легко :-)
                    Вообще-то этот метод придумал не я, а один производитель некоего оборудования в одной японской лаборатории. Я просто подсмотрел, что форма остается статичной, меняются лишь панели с контролами. И сделал так же. Наверное получилось не хуже чем у японцев...
                    Сообщение отредактировано: Dmitry_Z -
                      Dmitry_Z, если ты хочешь назначить один обработчик на N контролов + выполнять код по какому-то условию, то "ветвлений" ты никак не избежишь в любом случае.
                      Код у тебя в итоге всё равно сведётся к условным переходам (jXX + call). Не заморачивайся на этом.

                      Посмотри ещё раз посты #4 и #9 - проверка по "is" (защищённый код - "safe code" в оригинале) избавит тебя от ошибок в дальнейшем - например, если ты назначишь тот же обработчик контролам другого типа (скажем, TMenuItem'ам, дублирующим функциональность TButton'ов), или ты вообще не юзаешь VCL в каких-то частях своего кода, etc.
                      Кто рано встает, тому целый день спать хочется
                        Цитата Dmitry_Z @
                        На форме 5-7 панелей, одна наложена на другую... Что не так ?
                        Да, редактирование формы в процессе отладки - еще тот процесс (растаскивание панелей по углам экрана), но что делать

                        Использовать TPageControl без ярлычков (у каждой вкладки установить TabVisible = false). При этом видимость вкладок можно переключать по ActivePage как в рантайме, так и при дизайне\отладке формы.

                        Цитата Dmitry_Z @
                        Какое событие придумать для селектора из 10 кнопок ? ...
                        ... на каждой панели по 1-2 TButton, панели в определенный момент делаются visible

                        По какому "событию" они делаются visible? Вот когда ты делаешь панель видимой, тогда и можно проверять условие доступности нажатия кнопок и устанавливать им Enabled:=true или false. (Причем делать это достаточно не для всех кнопок, а только для 1-2, которые расположены на данной панели, т.к. остальные по любому не видимы и соотв-но недоступны)

                        Цитата Dmitry_Z @
                        В принципе можно было и в Button1Click сделать селектор, но в этом обработчике начинаются всякие разные обращения к USB портам и так далее... Зачем усложнять отладку и вылавливание возможных в процессе эксплуатации ошибок ?

                        А в чем ты видишь усложнение? Тебе уже не раз говорили, что твой "селектор" нужно вынести в отдельный метод и вызывать его до начала "всяких разных обращений"
                        ExpandedWrap disabled
                          type
                             TForm1 = class(TForm)
                               ...
                             public
                               function MySelector:boolean;
                               ...
                             end;
                           
                          function TForm1.MySelector:boolean;
                          begin
                            ... //проверка условий с установкой Result:=true или false;
                            ... //+ возможен вывод сообщения через ShowMessage, чтобы юзер не ломал голову, почему кнопка не срабатывает
                          end;
                           
                          procedure TForm1.Button1Click(Sender:TObect);
                          begin
                            if not MySelector then
                              Exit;
                            ... //всякие разные обращения к USB портам и так далее
                          end;

                        Никакого усложнения отладки тут нет, т.к. ошибка может возникнуть либо в общей функции MySelector, либо в коде обработки конкретной кнопки (на строках if not и Exit никакой ошибки в принципе быть не может).

                        Цитата Dmitry_Z @
                        Любое ветвление - уже само по себе потенциальный источник ошибок, если не предусмотрены все случаи , включая деление на ноль :-)

                        Угу, а ты вместо тривиальной проверки if not MySelector then Exit, упорно хочешь создать ветвистое дерево проверок на 10 условий, рискуя нарваться на дополнительные ошибки.
                        Сообщение отредактировано: leo -
                          Селектор сделать нужно в одной процедуре или функции. Потому как после этого она объявляется exports, далее в системе защиты StarForce она маркируется как защищенная. Почему плохо делать десять защищенных функций вместо одной - слишком долго расписывать. Я не пишу универсальную функцию на все случаи жизни, мне достаточно написать одну компактную и устойчивую к возможным ошибкам. Спасибо, над какими-то моментами из начала обсуждения топика я обязательно подумаю.
                            Цитата Dmitry_Z @
                            Селектор сделать нужно в одной процедуре или функции. Потому как после этого она объявляется exports, далее в системе защиты StarForce она маркируется как защищенная.

                            И что мешает защитить саму функцию селектора? Она будет отвязана от ГУЯ и прекрасно может быть применена как в выносной DLL, так и в консоли (ежели вдруг решите писать тесты). А кнопочки должны служить только средством для запуска функций, и никакого "обращения к USB портам" в Button1Click быть не должно.

                            P.S. Старфорс - мастдай!
                            Codero ergo sum
                            // Программирую — значит, существую
                            1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script Execution time: 0,1568 ]   [ 17 queries used ]   [ Generated: 22.10.17, 15:39 GMT ]