#include <vcl.h>
#pragma hdrstop
#include "Code.h"

#define MAIN_PAGE "bcdev.narod.ru"
#define E_MAIL  yerm@mail.ru
////////////////////////////////////////////////////////
// Это не FAQ (часто задаваемые вопросы) и CAQ (обычно  
// задаваемые вопросы). Скорее всего это можно 
// охарактеризовать как коллекцию фрагментов кода из 
// реально работающих программ. Очень часто, разрабатывая
// новый проект, сталкиваешься с ситуацией, когда вдруг 
// понимаешь, что подобная задача уже была однажды решена
// тобой. К сожалению, найти предыдущее решение бывает 
// не всегда легко. А в случае смены места работы и вовсе
// невозможно. Поэтому я решил создать эту коллекцию и 
// обнародовать ее в Инете. Там иногда найти легче, чем  
// на своем компьютере :). К тому же, может быть, это  
// будет представлять интерес не только для меня.
// Фрагменты снабжены комментариями, поясняющими суть
// решаемой проблемы. 
////////////////////////////////////////////////////////
// 
// 1.Сохранение-чтение неопубликованного свойства типа enum
// 2.Присвоить глобальную функцию событию 
// 3.Вызвать метод класса как функцию (по "обычному" адресу) 
// 4.Вызвать опубликованный метод класса по имени
// 5.Получить имя опубликованного метода
// 6.Подмена Caption для комплексной строки в компоненте
//   TdxDBInspector (DevExpress)
// 7.Перенаправление на актуальный DataModule
// 8.Вызов защищенного виртуального метода 
// 9
.Создание компонента по его метаклассу: 
// 10.Динамическое добавление Action в ActionManager и ActionMainMenuBar 
// 11.Исправление ошибки в примере
Examples\ShellControls
// 12.Получение интерфейса текущего проекта (Tool API)
// 13.Получение опций текущего проекта (Tool API)

////////////////////////////////////////////////////////
// Здесь надо обратить внимание, каким образом определяется
//символьный эквивалент значения переменной типа enum.
//Основное требование, при котором данный код сработает,
//заключается в том, чтобы этот тип enum был зарегистрирован
//в RTTI, т.е. хоть раз был использован в качестве типа для
//опубликованного свойства. В данном случае речь идет о типе
//TWindowState, использовался как тип для published свойства
//WindowState в TForm. Надо заметить, что если для получения 
//информации о типе использовать TCustomForm, функция
GetPropInfo
//либо выдаст exception (C++Builder 5), либо NULL(C++Builder 6),
//т.к. в TCustomForm это свойство объявлено лишь как public   

//-----------------------------------------------------

void __fastcall TDataWrapper::DefineProperties(TFiler* Filer)
{

inherited::DefineProperties(Filer);
//определяем, какие свойства будут сохраняться и функции
//это будут выполнять 
Filer->DefineProperty("FormState",ReadFormState, WriteFormState, true);
}
//-----------------------------------------------------
void __fastcall TDataWrapper::ReadFormState(TReader* Reader)
{
TEntryPointForm* Form = (TEntryPointForm*)Owner;
//получение информации о свойстве, имеющего тип TWindowState
Typinfo::PTypeInfo pTypeInfo =
*(Typinfo::GetPropInfo(__typeinfo(TForm),"WindowState"))->PropType;
//чтение значения свойства в символьном виде 
AnsiString strEnumValue = Reader->ReadIdent();
//перевод символьного вида в значение типа enum 
TWindowState state = (TWindowState)GetEnumValue(pTypeInfo,strEnumValue);
if(Form->SettingsClient->FStoredParams.Contains(spState))
Form->FWindowState = state;

}
//------------------------------------------------------
void __fastcall TDataWrapper::WriteFormState(TWriter* Writer)
{

TEntryPointForm* Form = (TEntryPointForm*)Owner;
//получение информации о свойстве, имеющего тип TWindowState
Typinfo::PTypeInfo pTypeInfo =
*(Typinfo::GetPropInfo(__typeinfo(TForm),"WindowState"))->PropType;
//запись значения enum в символьном виде 
Writer->WriteIdent(GetEnumName(pTypeInfo,Form->FWindowState));
}

