Конференция "Компоненты" » Обработчик на изменение свойства tag
 
  • ship © (30.10.07 17:59) [0]
    Нужно расширить список событий компоненту TButton например, добавив событие OnTagChange, для отлавливания изменений свойства Tag.

    В модуле компонента делаю так:
     private
     FOnTagChange: TNotifyEvent;
     ..
     published
     property OnTagChange: TNotifyEvent read FOnTagChange write FOnTagChange;

    Хочу отлавливать изменения через WndProc, но при инициации изменений свойства Tag вход в WndProc не происходит.
    Подскажите как тогда отлавливать изменение?
  • Reindeer Moss Eater © (30.10.07 18:09) [1]
    ... write SetTagValueProc;
  • Reindeer Moss Eater © (30.10.07 18:17) [2]
    но при инициации изменений свойства Tag вход в WndProc не происходит.

    Не должно и не происходит. Странно да?
  • Reindeer Moss Eater © (30.10.07 18:47) [3]
    У свойства по записи должна быть процедура меняющая значение вместо простого write FOnTagChange;
    Внутри процедуры смотрим, что новое значение отличается от текущего, проверяем, что назначен обработчик, вызваем обработчик.
    Ну и конечно не забываем измсенить само значение тэга на новое.
    Все как учили в автошколе.
  • Юрий Зотов © (30.10.07 19:54) [4]
    > при инициации изменений свойства Tag вход в WndProc не происходит

    А кто сказал, что должен происходить? Никто. И не должен.

    Свойство Tag появляется у класса TComponent. А у этого класса никаких WndProc нет. И куда же тогда входить? Некуда.

    Посмотрите объявление свойства TComponent.Tag. Если там стоит write SetTag и метод SetTag - виртуальный или динамический, то отловить изменение Tag можно, перекрыв этот метод.

    Если же метода SetTag нет, либо он статический, то никак Вы это изменение не отловите. И, соответственно, никакого события не возбудите.

    Да и стоит ли переопределять документированное поведение свойства Tag? Не лучше ли ввести свое, новое свойство? Тогда и проблем никаких, и документации ничто противоречить не будет.
  • ship © (31.10.07 12:15) [5]
    Спасибо за пояснение.
    В итоге вместо tag создал свое свойство сам, на него завязал обрабочтик изменения, такой вариант тоже устроил.

    type
     TRxSpeedButtonEx = class(TRxSpeedButton)
     private
       FParamsID: integer;
       FOnSetParamsID: TNotifyEvent;
     protected
       procedure SetParamsID(ID: Integer);
     published
       property ParamsID: Integer read FParamsID write SetParamsID default 0;
       property OnParamsIDChange: TNotifyEvent read FOnSetParamsID write FOnSetParamsID;

    procedure TRxSpeedButtonEx.SetParamsID(ID: Integer);
    begin
       FParamsID:=ID;
       if assigned(FOnSetParamsID) then FOnSetParamsID(self);
    end;
  • Reindeer Moss Eater © (31.10.07 12:28) [6]
    а где проверка на то, что новое значение отличается от старого?
  • Юрий Зотов © (31.10.07 21:41) [7]
    Вот "классический" вариант:

    type
     TRxSpeedButtonEx = class(TRxSpeedButton)
     private
       FParamsID: integer;
       FOnParamsIDChange: TNotifyEvent;
       procedure SetParamsID(const Value: Integer);
     protected
       procedure DoParamsIDChange; dynamic;
     published
       property ParamsID: Integer read FParamsID write SetParamsID default 0;
       property OnParamsIDChange: TNotifyEvent read FOnParamsIDChange write FOnParamsIDChange;
     end;

    procedure TRxSpeedButtonEx.SetParamsID(const Value: Integer);
    begin
     if FParamsID <> Value
     begin
       FParamsID := Value;
       DoParamsIDChange
     end
    end;

    procedure TRxSpeedButtonEx.DoParamsIDChange;
    begin
     if Assigned(FParamsIDChange) then
       FParamsIDChange(Self)
    end;


    Основное отличие в том, что потомок (возможность появления которого всегда надо предполагать), перекрыв метод DoParamsIDChange (так называемый метод диспетчеризации события), может включить свой код в цепочку обработки события без риска нарушить работу компонента.
  • Kolan © (02.11.07 17:37) [8]
    > procedure DoParamsIDChange; dynamic;

    Почему не virtual? Чем вы руководствовались?
  • Юрий Зотов © (02.11.07 17:48) [9]
    > Kolan ©   (02.11.07 17:37) [8]

    Если предполагается, что метод в потомках будет замещаться часто, то выгоднее virtual, если редко - то dynamic.
  • Kolan © (02.11.07 17:59) [10]
    > Юрий Зотов ©   (02.11.07 17:48)

    Буду знать, а то отличие вроде знаю, а когда конкретно что использовать поянть не мог…
  • DimaBr © (05.11.07 08:43) [11]
    Можно "перекрыть" свойство Tag написав такое же одноимённое

    TButton = class(StdCtrls.TButton)
     private
       fOnTagGhange: TNotifyEvent;
       function GetTag: integer;
       procedure SetTag(const Value: integer);
     published
        property Tag: integer read GetTag write SetTag;
        property OnTagGhange: TNotifyEvent read fOnTagGhange write fOnTagGhange;
    end;

     TForm1 = class(TForm)
       Button1: TButton;
       procedure Button1Click(Sender: TObject);
       procedure FormCreate(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
       procedure DoTagGhange(Sender: TObject);
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    function TButton.GetTag:integer;
    begin
     Result := inherited Tag;
    end;

    procedure TButton.SetTag(const Value: integer);
    begin
     inherited Tag := Value;
     if Assigned(OnTagGhange) then OnTagGhange(self);
    end;

    //  проверка
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     Button1.OnTagGhange := DoTagGhange;
    end;
    procedure TForm1.Button1Click(Sender: TObject);
    begin
     Button1.Tag := Button1.Tag + 1;
    end;

    procedure TForm1.DoTagGhange(Sender: TObject);
    begin
     ShowMessage('DoTagGhange');
    end;

  • Юрий Зотов © (05.11.07 11:53) [12]
    > DimaBr ©   (05.11.07 08:43) [11]

    А как насчет вот такой проверки:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
     with TComponent(Sender) do
       Tag := Tag + 1
    end;
  • Юрий Зотов © (05.11.07 11:58) [13]
    И еще: уносим новую кнопку в юнит MyButton. А в модуле с Form1 перечисляем юниты сначала в таком порядке:
    uses ..., MyButton, ..., StdCtrls, ...;


    а потом в таком:
    uses ..., StdCtrls, ..., MyButton, ...;


    и сравниваем результаты.
  • DimaBr © (05.11.07 12:21) [14]
    На счёт [12] абсолютно согласен, посему и написал "перекрыть"
    На счёт [13] - естественно пишем новый компонент, регистрируем и пользуемся, это так для примера. Само собой что прирегатива за последним юнитом, самые частые грабли - TBitMap.
  • Юрий Зотов © (05.11.07 12:28) [15]
    > DimaBr ©   (05.11.07 12:21) [14]

    Дим, это я к тому, что форум читают люди всякие, и среди них немало тех, кто в разработке компонентов искушен еще слабовато (но научиться хочет), а потому советы и пример людей в синих штанах воспринимает буквально. Так что это... немного осторожности не помешает...
    :о)
  • DimaBr © (05.11.07 12:30) [16]
    Хорошо, извиняюсь, вот так работает :)))

    with TButton(Sender) do
      Tag := Tag + 1

  • Юрий Зотов © (05.11.07 12:44) [17]
    > DimaBr ©   (05.11.07 12:30) [16]

    До тех пор, пока новая кнопка в одном модуле с формой. А если в разных, то или работате, или не работает. Зависит от порядка перечисления модулей в uses. И если возникнет ошибка (а она в таком случае ОЧЕНЬ вероятна), то вылавливать ее будет непросто.

    В общем, согласись, что код ненадежный, потому что его поведение неоднозначно и зависит от внешних факторов.
  • DimaBr © (05.11.07 12:56) [18]
    Если учесть вопрос автора
    Нужно расширить список событий компоненту TButton например, добавив событие OnTagChange, для отлавливания изменений свойства Tag.


    то думаю подразумевался новый компонент - наследник TButton с введением нового события.
  • Юрий Зотов © (05.11.07 13:45) [19]
    > DimaBr ©   (05.11.07 12:56) [18]

    Что, собственно, и было сделано.
 
Конференция "Компоненты" » Обработчик на изменение свойства tag
Есть новые Нет новых   [119110   +107][b:0][p:0.002]