Конференция "Компоненты" » Перекрытие SetColor
 
  • TStas © (01.04.08 19:19) [0]
    Почти что написал компонент - наследник TCustomGroupBox. Это GroupBox, а на нем Edit и кнопочка с точечками. На кнопочку нажимаю - вылазит окошко диалога пути к папке и можно редактировать. Естественно, что при изменении цвета должен меняться цвет и у Edit'а. Написал procedure procedure SetColor(const Value: TColor); override; Дальфи грязно ругаются: "Процедура не найдена в базовом классе". Но вот procedure TControl.SetColor(Value: TColor);
    Никак не пойму, как это процедура не найдена и как с этим бороться?
  • Игорь Шевченко © (01.04.08 19:51) [1]

    > procedure SetColor(const Value: TColor); override


    override можно только то, что virtual;

    Тебе проще написать свойство Color у своего компонента и внутри его вызвать Edit.Color := Value;
  • TStas © (01.04.08 21:51) [2]
    Игорь, так ведь я пробовал и без override, а там вызывал Inherited. Тоже не получалось. И о свойстве Color я, конечно, думал. Но только что в нем написать?
    SetColor(const Value: TColor);
    begin
     FEdit.Color := Value; //Это понятно
     //А дальше что? Если я напишу Color := Value просто стек переполню и всё.
    end;
    Просто как-то не хочется заставлять перерисовываться GroupBox, который и без меня отлично рисуется.
    Ещё раз: компонент - это GroupBox с Edit'ом и кнопочкой и ну, конечно, функциональностью.
    Понимаю, можно свойство как-то иначе обозвать и всё. Но дурацкие названия противоречат же всему просто.
  • Игорь Шевченко © (01.04.08 22:44) [3]

    > Игорь, так ведь я пробовал и без override, а там вызывал
    > Inherited. Тоже не получалось. И о свойстве Color я, конечно,
    >  думал. Но только что в нем написать?
    > SetColor(const Value: TColor);


    inherited Color := Value ?
  • TStas © (01.04.08 23:00) [4]
    Какой Вы умный, Игорь. Ну да, а метод чтения
    function TStFolderDialog.GetColor: TColor;
    begin
     Result := Inherited Color;
    end;

    :)
  • DimaBr © (02.04.08 08:49) [5]
    Перехватите CM_ColorChanged
  • capkoh © (02.04.08 13:09) [6]
    > inherited Color := Value ?
    > Какой Вы умный (...)

    Попробовали хотя бы?
    Неужели не работает?

    type
     TMyLabel = class (TLabel)
       private
         procedure SetColor(AValue : TColor);
       
       published
         property Color write SetColor;
     end;
     

    procedure TMyLabel.SetColor(AValue : TColor);
    begin
     inherited Color := AValue;
     // fEdit.Color := AValue;
    end;

  • DimaBr © (02.04.08 13:47) [7]
    Пробывал, не работает !!!
    var L: TMyLabel;
    begin
     L := TMyLabel.Create(nil);
     TLabel(L).Color := clRed;
     L.Parent := Form1;
    end;

  • Семеныч (02.04.08 14:04) [8]
    > capkoh ©   (02.04.08 13:09) [6]

    Что будет, если на форме лежит компонент TMyLabel, а его пользователь (то есть, прикладной программист) напишет, например, такой код:

    if Components[i] is TLabel then
     TLabel(Components[i]).Color := clRed;

    Чей метод SetColor будет вызван?

    =================

    Попытка перекрыть свойство или статический метод - это довольно распространенная ошибка. Их нельзя перекрыть, их можно только закрыть - но в этом случае поведение компонента не будет однозначным, а будет зависеть от того, к какому типу приведена ссылка на него (или с каким типом она объявлена). Что, конечно же, недопустимо.
  • Семеныч (02.04.08 14:05) [9]
    > TStas

    Правильное решение - в [5].
  • DimaBr © (02.04.08 15:25) [10]

    > Семеныч   (02.04.08 14:05) [9]
    > Правильное решение - в [5].

    :)))
  • capkoh © (02.04.08 16:41) [11]
    > [8] Семеныч   (02.04.08 14:04)

    Понял свою ошибку.
  • TStas © (02.04.08 22:33) [12]
    Да всё работает чудестно. Я и написал, что Шевченко умный. Такое простое решение придумал, но, главное, я не знал, что можно так делать. За это я спасибу ему написал.
  • Семеныч (03.04.08 18:32) [13]
    > TStas ©   (02.04.08 22:33) [12]

    Чудесно, говорите? А Вы напишите вот что:

    type
     THackGroupBox = class(TCustomGroupBox);
    ...
    THackGroupBox(YourComponent).Color := clRed;


    И посмотрите, сработает ли Ваш метод SetColor.
  • capkoh © (03.04.08 18:58) [14]
    Вы, наверное, ошиблись.
    Чтобы доказать, что метод не работает, нужно написать:

    type
     THackGroupBox = class(TGroupBox);
    ...
    TGroupBox(YourComponent).Color := clRed;


    У TCustomGroupBox свойство Color недоступно, потому TGroupBox пишу.

    Или [7].
  • Семеныч (03.04.08 19:53) [15]
    > capkoh ©   (03.04.08 18:58) [14]

    > Вы, наверное, ошиблись.

    "Эт вряд ли".  © тов. Сухов.
    :о)

    > У TCustomGroupBox свойство Color недоступно

    Объявление THackGroupBox и приведение класса к THackGroupBox дает доступ к секции protected.

    > потому TGroupBox пишу

    И будет ошибка. В сабже сказано, что компонент наследуется от TCustomGroupBox, поэтому потомком TGroupBox  он НЕ является и приводить его к этому классу нельзя.
  • capkoh © (03.04.08 20:44) [16]
    Вот так вы говорите сделать:

    type
     THackGroupBox = class (TCustomGroupBox)
       private
         procedure SetColor(AValue : TColor);

       published
         property Color write SetColor;
     end;

    var
     G : THackGroupBox;

    procedure THackGroupBox.SetColor(AValue : TColor);
    begin
     G.Caption := 'THackGroupBox';
     inherited Color := AValue;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
     G := THackGroupBox.Create(Self);
     G.Caption := 'TGroupBox';

     THackGroupBox(G).Color := clRed; // Вы на этом настаиваете в [15]
     G.Parent := Self;
    end;


    ?

    Но тогда я не понимаю, чем вызов

     THackGroupBox(G).Color := clRed;


    будет отличатся от

     G.Color := clRed;


    если

     G : THackGroupBox;


    ?

    При выполнении кода выше, вызывается THackGroupBox.SetColor(), а не TCustomGroupBox.SetColor(), как, видимо, вы полагаете. Тем не менее, вашей целью, как я понимаю, является доказательство того, что потенциально появляется неоднозначность, как описано в [8]. Мне это непонятно. Или я совсем ничего не понимаю? (такое тоже может быть)

    > У TCustomGroupBox свойство Color недоступно, потому TGroupBox
    > пишу.

    Приводя YourComponent так в [14]

    TCustomGroupBox(YourComponent).Color := clRed;


    получим ошибку компиляции

    [Error]: Undeclared identifier 'Color'


    при этом в [14]

    THackGroupBox = class(TGroupBox);


    так что ошибки наследования не будет, и приведение к TGroupBox оправдано.

    Получается, что наследоваться от TCustom* и применять метод [3], [6] для свойств вполне можно, если они невидимы в базовом классе. Это верно?
  • Семеныч (04.04.08 04:56) [17]
    > capkoh ©   (03.04.08 20:44) [16]

    > Вот так вы говорите сделать.

    Нет, не так. Код в [13] - полный, ничего больше не нужно. Только объявить Hack-класс (без всякой реализации) и привести компонент к нему.

    > При выполнении кода выше, вызывается THackGroupBox.SetColor(), а не
    > TCustomGroupBox.SetColor()

    Эх... писали-писали, читали-читали... и все с начала...

    С каким типом объявлена переменная G, тот метод и вызывается. Объявите
    var G: TCustomGroupBox;


    и результат будет другим. О чем и речь.

    > ошибки наследования не будет

    Есть сабжевый компонент:

    unit YourComponentUnit;
    type
     TYourComponent = class(TCustomGroupBox)
       ...
     end;


    И есть объявление Hack-класса (только объявление, больше ничего).

    unit Unit1;
    type
     TTHackGroupBox = class(TCustomGroupBox);


    1. В Unit1 свойство TCustomGroupBox.Color недоступно, а свойство THackGroupBox.Color - доступно.

    2. Класс TYourComponent является классом TCustomGroupBox, но НЕ является классом TGroupBox. Приводить его к TGroupBox нельзя, потому что класс TGroupBox от класса TCustomGroupBox (предка компонента) отличается.

    3. Хотя класс TYourComponent классом THackGroupBox тоже не является, приводить его к классу THackGroupBox можно - потому что класс THackGroupBox от класса TCustomGroupBox (предка компонента) по сути НЕ отличается.

    > Получается, что наследоваться от TCustom* и применять метод [3], [6]
    > для свойств вполне можно, если они невидимы в базовом классе

    Нельзя. Но если хочется ловить неожиданные баги в неожиданных местах - то можно.
  • DimaBr © (04.04.08 10:15) [18]
    Повторяю ещё раз !!!
    Перекрыть метод изменения цвета нельзя, потому что но не виртуальный. Следовательно, создание одноимённого свойства не приводит к тому что родители компонента будут к нему обращаться.
    Обращение типа
    TLabel(MyLabel).Color


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

    Правильное решение перехватить событие
    CM_ColorChanged

    и обработать в нём свои изменения.
  • capkoh © (04.04.08 11:11) [19]
    > Нет, не так. Код в [13] - полный, ничего больше не нужно.

    Теперь понял, надеюсь, окончательно.
    Я не знал, что можно подобраться к SetColor() в TCustom*.

    > при этом новый метод записи попросту игнорируется

    Это я понял ещё в [11].

    Семеныч, DimaBr, спасибо за разъяснения (хотя я и не топикстартер :).
 
Конференция "Компоненты" » Перекрытие SetColor
Есть новые Нет новых   [134464   +62][b:0][p:0.002]