////////////////////////////////////////////////////////
// Ниже приведен код, иллюстрирующий работу с адресами 
//методов класса
// Присвоить глобальную функцию событию 
// Вызвать метод класса как функцию (по "обычному" адресу) 
// Вызвать опубликованный метод класса по имени
// Получить имя опубликованного метода
//-----------------------------------------------------

class TForm1 : public TForm
{
__published:
// IDE-managed Components
   
TButton* Button1;
    TButton* Button2;
    void __fastcall
Button1Click(TObject *Sender)
private:
// User declarations
public:
// User declarations
    __fastcall TForm1(TComponent* Owner);
};
//-----------------------------------------------------
//через первый параметр будет перадаваться this

void __fastcall GlobalClick(void* This, TObject *Sender)
{
    ShowMessage(AnsiString("Global:")+
    ((TComponent*)This)->Name + "->" +
    ((TComponent*)Sender)->Name);
}
//------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
//присвоить глобальную функцию событию
TMethod Method;
Method.Data = this;
Method.Code= GlobalClick;
Button2->OnClick = *(TNotifyEvent*)&Method;

//вызвать метод по обычную адресу
TNotifyEvent Click = &Button1Click;
TMethod Method1 = *(TMethod*)&Click;
//через первый скрытый параметр передаем this
typedef void (__fastcall *Func)(void*,TObject *);
Func func;
func = (Func)Method1.Code;
func(this, Button1);

//вызвать опубликованный метод по имени
ShortString ProcName = "Button1Click";
TMethod Method2;
Method2.Code = MethodAddress(ProcName);
if (Method2.Code)
{
    Method2.Data = this;
    TNotifyEvent Click = *(TNotifyEvent*)&Method2;
    Click(Button1);
}

//получить имя обработчика события
TMethod Method3 = *(TMethod*)&(Button1->OnClick);
ShortString ProcName1 = MethodName(Method3.Code);
ShowMessage( ProcName1);
}
//------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ShowMessage(AnsiString("Method:") +
    this->Name + "->" + ((TComponent*)Sender)->Name);
}
//------------------------------------------------------

////////////////////////////////////////////////////////
//Пример, как простенькая задача может превратиться в
//головную боль. Требовалось всего на всего подменить
//стандартный Caption, который набирается из Caption строк,
//входящих в комплексную строку, на свой. Для этого фирма
//DevExpress предлагает воспользоваться событием OnDrawCaption,
//в котором нужно задать требуемый текст и указать, что 
//дальнейшая отработка не требуется

