Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Компонент TCheckListBox в BCB6


Автор: avalon 14.3.2003, 03:00
Подскажите, плз, как они "выкусывают" свой TCheckListBoxDataWrapper (объект для хранения состояния итема - cbChecked, cbUnchecked, cbGrayed и т.д.) при таком доступе к ассоциированному объекту:

j = *(long*)TestBox->Items->Objects[0];

В TCheckListBoxDataWrapper'е есть поле для хранения адреса ассоциированных данных пользователя.


TCheckListBox *TestBox;
long *i, j;
i = new long;
*i = 9999;

TestBox->Items->AddObject("test sg", (TObject*)i);
TestBox->Checked[0] = 1;
TestBox->State[0] = cbGrayed;
j = *(long*)TestBox->Items->Objects[0];

j == *i // confused.gifconfused.gif

Оно в принципе правильно работает, но я не могу понять, как они это делают?
Перелопатил весь checklst.pas, не нашел.
Пожалуйста, помогите !


Автор: Vyacheslav 17.3.2003, 19:58
Ничего не понял. Причем здесь ассоциированые объекты? Эти объекты используются только, если у программиста возникла необходимость хранить наряду с текстовой строкой дополнительную информацию. Если такой необходимости нет, его можно просто не использовать. В твоем примере просто дополнительно хранится число 9999. До состояния можно добраться через State или Checked
Код

TCheckListBox *TestBox;
long *i, j;
i = new long;
*i = 9999;

// добавляем пункт "test sg" и ассоциируем с ним число 9999
TestBox->Items->AddObject("test sg", (TObject*)i);
// устанавливаем Checked
TestBox->Checked[0] =  true;
//сбрасываем Checked и  устанавливаем cbGrayed
//а хотели наверное TestBox->ItemEnabled[0] = false
TestBox->State[0] = cbGrayed;
// обратно получаем ассоцироавнный объект  9999
j = *(long*)TestBox->Items->Objects[0];

j == *i //

Автор: avalon 17.3.2003, 21:15
Мне надо написать компонент типа TComboBox, только с возможностью множественного выбора. Я ковырял исходники TCheckListBox, чтобы понять как и где они хранят состояние итемов. Оказалось, они вставляют объект TCheckListBoxDataWrapper(хранящий состояние итемов) между итемом и ассоц. данными, то есть итем указывает не на ассоц. данные, а на TCheckListBoxDataWrapper, а он, в свою очередь, на ассоц. данные. При доступе к асс. данным методами TCheckListBox TCheckListBoxDataWrapper явно выкусывается (видно в исх. коде), но при доступе методами TStrings и TStringList выкусывания в коде нет!!! А ведь при доступе к асс. данным методами TStrings я получаю нормальные асс. данные, как в моем примере. Тем не менее, в TStrings не имеют представления о том, что между итемом и асс. данными может что-то быть, но методы TStrings корректно работают. (confused.gif!!! Ж8-О)

Автор: Vyacheslav 17.3.2003, 23:21
Состояние итемов они хранят, как ты правильно заметил в TCheckListBoxDataWrapper.
Что здесь непонятно, я лично не понял. Во первых, надо учитывать, что в TCustomListBox используется не просто TStringList, а TListBoxStrings. У него переопределены GetObject и SetObject. Они для получения ассоциированного объекта используют методы своего владельца, в данном случае CheckListBox. ( учти метод GetItemData - DYNAMIC)

Код

function TListBoxStrings.GetObject(Index: Integer): TObject;
begin
 if ListBox.Style in [lbVirtual, lbVirtualOwnerDraw] then
   Result := ListBox.DoGetDataObject(Index)
 else
 begin
   Result := TObject(ListBox.GetItemData(Index));
   if Longint(Result) = LB_ERR then Error(SListIndexError, Index);
 end;
end;

Ну а TCheckListBox::GetItemData и выполняет "выкусывание"
Код

function TCheckListBox.GetItemData(Index: Integer): LongInt;
begin
 Result := 0;
 if HaveWrapper(Index) then
   Result := TCheckListBoxDataWrapper(GetWrapper(Index)).FData;
end;

Автор: avalon 18.3.2003, 18:33
Vyacheslav, спасибо smile.gif

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