На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Обязательно выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Этот раздел предназначен для вопросов, посвященных разработке компонентов, а также для тестирования собственных бесплатных компонентов с открытым исходным кодом.

Здесь запрещается:
1. Размещать ссылки на какие-либо коммерческие компоненты, реализующие требуемую функциональность.
2. Обсуждать и тестировать коммерческие компоненты или компоненты с закрытым кодом.
3. Давать ссылки на сайты с исходным кодом компонентов. Все тестируемые исходные коды должы быть размещены на сайте ИСХОДНИКИ.RU.
Модераторы: Rouse_, DimaBr
  
> Как создать свойство типа подсвойства Name у свойства Font класса TFont? , Как создать свойство типа подсвойства Name у свойства Font класса TFont в компоненте?
    Добрый вечер!

    В моей задаче необходимо показать в свойстве компонента список значений из массива строк. В инете нашел пример:

    ExpandedWrap disabled
      TMyClass = class(TComponent)
      private
        FStr: array of string;
      protected
        procedure SetStr(Index: Integer; Value: string);
        function GetStr(Index: Integer): string;
      public
        property Str[Index: Integer]: string read GetStr write SetStr;
        ...
      end;
       
      implementation
       
      procedure TMyClass.SetStr(Index: Integer; Value: string);
      begin
        FStr[Index] := Value;
      end;
       
      function TMyClass.GetStr(Index: Integer): string;
      begin
        result := FStr[Index];
      end;


    Но, если использовать этот код, то в при подготовке проекта в инспекторе объекта этого свойства нет.
    Мне необходимо создать свойство типа подсвойства Name у свойства Font класса TFont, в котором приведены для выбора названия шрифтов.

    Спасибо за помощь.
    Сообщение отредактировано: SkAndriy -
      1) Чтобы св-во появилось в инспекторе, его нужно объявлять в секции published (а не public)
      2) Для задания выпадающего списка значений нужно
      a) создать свой класс - наследник от DesignEditors.TStringProperty и переопределить в нем методы GetAttributes (указать наличие списка paValueList) и GetValues (заполнение списка)
      б) связать нужное св-во с созданным классом, вызвав RegisterPropertyEditor в секции initialization модуля

      Добавлено
      Похоже нужно уточнить задачу, т.к. ты путаешь св-во как массив\список значений типа TListBox.Items, и просто одну строку, значение которой можно выбирать из списка типа TFont.Name
        Посмотрите как реализовано TFontNameProperty или TFontCharsetProperty в VCLEditors
          Доброе утро всем!

          Я так и сделал:

          ExpandedWrap disabled
            unit MyComponent;
             
            TMyComponent = class(TComponent)
             
            ................................
            published
                property MyPropertyList : String read FMyPropertyList write FMyPropertyList;
                property IndexMyProperty : Integer read FIndexMyProperty write FIndexMyProperty;
            .........................
             
            unit  MyPropertyEditor;
             
            type
              TMyProperty = class (TStringProperty)
              public
                function GetAttributes: TPropertyAttributes; override;
                procedure GetValues(Proc: TGetStrProc); override;
                // procedure Edit; override;
              end;
             
            implementation
             
            procedure Register;
            begin
              RegisterComponents('test', [TMyComponent]);
              RegisterPropertyEditor (TypeInfo(string), TMyComponent, 'MyPropertyList', TMyProperty);
            end;
             
            procedure TMyProperty.GetValues(Proc: TGetStrProc);
            var
              i : Integer;
            begin
              for i := 0 to High(MyArrayOfString) do
                Proc(MyArrayOfString[i]);
            end;
             
            function TMy.GetAttributes: TPropertyAttributes;
            begin
              Result := [paValueList];
            end;


          Выпадающий список строковых значени своего массива получил, но как узнать и передать в свойство IndexMyProperty порядковый индекс выбранного в списке (массиве) элемента. Например, я выбрал в выпадающем списке элемент №3. Мне нужно занести его индекс в свойство IndexMyProperty и обработать на это свое событие. Как это можно сделать. Что необходимо добавить в редактор свойств, чтобы фиксировать выбранный номер выбранного элемента в списке. Спасибо всем.
            Цитата SkAndriy @
            но как узнать и передать в свойство IndexMyProperty порядковый индекс выбранного в списке (массиве) элемента

            Никак. Для свойств-массивов типа Str[Index: Integer]:string задание значений в инспекторе не поддерживается. Нужно вместо массива юзать список строк Str:TStrings, а чтобы прикрутить к нему выбор значений из своего списка, то нужно изменить реализацию TStringListProperty, переопредилив в нем тип диалога со стандартного TStrEditDlg на какой-то свой (см. StrEdit.pas)

            Добавлено
            :offtop:
            Похоже ты решил забить на научную работу и увязнуть в дебрях проперти-эдиторов ;)
            Сообщение отредактировано: leo -
              Я не совсем понимаю Вашу мысль. Вы предлагаете занести массив в StringList и затем в модуле компонента просто искать по строке выбранного в редакторе свойств элемента? Есть еще варианты, может есть несколько иное решение? Например, вызвать модальную форму с занесенным в нее списком массива, но как из нее получить индекс выбранного элемента? Спасибо.
                Цитата SkAndriy @
                Вы предлагаете занести массив в StringList

                Я предлагаю выкинуть массив и заменить его на TStrings - при этом обращение к св-вy Str[i] останется тем же самым.
                Редактировать непосредственно в инспекторе каждый элемент TStrings нельзя - нужно вызывать некий диалог и уже в этом диалоге делай что хочешь - можешь сразу весь список показывать (как в стандартном), можешь задать отдельное поле для индекса и отдельный комбобокс со значениями и т.д. и т.п.

                Добавлено
                PS: Как ни крути, а св-ва массивы не поддерживаются в дизайне потому, что нет способа сохранить их в dfm-файле формы и затем загрузить. А для TStrings сохраняется и загружается единый текст TStrings.Text
                  Понятно, тогда каким образом передать в совйство индекс выделенного итема. Допустим в свойство Str я передал строковую форму, а как в свойство IndexStr из диалоговой формы выбора передать индекс выделенного итема? Что нужно добавить в процедуру Edit редактора свойств. Если можно небольшой пример. Спасибо
                    Цитата SkAndriy @
                    Понятно, тогда каким образом передать в совйство индекс выделенного итема

                    Похоже, что не понятно. В случае TStrings диалог вызывается для редактирования не каждого отдельного итема, а всего списка - получаешь на входе все строки из св-ва, сохраняешь их в каком-то листбоксе или мемо диалога, затем юзер что-то там добавляет\меняет и при закрытии диалога все строки записываются обратно в список. Поэтому никаких проблем с индексами тут нет
                      Напишите редактор для свойства IndexMyProperty: integer, который и будет выпадающий список, а свойство MyPropertyList : String - лишнее
                        Теперь Вы меня не понимаете.
                        Я использовал диалог в редакторе свойств. работает отлично и в свойство компонента заносит стровый элемент из списка/массива прекрасно, но в дополнении к тому мне нужен и индекс этого элемента. Вот код в дополнение к предыдущему:

                        ExpandedWrap disabled
                          type
                            TSMyProperty = class (TStringProperty)
                            public
                              function GetAttributes: TPropertyAttributes; override;
                              // procedure GetValues(Proc: TGetStrProc); override;
                              procedure Edit; override;
                            end;
                           
                          procedure Register;
                          begin
                            RegisterComponents('test', [TMyComponent]);
                            RegisterPropertyEditor (TypeInfo(string), TMyComponent, 'MyPropertyList', TSoundProperty);
                          end;
                           
                          function TSoundProperty.GetAttributes: TPropertyAttributes;
                          begin
                            Result := [paDialog];
                          end;
                           
                          procedure TMyProperty.Edit;
                          begin
                            DialogForm := TDialogForm.Create(nil);
                            try
                              DialogForm.ComboBox1.Text := GetValue;
                              // show the dialog box
                              if DialogForm.ShowModal = mrOK then
                                SetValue(DialogForm.ComboBox1.Text);
                            finally
                              DialogForm.Free;
                            end;
                          end;


                        Как теперь используя редактор свойст передать индекс выделенного итема. Пробоовал добавить в процедуру Edit SetOrdValue(DialogForm.ComboBox1.ItemIndex) - не работает вообще. Что нужно добавить в редактор, чтобы это сработало. Спасибо.
                          Зачем вам диалог ?
                          ExpandedWrap disabled
                            type
                            TMyComponent = class(TComponent)
                              private
                                fList: TStrings;
                                fIndexList: integer;
                              public
                                constructor Create(AOwner: TComponent);override;
                                destructor Destroy;override;  
                              published
                                property IndexList: integer read fIndexList write fIndexList;
                            end;
                             
                            implementation
                             
                            type
                            TIndexListProperty = class(TPropertyEditor)
                              public
                                function GetValue: string; override;
                                procedure SetValue(const Value: string); override;
                                function GetAttributes: TPropertyAttributes; override;
                                procedure GetValues(Proc: TGetStrProc); override;
                                function MyComponent: TMyComponent;
                            end;
                             
                            procedure Register;
                            begin
                              RegisterComponents('test', [TMyComponent]);
                              RegisterPropertyEditor(TypeInfo(Integer), TMyComponent, 'IndexList', TIndexListProperty);
                            end;        
                             
                            { TMyComponent }
                             
                            constructor TMyComponent.Create(AOwner: TComponent);
                            begin
                              inherited;
                              fList := TStringList.Create;
                              fList.Add('aaa');
                              fList.Add('bbb');
                              fList.Add('ccc');
                              fList.Add('ddd');
                            end;
                             
                            destructor TMyComponent.Destroy;
                            begin
                              fList.Free;
                              inherited;
                            end;
                             
                            { TIndexListProperty }
                             
                            function TIndexListProperty.GetAttributes: TPropertyAttributes;
                            begin
                              Result := [paMultiSelect, paValueList, paRevertable];
                            end;
                             
                            function TIndexListProperty.GetValue: string;
                            begin
                              Result := MyComponent.fList[GetOrdValue];
                            end;
                             
                            procedure TIndexListProperty.GetValues(Proc: TGetStrProc);
                            var i: integer;
                            begin
                              for i := 0 to MyComponent.fList.Count-1 do
                                Proc(MyComponent.fList[i]);
                            end;
                             
                            function TIndexListProperty.MyComponent: TMyComponent;
                            begin
                              Result := GetComponent(0) as TMyComponent;
                            end;
                             
                            procedure TIndexListProperty.SetValue(const Value: string);
                            begin
                              SetOrdValue(MyComponent.fList.IndexOf(Value));
                            end;
                             
                            end.
                            Попробовал сделать так:

                            ExpandedWrap disabled
                              type
                                TIndexProperty = class (TEnumProperty)
                                public
                                  function GetAttributes: TPropertyAttributes; override;
                                  procedure GetValues(Proc: TGetStrProc); override;
                                  procedure Edit; override;
                                end;
                               
                                TMyProperty = class (TStringProperty)
                                public
                                  function GetAttributes: TPropertyAttributes; override;
                                  procedure GetValues(Proc: TGetStrProc); override;
                                  procedure Edit; override;
                                end;
                               
                              procedure Register;
                              begin
                                RegisterComponents('test', [TMyComponent]);
                                RegisterPropertyEditor(TypeInfo(Integer), TMyComponent, 'MyOptions',
                                  TMySetTypeProperty);
                                RegisterPropertyEditor (TypeInfo(string), TMyComponent, 'MyPropertyList',
                                  TMyProperty);
                                RegisterPropertyEditor(TypeInfo(Integer), TMyComponent, 'IndexDown',
                                  TIndexProperty);
                              end;
                               
                              ...............................
                               
                              procedure TIndexProperty.GetValues(Proc: TGetStrProc);
                              var
                                i : Integer;
                              begin
                                for i := 0 to High(MyArray) do
                                  Proc(MyArray[i]);
                              end;
                               
                              procedure TIndexProperty.Edit;
                              begin
                                DialogForm := TDialogForm.Create(nil);
                                try
                                  DialogForm.ComboBox1.ItemIndex := GetOrdValue;
                                  // show the dialog box
                                  if DialogForm.ShowModal = mrOK then
                                    SetOrdValue(vForm.EomboBox1.ItemIndex);
                                finally
                                  DialogForm.Free;
                                end;
                              end;
                               
                              function TIndexProperty.GetAttributes: TPropertyAttributes;
                              begin
                                // editor, sorted list, multiple selection
                                Result := [paDialog];
                              end;
                               
                              //=======================
                               
                              procedure TSoundProperty.GetValues(Proc: TGetStrProc);
                              var
                                i : Integer;
                              begin
                                for i := 0 to High(TimeZone) do
                                  Proc(TimeZone[i]);
                              end;
                               
                              procedure TSoundProperty.Edit;
                              begin
                                SoundForm := TSoundForm.Create(nil);
                                try
                                  SoundForm.ElComboBox1.Text := GetValue;
                                  // show the dialog box
                                  if SoundForm.ShowModal = mrOK then
                                    SetOrdValue(SoundForm.ElComboBox1.Text);
                                finally
                                  SoundForm.Free;
                                end;
                              end;
                               
                              function TSoundProperty.GetAttributes: TPropertyAttributes;
                              begin
                                Result := [paDialog];
                              end;

                            Каждый из редакторов работает.Но работает в отдельномссти. А как их объеденить или при вызове одного чтобы срабатывал и другой и оба поля свойств MyPropertyList и IndexDown имели одновременно значения соответствующие выделенному итему. Что добавитть к коду или как его изменить. Спасибо.
                              Я уже ва-аще ниче не понимаю :wacko: Как связаны (или должны быть) между собой MyPropertyList и IndexDown ? Объясни словами, что ты хочешь в итоге получить

                              Добавлено
                              PS: Если MyPropertyList и IndexDown однозначно связаны между собой через какой-то список значений, то 1) их соотв-е нужно задавать в процедурах установки св-ва Set.., чтобы изменение одного приводило к автоустановке другого, 2) незачем оба св-ва делать published, т.к. это просто лишняя работа, не имеющая никакого отношения к науке ;)
                              Сообщение отредактировано: leo -
                                DimaBr
                                Все заработало, только редактор свойств я перенес в отдельный модуль, не компилируется иначе.

                                редактор свойств в отдельном модуле

                                ExpandedWrap disabled
                                  type
                                    TIndexListProperty = class(TPropertyEditor)
                                    public
                                      function GetValue: string; override;
                                      procedure SetValue(const Value: string); override;
                                      function GetAttributes: TPropertyAttributes; override;
                                      procedure GetValues(Proc: TGetStrProc); override;
                                    end;
                                   
                                  .........................................................
                                   
                                  procedure Register;
                                  begin
                                    RegisterComponents('test', [TMyComponent]);
                                    RegisterPropertyEditor(TypeInfo(Integer), TMyComponent, 'IndexList', TIndexListProperty);
                                  end;
                                   
                                  function TIndexListProperty.GetAttributes: TPropertyAttributes;
                                  begin
                                    Result := [paValueList, paRevertable];
                                  end;
                                   
                                  function TIndexListProperty.GetValue: string;
                                  var
                                    Obj: TPersistent;
                                  begin
                                    Obj := GetComponent(0);
                                    if Assigned(Obj) and (Obj is TMyComponent) then
                                      with TMyComponent(Obj) do
                                    Result := fList[GetOrdValue];
                                  end;
                                   
                                  procedure TIndexListProperty.GetValues(Proc: TGetStrProc);
                                  var i: integer;
                                  Obj: TPersistent;
                                  begin
                                    Obj := GetComponent(0);
                                    if Assigned(Obj) and (Obj is TMyComponent) then
                                      with TMyComponent(Obj) do
                                    for i := 0 to fList.Count-1 do
                                      Proc(fList[i]);
                                  end;


                                все работает, но к в каждой функции или процедуре нужно писать:

                                ExpandedWrap disabled
                                  var
                                    Obj: TPersistent;
                                  begin
                                    Obj := GetComponent(0);
                                    if Assigned(Obj) and (Obj is TMyComponent) then
                                       with TMyComponent(Obj) do


                                Это можно как то один раз где-то указать или нет?

                                Спасибо
                                Сообщение отредактировано: SkAndriy -
                                  Я же написал в виде функции, чем она вас не устраивает ?

                                  ExpandedWrap disabled
                                    function TIndexListProperty.MyComponent: TMyComponent;
                                    begin
                                      Result := GetComponent(0) as TMyComponent;
                                    end;
                                    Извините, все работает. просто модуль компонента перенес в вверх. Спасибо
                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                    0 пользователей:


                                    Рейтинг@Mail.ru
                                    [ Script execution time: 0,0505 ]   [ 16 queries used ]   [ Generated: 1.05.24, 13:36 GMT ]