void __fastcall TAttrValueSetFrame::InspectorDrawCaption(
TdxInspectorRow *Sender, TCanvas *ACanvas, const TRect &ARect,
AnsiString &AText, TFont *AFont, TColor &AColor, bool &ADone)
{
    AText =
"Мой собственный Caption"
    ADone = true;
}
//Все работает замечательно, пока эта строка не является 
//подстрокой. В этом случае справа от Caption резервируется
//область под кнопку, отрисовка которой происходит после
//события OnDrawCaption. А поскольку установив
ADone в true,
//мы указали, что дальнейшей отрисовки не требуется, вместо
//кнопки появлялся всякий мусор. Если же установить
ADone=true,
//кнопка отрисовывалась нормально, но вместо нужного Caption
//выводился стандартный. Переписка с DevExpress ничего не дала.
//Они предлагали отрисовывать кнопку прямо в этом событии.
//Это приводило довольно к объемному коду, поскольку нужно было
//анализировать нужна кнопка или нет и вид кнопки в зависимости
//от стиля. Мной найден был более простой способ
void __fastcall TAttrValueSetFrame::InspectorDrawCaption(
TdxInspectorRow *Sender, TCanvas *ACanvas, const TRect &ARect,
AnsiString &AText, TFont *AFont, TColor &AColor, bool &ADone)
{
class TdxInspectorAccess:public Dxinspct::TdxInspector
{
public:
__property Indent;
};
TdxInspectorComplexRow* ComplexRow = dynamic_cast<TdxInspectorComplexRow*>(Sender);
if (ComplexRow)
{
TRect TextRec = ARect;
TextRec.Left = ((TdxInspectorAccess*)Sender->Inspector)->Indent+1;
ACanvas->Brush->Color = AColor;
ACanvas->TextRect(TextRec, ARect.Left + 1, TextRec.Top + 1,
"Мой собственный Caption");
//Изюминка здесь. Дальнейшая обработка не прерывается
//Просто стандартный Caption будет отрисовываться
//в области с нулевой шириной.

TextRec.Right = TextRec.Left;
//А здесь снимаем защиту разработчиков, которые 
//запретили изменение ARect
const_cast<TRect&>(ARect) = TextRec;
//и разрешаем дальнейшую отрисовку.
ADone = false;
}
//Надо сказать, что компоненты DevExpress хороши, когда их
//используешь как есть. Но если требуется что-то неординарное
//возникает куча проблем из-за недостаточной продуманности
//их структуры.

////////////////////////////////////////////////////////
//Решение проблемы, которая возникает как правило
//при использовании пары TForm - TDataModule. Суть проблемы 
//состоит в следующем: в приложении динамически создаются 
//экземпляр TForm1 и TDataModule1. При этом Data Contols формы
//ссылаются TDataSource модуля. Если эти ссылки присваивать в 
//в дизайне, то при создании вторых экземпляров формы и модуля  
//в приложении в рантайме, котролы второго экземпляра формы будут 
//ссылаться на TDataSource's первого экземпляра модуля. Для того, 
//что бы перенаправить их на нужный модуль можно использовать 
//следующую универсальную функцию, которая должна вызываться или  
//после создания формы или непосредственно в конструкторе

void __fastcall TEntryPointForm::Redirect(TComponent *Root, TDataModule *DataModule)
{

Typinfo::TTypeKinds SupportKinds;
SupportKinds << tkClass;
for(int i = 0; i < Root->ComponentCount; ++i)
 {
    TComponent* Component = Root->Components[i];
    Typinfo::TPropList pList;
    int nPropCount = GetPropList((Typinfo::PTypeInfo)(Component->ClassInfo()),
    SupportKinds,((Typinfo::PPropList)(&pList)));
    for( int j = 0; j < nPropCount; j++)
    if (__classid(TDataSource) == GetObjectPropClass(Component, pList[j]->Name))
    {
        TDataSource* Source = dynamic_cast<TDataSource*>
            (GetObjectProp(Component, pList[j], __classid(TDataSource)));
        if (Source)
        {
            TDataSource* Destination =
                  dynamic_cast<TDataSource*>(DataModule->FindComponent(Source->Name));
            if (Destination)
                SetObjectProp(Component, pList[j], Destination);
         }
    }
    if (Component->ComponentCount)
        Redirect(Component, DataModule);
 }
}
//А теперь использование

TDataModule1*  Module1 =  new TDataModule(Application);
TForm1*  Form1 =  new TForm1(Application);
Form1->Redirect(Form1,Module1);

////////////////////////////////////////////////////////
// Ответ на вопрос, заданный на одном из форумов: 
//"Как вызвать у компонента TStringGrid защищенный
// виртуальный метод DrawCell?". Не вдаваясь в обсуждение 
// целесообразности вызова DrawCell просто привожу код
// как это можно сделать 

void __fastcall TForm1::Button1Click(TObject *Sender)
{
class TPublicGrid:public TStringGrid
{
    public:
        void __fastcall DrawCell(int ACol, int ARow,
        const Windows::TRect &ARect, Grids::TGridDrawState AState){}
};
((TPublicGrid*)StringGrid1)->DrawCell(1,1, TRect(), TGridDrawState());
}


////////////////////////////////////////////////////////
// Создание компонента по его метаклассу
//   (Из форума RSDN)

TComponent *CreateComponent( TComponentClass CClass, TComponent *AOwner)
{
  typedef TComponent *( __fastcall *TConstructor)( TComponentClass, bool, TComponent *);
  TConstructor constructor = ((TConstructor *) CClass)[ vmtCreateObject - 1];
 return constructor( CClass, true, AOwner);
};  

////////////////////////////////////////////////////////
// Динамическое создание Action, ActionManager  
//  и ActionMainMenuBar и добавление Action в ActionManager
//  и ActionMainMenuBar

TActionManager*  ActionManager = new TActionManager(this);

//создание первого Action
TAction* Action = new TAction(this);
Action->Name = "TestAction1";
Action->Category = "Main";
Action->OnExecute = Action1Execute;
//добавление в ActionManager
Action->ActionList = ActionManager;

//создание второго Action
Action = new TAction(this);
Action->Name = "TestAction2";
Action->Category = "Main";
Action->OnExecute = Action2Execute;
//добавление в ActionManager
Action->ActionList = ActionManager;
 

TActionBarItem* BarItem = ActionManager->ActionBars->Add();
 
//создание  ActionMainMenuBar 
TActionMainMenuBar*  MenuBar = new TActionMainMenuBar(this);
BarItem->ActionBar =  MenuBar;
MenuBar->Parent = this;
 
class TProxyActionBar : public TCustomActionBar {
    public:
      __property Items;
      using TCustomActionBar::CreateControl;
  };
 
//формируем меню "Main" из Action, принадлежащих к категории "Main"
TActionClientItem* Item = ((TProxyActionBar*)MenuBar)->Items->Add();
Item->Caption  =   "Main";
for( int i= 0; i <  ActionManager->ActionCount; i++)
    if ( ((TAction*) ActionManager->Actions[i])->Category ==  "Main" )
      Item->Items->Add()->Action =  ActionManager->Actions[i];
 
((TProxyActionBar*)MenuBar)->CreateControl(Item);
 
////////////////////////////////////////////////////////
// Исправления, которые необходимо внести в ShellCtrls.cpp  
//  для того, чтобы компонент  TShellListView нормально работал
//  (см.
\Examples\ShellControls)

