Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.225.255.134] |
|
Сообщ.
#1
,
|
|
|
Добрый вечер!
В моей задаче необходимо показать в свойстве компонента список значений из массива строк. В инете нашел пример: 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, в котором приведены для выбора названия шрифтов. Спасибо за помощь. |
Сообщ.
#2
,
|
|
|
1) Чтобы св-во появилось в инспекторе, его нужно объявлять в секции published (а не public)
2) Для задания выпадающего списка значений нужно a) создать свой класс - наследник от DesignEditors.TStringProperty и переопределить в нем методы GetAttributes (указать наличие списка paValueList) и GetValues (заполнение списка) б) связать нужное св-во с созданным классом, вызвав RegisterPropertyEditor в секции initialization модуля Добавлено Похоже нужно уточнить задачу, т.к. ты путаешь св-во как массив\список значений типа TListBox.Items, и просто одну строку, значение которой можно выбирать из списка типа TFont.Name |
Сообщ.
#3
,
|
|
|
Посмотрите как реализовано TFontNameProperty или TFontCharsetProperty в VCLEditors
|
Сообщ.
#4
,
|
|
|
Доброе утро всем!
Я так и сделал: 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 и обработать на это свое событие. Как это можно сделать. Что необходимо добавить в редактор свойств, чтобы фиксировать выбранный номер выбранного элемента в списке. Спасибо всем. |
Сообщ.
#5
,
|
|
|
Цитата SkAndriy @ но как узнать и передать в свойство IndexMyProperty порядковый индекс выбранного в списке (массиве) элемента Никак. Для свойств-массивов типа Str[Index: Integer]:string задание значений в инспекторе не поддерживается. Нужно вместо массива юзать список строк Str:TStrings, а чтобы прикрутить к нему выбор значений из своего списка, то нужно изменить реализацию TStringListProperty, переопредилив в нем тип диалога со стандартного TStrEditDlg на какой-то свой (см. StrEdit.pas) Добавлено Похоже ты решил забить на научную работу и увязнуть в дебрях проперти-эдиторов |
Сообщ.
#6
,
|
|
|
Я не совсем понимаю Вашу мысль. Вы предлагаете занести массив в StringList и затем в модуле компонента просто искать по строке выбранного в редакторе свойств элемента? Есть еще варианты, может есть несколько иное решение? Например, вызвать модальную форму с занесенным в нее списком массива, но как из нее получить индекс выбранного элемента? Спасибо.
|
Сообщ.
#7
,
|
|
|
Цитата SkAndriy @ Вы предлагаете занести массив в StringList Я предлагаю выкинуть массив и заменить его на TStrings - при этом обращение к св-вy Str[i] останется тем же самым. Редактировать непосредственно в инспекторе каждый элемент TStrings нельзя - нужно вызывать некий диалог и уже в этом диалоге делай что хочешь - можешь сразу весь список показывать (как в стандартном), можешь задать отдельное поле для индекса и отдельный комбобокс со значениями и т.д. и т.п. Добавлено PS: Как ни крути, а св-ва массивы не поддерживаются в дизайне потому, что нет способа сохранить их в dfm-файле формы и затем загрузить. А для TStrings сохраняется и загружается единый текст TStrings.Text |
Сообщ.
#8
,
|
|
|
Понятно, тогда каким образом передать в совйство индекс выделенного итема. Допустим в свойство Str я передал строковую форму, а как в свойство IndexStr из диалоговой формы выбора передать индекс выделенного итема? Что нужно добавить в процедуру Edit редактора свойств. Если можно небольшой пример. Спасибо
|
Сообщ.
#9
,
|
|
|
Цитата SkAndriy @ Понятно, тогда каким образом передать в совйство индекс выделенного итема Похоже, что не понятно. В случае TStrings диалог вызывается для редактирования не каждого отдельного итема, а всего списка - получаешь на входе все строки из св-ва, сохраняешь их в каком-то листбоксе или мемо диалога, затем юзер что-то там добавляет\меняет и при закрытии диалога все строки записываются обратно в список. Поэтому никаких проблем с индексами тут нет |
Сообщ.
#10
,
|
|
|
Напишите редактор для свойства IndexMyProperty: integer, который и будет выпадающий список, а свойство MyPropertyList : String - лишнее
|
Сообщ.
#11
,
|
|
|
Теперь Вы меня не понимаете.
Я использовал диалог в редакторе свойств. работает отлично и в свойство компонента заносит стровый элемент из списка/массива прекрасно, но в дополнении к тому мне нужен и индекс этого элемента. Вот код в дополнение к предыдущему: 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) - не работает вообще. Что нужно добавить в редактор, чтобы это сработало. Спасибо. |
Сообщ.
#12
,
|
|
|
Зачем вам диалог ?
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. |
Сообщ.
#13
,
|
|
|
Попробовал сделать так:
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 имели одновременно значения соответствующие выделенному итему. Что добавитть к коду или как его изменить. Спасибо. |
Сообщ.
#14
,
|
|
|
Я уже ва-аще ниче не понимаю Как связаны (или должны быть) между собой MyPropertyList и IndexDown ? Объясни словами, что ты хочешь в итоге получить
Добавлено PS: Если MyPropertyList и IndexDown однозначно связаны между собой через какой-то список значений, то 1) их соотв-е нужно задавать в процедурах установки св-ва Set.., чтобы изменение одного приводило к автоустановке другого, 2) незачем оба св-ва делать published, т.к. это просто лишняя работа, не имеющая никакого отношения к науке |
Сообщ.
#15
,
|
|
|
DimaBr
Все заработало, только редактор свойств я перенес в отдельный модуль, не компилируется иначе. редактор свойств в отдельном модуле 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; все работает, но к в каждой функции или процедуре нужно писать: var Obj: TPersistent; begin Obj := GetComponent(0); if Assigned(Obj) and (Obj is TMyComponent) then with TMyComponent(Obj) do Это можно как то один раз где-то указать или нет? Спасибо |
Сообщ.
#16
,
|
|
|
Я же написал в виде функции, чем она вас не устраивает ?
function TIndexListProperty.MyComponent: TMyComponent; begin Result := GetComponent(0) as TMyComponent; end; |
Сообщ.
#17
,
|
|
|
Извините, все работает. просто модуль компонента перенес в вверх. Спасибо
|