[ главная ]   [ рейтинг статей ]   [ справочник радиолюбителя ]   [ новости мира ИТ ]



Ответов: 0
25-02-12 07:01







   Web - программирование
PHP


ASP






XML



CSS

SSI





   Программирование под ОС











   Web - технологии








   Базы Данных









   Графика






Данные




Программирование под ОС / C - C++ /

Создание редактора свойств(property editor) в C++Builder 4

Базовые аспекты написания редакторов свойств


Редакторы свойств и редакторы компонент - вот два самых важных свойства, которые разработчик компонент может добавить в C++ Builder IDE. Изначально, они созданы чтобы предоставить вам или другому разработчику более простой, удобный и надежный путь для изменения ключевых свойств вашего компонента.

Редакторы свойств обычно проектируются так, чтобы они могли быть вызваны из object inspector, хотя они выводят диалоговые окна, которые работают независимо от него.

Редакторы свойств должны наследовать как минимум от TPropertyEditor, но они могут также наследовать и от TStringProperty или от множества разнообразных специализированных редакторов, которые описаны в Component Developer's Guide и on-line help.

Редакторы свойств должны знать и о свойстве, которое они редактируют, и о компоненте, в котором это свойство существует. Существуют специальные функции для редакторов свойств, предоставляющие доступ к значениям свойств. Они включают в себя:

  • GetOrdValue(), которая используется для получения указателя на свойство-класс.
  • GetIntValue(), которая используется для получения значения целого свойства.
  • GetStrValue(), которая используется для получения значения свойства-строки.

Чтобы получить информацию о компоненте требуется знать его класс или класс его предка. Указатель на компонент можно получить с помощью GetComponent(); потом этот указатель должен быть приведен к типу, в котором прдполагается наличие редактируемого свойства.

Пример редактора свойств


Этот редактор свойств предполагается использовать в компоненте, порожденном от TDataSet. Он должен получить имена полей из компонента и позволить пользователю выбрать одно из них, которое затем должно быть записано в свойство.

Пример класса свойства


Класс объекта-свойства объявлен следующим образом:

//---------------------------------------------------------------------------
#ifndef aStringObjectH
#define aStringObjectH

#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class aStringObject: public TPersistent
{
   public:

      __fastcall aStringObject(void){};
      __fastcall aStringObject(String theString){myString = theString;};
      __fastcall aStringObject(aStringObject &theStringObject){myString = theStringObject.AsString;};

      operator String(void){return myString;};
      aStringObject &operator = (String theString){myString = theString; return *this;};

      void __fastcall ReadData(TReader *theReader)
      {
         myString = theReader->ReadString();
      };

      void __fastcall WriteData(TWriter *theWriter)
      {
         theWriter->WriteString(myString);
      };

      void __fastcall DefineProperties(TFiler* theFiler)
      {
         bool HasData = false;

         if (theFiler->Ancestor != NULL) // This is on a descendant form
         {
            aStringObject *AncestorObject = dynamic_cast<aStringObject *>(theFiler->Ancestor);

            if (AncestorObject != NULL)
            {
               HasData = !(myString == *AncestorObject);
            }
            else
            {
               HasData = true;
            };
         }
         else
         {
            HasData = true;
         };

         theFiler->DefineProperty("String",ReadData,WriteData,HasData);
      };

      int __fastcall Length(void){return myString.Length();};
      __property String AsString = {read=myString,write=myString};

   private:

      String myString;
};

#endif

Как видите, этот класс - всего лишь обертка вокруг AnsiString, необходимая, поскольку AnsiString не потомок TObject. Но несмотря на это, все механизмы редактора свойств останутся такими же.

Класс использует потоковую систему для сохранения и загрузки не опубликованного подсвойства String. Это достигается путем переопределения ReadData, WriteData, and DefineProperties (которая заставляет потоковую систему использовать ReadData и WriteData).