void __fastcall TCustomShellListView::RootChanged(void)
{
    bool StayFresh;
    if(FUpdating)
        return;
    FUpdating = true;
    try
    {
        StayFresh = FAutoRefresh;
       
       //AutoRefresh = false;-ошибка, исправлено на
        FAutoRefresh = false;
       
         SynchPaths();
        Populate();
        if(ViewStyle == vsReport)
            EnumColumns();
       
        //AutoRefresh = StayFresh;-ошибка, исправлено на
        FAutoRefresh = StayFresh;
    }
    __finally
    {
        FUpdating = false;
    }
}
 

////////////////////////////////////////////////////////
//
Получение интерфейса текущего проекта (Tool API)  
// 

_di_IOTAProject __fastcall TPluginModuleEditor::GetProject()
{
  _di_IOTAModuleServices svc;
  BorlandIDEServices->Supports(svc);
  _di_IOTAProject result = 0;
  for (int i = 0; i < svc->ModuleCount; ++i)
  {
   _di_IOTAModule module = svc->Modules[i];
   _di_IOTAProjectGroup group;
   if (module->Supports(group)) {
   result = group->ActiveProject;
   break;
  }
return result;
}
 

////////////////////////////////////////////////////////
//
Получение опций текущего проекта (Tool API)   
// 

Variant __fastcall TPluginModuleEditor::GetOptions(_di_IOTAProject a_Project,
const AnsiString& a_Value)
{
 _di_IOTAProjectOptions Options = a_Project->GetProjectOptions();
 return Options->Values[a_Value];
}

...
//Получение финального пути  
AnsiString OutputDir = GetOptions(a_Project, "OutputDir");
//Получение версии
 
int MajorVersion = GetOptions(a_Project,"MajorVersion");
 int MinorVersion = GetOptions(a_Project,"MinorVersion");
 int Release      = GetOptions(a_Project,"Release");
 int Build        = GetOptions(a_Project,"Build");
 

 




 

 
 




 
 



 

Сайт управляется системой uCoz