dvv |
Отправлено: 03.05.2005, 07:46 |
|
Не зарегистрирован
|
Можно ли написать такую функцию, которая возвращала бы нужный тип данных? Например, как нибудь так:
template <class Type> Type MyFunc(int Chooze)
{
switch
{
case 1: return (int)1;
case 2: return (float)1.1;
}
return "Параметр функции может быть только 1 или 2";
}
Т.е. в зависимости от параметра функция возвращает различный тип. [B] |
|
Rius |
Отправлено: 03.05.2005, 08:59 |
|
Мастер участка
Группа: Участник
Сообщений: 321
|
CODE | Variant MyFunc(int Chooze)
{
Variant res;
switch(Chooze)
{
case 1: res = (int)1; break;
case 2: res = (float)1.1; break;
default: res = AnsiString("Параметр функции может быть только 1 или 2");
}
return res;
} | А зачем?
|
|
dvv |
Отправлено: 03.05.2005, 09:38 |
|
Не зарегистрирован
|
Идея принимается!
Работая с базами данных я часто сталкивался с методом FieldByName. C его помощью можно не только читать значения полей таблицы, но и присваивать значение полям. Например:
int aaa=Table1->FieldByName("Id")->AsInteger;
Table1->FieldByName("Name")->Text="Наименование чего-то там";
Можно ли написать такую функцию(метод), которая устаналивала бы значение нужного типа данных и не просто для переменной, а для свойства компонента. Т.е. работала бы так как FieldByName, но применительно к свойствам. Например:
TLabel * Label;
. . .
Variant __fastcall TForm1::MyFieldByName(TComponent* Label1, AnsiString PropertyName)
{
if(PropertyName=="Caption")
return Label1->Caption;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
MyFieldByName(Label1, "Caption")="Надпись";
}
Я понимаю, что Label1->Caption="Надпись" никто не отменял.
Но нужно реализовать именно через функцию(метод)! Я хочу создать объект, свойствами которого, будут компоненты TLabel, TEdit ...
Для управления свойствами компонентов объекта мне и нужна такая функция
|
|
dvv |
Отправлено: 03.05.2005, 16:02 |
|
Не зарегистрирован
|
Упростим задачу. Есть функция
int* __fastcall Test(int* i)
{ return i;}
После выполнения кода:
int aa=10;
*(Test(&aa))=20;
aa примет значение 20. Т.к.функция вернет указатель на переменную aa. Затем значению указателя присвоим 20.
Делаем то же самое с компонентом:
int* __fastcall TForm1::Test()
{ return &(Edit1->Width);}
Выполнение кода
*(Test())=300;
должно привести к изменению ширины компонента:
На самом деле, хотя Edit1->Width изменяется, ширина компонента остается прежней. Почему?
|
|
Rius |
Отправлено: 03.05.2005, 20:06 |
|
Мастер участка
Группа: Участник
Сообщений: 321
|
В ООП и С++ принято предотвращать прмяой доступ к членам классов. Доступ осуществляется через функции-члены, которые могут проверить правильность указываемых данных. Поэтому это &(Edit1->Width) не работает.
CODE | Variant __fastcall TForm1::MyFieldByName(TComponent* Label1, AnsiString PropertyName)
{
if(PropertyName=="Caption")
return Label1->Caption;
} | — imho изобретение усложненной версии велосипеда, есть широко распространенный обработчики событий с параметром Sender. Например и у формы и у кнопки может быть один обработчик события OnClick:
CODE | void __fastcall TForm1::OnClick(TObject *Sender)
{
AnsiString cname = Sender->ClassName();
if(cname == "TForm") Caption = "Form clicked";
if(cname == "TButton") Caption = "Button clicked";
} |
|
|
dvv |
Отправлено: 03.05.2005, 21:25 |
|
Не зарегистрирован
|
C первой частью "марлизонского балета" разобрались. Теперь мы знаем как написать фунуцию, которая возвращеает любой тип. В моей реализации она будет иметь вид:
Variant GetProretyValue(TComponent* Component, AnsiString PropertyName);
Функция получает адрес компонета и имя свойства, а возвращает значение свойства.
Вторая часть "марлизонского балета" заключается в том, что бы уже не читать значения свойств, а присваивать им значения. Например:
SetProretyValue(TComponent* Component, AnsiString PropertyName,Variant Value);
Как написать такую функцию (SetProretyValue) мне понятно. В принцыпе достаточно того, что будут делать эти две функции.
Третья часть "марлизонского балета" — хочется заменить две функции одной. Ведь мы стремимся к краткости кода! Сделать, например так, как работает FieldByName. Если, конечно, это возможно. А как такое сделать я не знаю. Может кто подскажет? |
|
Rius |
Отправлено: 03.05.2005, 22:01 |
|
Мастер участка
Группа: Участник
Сообщений: 321
|
Например создать класс, который имеет индексирумое строкой свойство с функциями доступа, а значение есть Variant.
|
|
dvv |
Отправлено: 04.05.2005, 06:48 |
|
Не зарегистрирован
|
Что имеется ввиду "индексирумое строкой свойство"? |
|
Rius |
Отправлено: 04.05.2005, 09:30 |
|
Мастер участка
Группа: Участник
Сообщений: 321
|
QUOTE | Свойство-массив
Некоторые свойства могут быть массивами, а не только такими простыми типами данных как bool, int и AnsiString. Этот аспект не очень хорошо документирован для пользователей. Примером свойства-массива является свойство Lines компонента ТМеmо. Это свойство позволяет пользователю осуществлять доступ к отдельным строкам компонента Memo.
Свойство-массив объявляется точно так же, как и другие свойства, но имеет два отличия: объявление включает соответствующие индексы с заданными типами, и индексы не обязательно целые числа. В листингах 9.12-9.15 приведен пример использования двух свойств. Одно содержит в качестве индекса строку, а второе -- целое число.
Листинг 9.12. Использование строки в качестве индексаCODE | class PACKAGE TStringAliasComponent : public TComponent
{private:
TStringList RealList; TStringList AliasList;
AnsiString _fastcall GetStringAlias(AnsiString RawString);
AnsiString _fastcall GetRealString(int Index);
void fastcall SetRealString(int Index, AnsiString Value);
public:
property AnsiString AliasString[AnsiString RawString] =
{read = GetStringAlias};
property AnsiString RealString[int Index] =
{read=GetRealString, write=SetRealString};
} | В этом примере компонент может хранить список строк вместе со списком псевдонимов. Свойство AliasString принимает значение RawString и возвращает псевдоним с помощью метода GetStringAlias(). При создании свойств-компонентов многие разработчики смущены тем, что в объявлении используется индексная нотация (т.е. квадратные скобки []), а в коде используется такой же способ записи, как и при вызове обычного метода. Например, свойство Real String имеет не только возвращаемое значение типа AnsiString, но и целое число в качестве индекса. Метод GetRealString() используется для извлечения строки списка на основе заданного значения индекса, как показано в листинге 9.13.
Листинг 9.13. Метод чтения свойства-массиваCODE | AnsiString _fastcall TStringAliasComponent::GetRealString(int Index)
{
if(Index > (RealList->Count — 1))
return ""; return RealList->Strings[Index];
} |
В коде это свойство будет выглядеть следующим образом. AnsiString str = StringAlias1->RealString[0];
Рассмотрим подробнее метод SetRealString(). На первый взгляд объявление этого метода выглядит несколько странно. Первый параметр является целочисленной переменной и используется как индекс, а второй — - переменной типа AnsiString. Переменная RealList типа TStringList вставляет в список строку типа AnsiString в месте, указанном с помощью целочисленного параметра-индекса. В листинге 9.14 показан код определения метода SetRealString().
Листинг 9.14. Метод записи значений свойства-массиваCODE | void fastcall TStringAliasComponent::SetRealString(int Index, AnsiString Value)
{
if((RealList->Count — 1)) < Index)
RealList->Add(Value); else
RealList->Insert(Index, Value);
} |
В листинге 9.14 значение параметра Index сверяется с количеством строк, которые уже находятся в списке. Если значение параметра Index больше этого количества, то строка Value просто добавляется в конец списка. В противном случае вызывается метод Insert () объекта TStringList для вставки строки в месте, указанном значением индекса Index. Теперь в этот список можно вставить следующую строку.
StringAliasl->RealString[l] == "некоторая строка";
Рассмотрим еще один интересный момент. Метод GetStringAlias() используется для чтения значения свойства AliasString, в котором в качестве индекса используется строка. Список строк является массивом строк, поэтому каждая строка имеет индекс или определенное место в этом списке. Метод IndexOf () компонента TStringList использу¬ется для сравнения переданной строки со строками, которые уже находятся в списке. Этот метод возвращает целое значение, которое является индексом строки в этом спи¬ске, или значение -1, если такой строки нет. Теперь остается только вернуть из списка псевдонимов строку с индексом, указанным в вызове метода IndexOf (). Соответствую¬щий код показан в листинге 9.15.
Листинг 9.15. Метод GetStringAlias()CODE | AnsiString _fastcall TStringAliasComponent::GetStringAlias(
AnsiString RawString)
{
int Index;
Index = RealList->IndexOf(RawString); if((Index == -1) (Index >(AliasList->Count-l))) return RawString;
return AliasList->Strings [Index ];
_} |
Для применения этого свойства можно использовать следующий код.
CODE | AnsiString MyAliasString =
StringAliasl->AliasString("The Raw String"); |
|
Источник: http://progz.ru/forum/viewtopic.php?t=11128
Jarrod Hollingworth, Dan Butterfield, Bob Swart, Jamie Allsop
C++Builder 5 Developer 's Guide,
Глава 9 "Создание пользовательских компонентов".
Впрочем FiledByname можно считать возвращает указатель на объект Field, так что делаешь один класс для доступа к свойству (={read=..., write=...}), и вкладываешь его в другой класс, который обращается к компонентам.
Отредактировано Rius — 04/05/2005, 12:37
|
|
dvv |
Отправлено: 05.05.2005, 08:56 |
|
Не зарегистрирован
|
Вот это в самое яблочко. Как раз такое мне и нужно! Спасибо.В результате удалось реализовать код:
TRo* Ro1 = new TRo(toLabel); // Создает объект по виду как TLabel
TRo* Ro2 = new TRo(toEdit); // Создает объект по виду как TEdit
Ro1->PropByName["Caption"] = "Значение";
Ro2->PropByName["Text"] = "100";
ShowMessage(Ro1->PropByName["Caption"]+" = "+Ro2->PropByName["Text"]); // Краткость — сестра таланта (и теща гонорара)
Не ясно только как работает компилятор. В принципе, это уже другая тема. Но все же. Например мы объявляем метод:
void __fastcall SetRealString(int Index, AnsiString Value);
А затем вызываем его :
StringAliasl->RealString[l] = "некоторая строка";
Не совсем понятно почему переменной l ставиться в соответствие int Index, а "некоторая строка" соответствует AnsiString Value?
Ну ладно здесь типы int и AnsiString разные. Вроде как можно разобраться. А если бы мы присваивали значение int вместо строки? А если бы в метод SetRealString объявить не два и три параметра? Есть ли по этому поводу какие либо правила? |
|
Rius |
Отправлено: 05.05.2005, 20:10 |
|
Мастер участка
Группа: Участник
Сообщений: 321
|
QUOTE | Не совсем понятно почему переменной l ставиться в соответствие int Index, а "некоторая строка" соответствует AnsiString Value?
Ну ладно здесь типы int и AnsiString разные. Вроде как можно разобраться. А если бы мы присваивали значение int вместо строки? А если бы в метод SetRealString объявить не два и три параметра? Есть ли по этому поводу какие либо правила? | это в книге описано. разберешь несколько примеров и заметишь закономерности. я сам пока только с одномерными массивами работал, да по двумерным советовал.
|
|
|