Также проверки HasData и AncestorObject внутри DefineProperties позволяют определить, находится ли компонент в форме-наследнике. Если да, то следует проверка, отличается ли значение свойства в текущей форме (потомке) от значения на родительской форме, и сохранение скрытого подсвойства String происходит только тогда, когда эти значения отличаются. Это очень важно для правильной поддержки наследования форм.

Код редактора свойств


//---------------------------------------------------------------------------
#ifndef aDataSetFieldNamePropertyEditorH
#define aDataSetFieldNamePropertyEditorH

#include <SysUtils.hpp>
#include <Controls.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
#include <DB.hpp>
#include <aStringObject.h>
//---------------------------------------------------------------------------
class PACKAGE aDataSetFieldNamePropertyEditor: public TStringProperty
{
   public:

      __fastcall aDataSetFieldNamePropertyEditor(void){};
      __fastcall ~aDataSetFieldNamePropertyEditor(void){};

      TPropertyAttributes __fastcall GetAttributes(void)
      {
         return TPropertyAttributes() << paValueList;
      };

      void __fastcall GetValues(Classes::TGetStrProc AddValueToList)
      {
         TDataSet *HostComponent = dynamic_cast<TDataSet *>(GetComponent(0));

         if (HostComponent != NULL)
         {
            TStringList *FieldName = new TStringList;
            FieldName->Sorted = true;

            HostComponent->GetFieldNames(FieldName);

            for (int Index = 0; Index < FieldName->Count; Index++)
            {
               AddValueToList(FieldName->Strings[Index]);
            };

            delete FieldName;

         }
         else
         {
            AddValueToList("n/a");
         };
      };

      AnsiString __fastcall GetValue(void)
      {
         aStringObject *StringObject = dynamic_cast<aStringObject *>((TObject *) GetOrdValue());
         return StringObject != NULL ? (String) *StringObject : AnsiString("");
      };

      void __fastcall SetValue(AnsiString theValue)
      {
         aStringObject *StringObject = dynamic_cast<aStringObject *>((TObject *) GetOrdValue());
         if (StringObject != NULL) *StringObject = theValue;
         Modified();
      };
};

#endif

  • Заметьте, что хотя я и редактирую свойство-класс, я порождаю свой редактор от TStringProperty. Это возможно, и позволяет мне использовать все свойства TStringProperty.
  • GetAttributes - переопределенная функция из TPropertyEditor - в этом случае, она сообщает IDE, что мое свойство - это строка и оно породит множество значений, из которых должен выбирать пользователь.
  • GetValues - переопределенная функция из TPropertyEditor - вызывается потому, что GetAttributes сообщает IDE, что этот редактор свойств выдает несколько значений для возможного выбора. Однако ее действия немного странные. Вместо того, чтобы возвратить все значения, например, через TStringList, она вызывает передавемую от IDE в качестве аргумента функцию типа TGetStrProc для каждой строки, которая должна появиться в Object Inspector. В этом случае, редактор извлекает data source из компонента(GetComponent(0) -функция в TPropertyEditor, которая возвращает указатель на TComponent - это тот компонент, который сейчас виден в Object Inspector), потом список имен полей из набора данных этого источника, и наконец, организует цикл по этому списку, вызывая для каждого члена функцию IDE.
  • GetValue переопределенная функция из TPropertyEditor, которая возвращает строковое значение для свойства - в даном случае имя поля из свойства aStringObject. Обратите внимание на приведение к нужному типу значения, возвращаемого GetOrdValue(), которое является указателем на свойство. Это делается для того, чтобы обеспечить доступ к свойству способом, соответствующим типу свойства. Обратите также внимание, что возвращается пустая строка, если приведение было неудачным.
  • SetValue переопределенная функция из TPropertyEditor, которая устанавливает значение свойства на основании выбранной пользователем строки. Заметьте, что она использует то же приведение, что и предыдущая, и если оно неудачно, ничего не делает. Также заметьте, что она вызывает Modified() - функцию TPropertyEditor, которая извещает IDE, что свойство было изменено, а соответственно, был изменен компонент, и модуль(а может быть, и проект) должен быть сохранен. Другой (возможно лучший) подход к этой проблеме заключается в том, чтобы сравнить входное значение с уже существующим, и только в том случае, если они различаются, вызвать Modified().

