Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > DefineProperties и TCustomEdit


Автор: Proxin 27.2.2016, 01:12
Столкнулся со странной ошибкой. Пишу свой ТЕдит на базе ТКастомЭдит, перекрываю в протектедах ДефайнПропертиз. И вот в чём загвоздка - исполнение кода в тестовом проекте туда попросту не доходит, точнее, при загрузке приложения вообще ни для каких контролов кроме главной формы, ДефайнПропертиз не выполняется. В чём может быть загвоздка?

Автор: Proxin 27.2.2016, 22:45
Вроде разобрался, но возникла следующая проблема. При использовании WriteComponent при последующем пользовании дизайнером ( сохранении формы с моим компонентом) вылетает ошибка out of memory. Код совершенно обычный
Код

    Writer.WriteListBegin();
    if    ( FButtons.WriteButtonsCount > 0 ) then
        for i := 0 to FButtons.Count - 1 do
            if    ( ( FButtons[i].Control <> NIL ) and ( FButtons[i].SaveRestore ) ) then
                if    ( FButtons[i].Control.ClassType = TSpeedButton ) then
                begin
                    Writer.WriteInteger(Integer(FButtons[i].Align));
                    if    ( FButtons[i].Align = ngalRight ) then
                        Writer.Root                                                                                                                :=    FTBLeft
                    else
                        Writer.Root                                                                                                                :=    FTBRight;
                    Writer.WriteComponent(FButtons[i].Control);
                end;
        Writer.WriteListEnd;

Автор: Proxin 27.2.2016, 23:56
Опытным путём выяснилось, что ошибка - переполнение буфера после использования WriteComponent. Никто не сталкивался с этим?

Автор: Doga 29.2.2016, 16:03
Привет.

Когда CodeGear отказалась от справки в формате .HLP, надо сказать, ею(справкой) стало невозможно пользоваться, т.к. вместо  справки получилось полное убожество(мягко говоря).

Однако о TWriter.WriteComponent они(CodeGear) кое-что все же написали:
Цитата

Never call WriteComponent directly. WriteComponent is recursively called for each owned component in Root. 


Отсюда и переполнение буфера. Как то так... smile

Автор: Proxin 1.3.2016, 01:02
А как тогда быть, если я хочу сохранить в DFM TComponent, который не является публикуемым свойством ни одной компоненты?

Автор: Doga 1.3.2016, 13:09
Не вижу ничего сложного.

Определяете методы для чтения и сохранения свойств компонента и с помощью DefineProperty(...) назначаете их для конкретного свойства.

Например:
Код

procedure TRCustomGrid.ReadHolderColCount(Reader: TReader);
begin
  FHolder.ColCount := Reader.ReadInteger;
end;
//------------------------------------------------------------------------------------------------
procedure TRCustomGrid.WriteHolderColCount(Writer: TWriter);
begin
  Writer.WriteInteger(FHolder.ColCount);
end;
//------------------------------------------------------------------------------------------------
procedure TRCustomGrid.ReadHolderColWidths(Reader: TReader);
var
  k: Integer;
begin
  with Reader do
  begin
    ReadListBegin;
    for k := 0 to FHolder.ColCount - 1 do 
    begin
      TRCellsVector(FHolder.FCols[k]).FSize := ReadInteger;
    end;
    ReadListEnd;
  end;
end;
//------------------------------------------------------------------------------------------------
procedure TRCustomGrid.WriteHolderColWidths(Writer: TWriter);
var
  k: Integer;
begin
  with Writer do
  begin
    WriteListBegin;
    for k := 0 to FHolder.ColCount - 1 do 
    begin
      WriteInteger(FHolder.ColWidths[k]);
    end;
    WriteListEnd;
  end;
end;
//------------------------------------------------------------------------------------------------
//...
//------------------------------------------------------------------------------------------------
procedure TRCustomGrid.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);

  with Filer do
  begin
    DefineProperty('HolderColCount', ReadHolderColCount, WriteHolderColCount, True);
    DefineProperty('HolderColWidths', ReadHolderColWidths, WriteHolderColWidths, True);
    //...
  end;
end;


И в соответствующем файле DFM можно видеть следующие строки:
Код

...
HolderColCount = 5
HolderColWidths = (
              30
              50
              50
              50
              50)
...


Кста, в догонку, Writer.Root тоже нельзя вызывать:
Цитата

Do not call Root directly. It is used internally to find the root object when streaming owned components. Root represents the ultimate owner of all the components being streamed during the current streaming process.

The ReadRootComponent and WriteRootComponent methods set Root before reading or writing their components and owned components.


Вообще, как это делается, можно подсмотреть в исходниках Delphi или компонентах других разработчиков.

Автор: Proxin 1.3.2016, 14:22
Это я знаю, что можно писать ручками все нужные значения. Но неужели нет способа вызывать WriteComponent? В статье про TReader/TWriter на этом форуме WriteComponent упоминаяется, и не стоит никаких предупреждений по его использованию.

Автор: Doga 1.3.2016, 20:16
Да, хорошая статья - http://forum.vingrad.ru/forum/topic-250409/unread-1/hl/treader+twriter/index.html

Отличная наглядная иллюстрация, прекрасно объясняет как это работает. Конечно, никто не может помешать нам создать свои собственные локальные Reader, Writer и в режиме RunTime сохранять компоненты в свои собственные файлы или загружать компоненты из них.

Но для реализации возможности сохранения свойств в DFM, я считаю, необходимо соблюдать соответствующие правила. 
Все визуальные компоненты сами умеют сохранять/читать свои свойства. Надо только предоставить им такую возможность.

Хотелось бы разобраться в концепции Вашего компонента и увидеть полный код методов используемых для чтения/записи свойств.

Кста, больше чем на три кнопки в составе Edit'а, меня не хватило  smile 





  

Автор: Proxin 1.3.2016, 20:48
В общем, стандартный TReader/TWiriter - не подходит. Если хотите всамделишные кнопки - энамьте все бублики через ртти и пишите в бинарную дату, потом парсьте её в ридере, с созданием компонента по имени класса и прочим фабричным весельем. Я удивлён, как вообще они стандартный TToolBar писали. Могли бы для себя добавить нормальную работу в дизайне.
А в компоненте у меня ничего сложного - два тулбара class(TWinControl) и хук на ресайз эдита. Кнопки храню с помощью TList, сам пишу, сам читаю. Потому что коллекциями это реализовывать - грабли через грабли.

Автор: dnek 4.3.2016, 21:59
Цитата

   А как тогда быть, если я хочу сохранить в DFM TComponent, который не является публикуемым свойством ни одной компоненты?
   

А директивы stored для свойства Вам не хватает?

Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/DefineProperties-i-TCustomEdit-id56d0ce66ae20151f298b4567#findElement_E7045_56d9db2dae2015b76a8b48c8_0

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)