Использование редактора свойств


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

namespace Agridwiththeeditor
{
   void __fastcall PACKAGE Register()
   {
      TComponentClass classes[1] = {__classid(aGridWithTheEditor)};

        RegisterPropertyEditor
      (
         __typeinfo(PVStringObject),
         __classid(aGridWithTheEditor),
         "IDFieldName",
         __classid(PVDBGridFieldNamePropertyEditor)
      );
        RegisterPropertyEditor
      (
         __typeinfo(PVStringObject),
         __classid(aGridWithTheEditor),
         "SequenceFieldName",
         __classid(PVDBGridFieldNamePropertyEditor)
      );

      RegisterComponents("Test Page", classes, 0);
   }
}

Отладка редактора свойств


Это тяжелая часть проекта. Теоритически, вы можете запустить вторую копию среды и установить точку останова в вашем редакторе, но практически это не всегда возможно.

Однако, вы можете выдавать Application->MessageBox из любой точки вашего редактора или задублировать свойство, выдающее строку из вашего.

Но что самое важное - надо сначала все продумать и писать с величайшей осторожностью, отлавливая все исключения с выдачей сообщений.

Куда все это поместить?


Класс, выступающий в качестве свойства, редактор свойства и компонент, который их использует, должны находиться в одном .bpk.

Заключение


Конечно, код, приведенный здесь, далек от совершенства, но это, в конце концов, только пример. Вы сами должны доработать(и доработаете, я уверен) его до нужного уровня. Написание редакторов компонент сделает ваши компоненты более надежными и удобными во время проектирования программ, а кроме того, немного поразмыслив, можно сделать их разделяемыми с другими авторами компонент. Удачи!




Комментарии

 Ваш комментарий к данному материалу будет интересен нам и нашим читателям!



Последние статьи: Программирование под ОС / C - C++ /

Пишем CD проигрыватель 2
28-05-2010   

Сейчас я покажу как можно написать простой проигрыватель CD дисков. Для начала разместим все нужные компоненты на форме (см. рисунок)... подробнее

Кол. просмотров: общее - 4915 сегодня - 0

Пишем браузер
28-05-2010   

Продолжаю тему клонирования программ darkamstera на Delphi в С++Builder. В этой статье я покажу, как с помощью стандартных компонентов, можно создать свой браузер. Браузер будет на движке всеми-любимого InternetExplorer. Наш зверь сможет ходить по URL... подробнее

Кол. просмотров: общее - 3729 сегодня - 1

Информация о системе
28-05-2010   

Выводим информацию о нашей родненькой системе. Для получения большей части информации мы будем использовать обширные функции, это не так сложно, как может показатся с первого взгляда и вообще код довольно простой и примитивный, так что покапавшись в нем пару минут - можно в легкостью разобраться что к чему, зачем и как... подробнее

Кол. просмотров: общее - 3530 сегодня - 0

FTP клиент своими руками
28-05-2010   

Здраствуй, сечас я покажу, как в CBuilder можно создать свой простой FTP-клиент, похожий пример можно найти в документации C++Builder Developnets Guilde... подробнее

Кол. просмотров: общее - 4201 сегодня - 0

Работаем с POP-сервером
28-05-2010   

Здраствуй, в этой статье я расскажу про способы получения e-mail писем и их прочтения. Для начала давайте составим интерфейс будущей программы Вот, что у меня вышло... подробнее

Кол. просмотров: общее - 3600 сегодня - 0



  WWW.COMPROG.RU - 2009-2012 | Designed and Powered by Zaipov Renat | Projects