C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
TVirtualStringTree, при сортировке теряется инициирующая инф
olegenty
Отправлено: 25.10.2006, 11:01


Ветеран

Группа: Модератор
Сообщений: 2412



После сортировки пропадает инициирующая информация об узлах, инициированных, как vsHasChildren, пропадает раскрывающий крестик, если фактически узел ни разу не раскрывался...

Пока тупо заглушил созданием фиктивного Child. Но это есть хероватое решение, хочется чего-то большого и тёплого, например — совета...
Doga
Отправлено: 25.10.2006, 16:03


Мастер участка

Группа: Участник
Сообщений: 575



Привет!

Странно, у меня такого эффекта не наблюдается... ohmy.gif

Проверил на том самом пресловутом VTVDemo. Для главной формы был добавлен следующий код:

VTreeHolder.h
CODE

class TNodeData : public TObject
{
 //...
 public:
   //...
   __property AnsiString NodeText = {read = FNodeText};
   __property AnsiString NodeHint = {read = FNodeHint};
 //...
}



MonitorForm.h
CODE

class TMonitorForm : public TForm
{
//...
private: // User declarations
//...
TSortDirection SortDirection;
//...
}


MonitorForm.cpp
CODE

//---------------------------------------------------------------------------
__fastcall TMonitorForm::TMonitorForm(TComponent* Owner)
: TForm(Owner)
{
//...
SortDirection = sdDescending;
}
//---------------------------------------------------------------------------
//Обработчик события сравнения нодов
void __fastcall TMonitorForm::VirtualStringTree1CompareNodes(
TBaseVirtualTree *Sender, PVirtualNode Node1, PVirtualNode Node2,
TColumnIndex Column, int &Result)
{
if (Node1->Parent == Node2->Parent)
{
VTVNODEDATA *VTVNodeData1 = (VTVNODEDATA *)VirtualStringTree1->GetNodeData(Node1);
VTVNODEDATA *VTVNodeData2 = (VTVNODEDATA *)VirtualStringTree1->GetNodeData(Node2);

if (VTVNodeData1 && VTVNodeData2)
{
Result = VTVNodeData1->NodeData->NodeText.AnsiCompare(VTVNodeData2->NodeData->NodeText);
}
else
{
Result = 0;
}
}
else
{
Result = 0;
}
}
//---------------------------------------------------------------------------
//Обработчик события OnClick дополнительной кнопки сортировки
void __fastcall TMonitorForm::BitBtn2Click(TObject *Sender)
{
if (SortDirection == sdDescending)
{
SortDirection = sdAscending;
}
else
{
SortDirection = sdDescending;
}

VirtualStringTree1->SortTree(0, SortDirection, false);
}
//---------------------------------------------------------------------------


Отредактировано Doga — 25.10.2006, 17:19
olegenty
Отправлено: 26.10.2006, 09:24


Ветеран

Группа: Модератор
Сообщений: 2412



а были ли у тебя там ноды со Styles vsHasChildren фактически без этих самых Children?

вся фишка в том, что не делаю я ничего "неправомерного".

вот так сравниваю:
CODE

///////////////////////////////////////////////////////////////////////////////////////////////////
//
void __fastcall COperator::OnCompareNodes( TBaseVirtualTree *Sender
                                        , PVirtualNode Node1
                                        , PVirtualNode Node2
                                        , TColumnIndex Column
                                        , int &Result
                                        )
{
   RecordType *Record1 = static_cast<RecordType*>(Sender->GetNodeData(Node1));
   RecordType *Record2 = static_cast<RecordType*>(Sender->GetNodeData(Node2));
   AnsiString SortGroup1 = Records_[Record1->InstanceID()]["SortGroup"] + Records_[Record1->InstanceID()]["Design"];
   AnsiString SortGroup2 = Records_[Record2->InstanceID()]["SortGroup"] + Records_[Record2->InstanceID()]["Design"];
   Result = AnsiCompareStr(SortGroup1, SortGroup2);
}


вот так сортирую
CODE

///////////////////////////////////////////////////////////////////////////////////////////////////
//
void __fastcall COperator::OnHeaderClick( TVTHeader *Sender
                                       , TColumnIndex Column
                                       , TMouseButton Button
                                       , TShiftState Shift
                                       , int X
                                       , int Y
                                       )
{
   if (mbLeft == Button && !Column)
   {
       if (sdAscending == Sender->SortDirection)
       {
           Sender->SortDirection = sdDescending;
       } else
       {
           Sender->SortDirection = sdAscending;
       }
       Tree_->SortTree(0, Sender->SortDirection);
   }
}


а вот так инициализирую:
CODE

void __fastcall COperator::OnInitNode( TBaseVirtualTree *Sender
                                    , PVirtualNode ParentNode
                                    , PVirtualNode Node
                                    , TVirtualNodeInitStates &InitialStates
                                    )
{
   RecordType *Record = static_cast<RecordType*>(Sender->GetNodeData(Node));
   if (Record)
   {
       if (Record->HasSpec())
       {
           Node->States << vsHasChildren;
           InitialStates << ivsHasChildren;
       }
   }
}


так вот, после вызова метода SortTree в любом месте, происходит сброс States. по крайней мере, оттуда пропадает vsHasChildren, и, что самое непонятное, даже ReinitNode для всех узлов после сортировки ни к чему не приводит, хотя код инициализации и вызывается. (хотя, ReinitNode — это хуже, чем та заглушка, что я пока прикрутил).
Doga
Отправлено: 26.10.2006, 14:23


Мастер участка

Группа: Участник
Сообщений: 575



Привет!

QUOTE

а были ли у тебя там ноды со Styles vsHasChildren фактически без этих самых Children?


Да, конечно. В VTVDemo все ноды такие. Нода ничего не знает о своих будущих детках до события OnExpanding. По этому я так же как и ты устанавливаю флаг состояния vsHasChildren принудительно.


Правда инициализация ноды у меня происходит немного по другому. Я неиспользовал событие OnInitNode, поскольку мне это было неудобно. Инициализация ноды производится сразу за её добавлением (созданием) в одном блоке кода. Тогда же производится и установка флага vsHasChildren. Хотя я, не думаю, что всё это имеет какое либо значение.


Я думаю, тут всё дело в способе взова метода SortTree.

procedure SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);

А именно, в последнем третьем параметре — DoInit. Похоже он отвечает за принудителную переинициализацию сортируемых нодов. Если его проигнорировать при вызове SortTree
(т.е. типа SortTree(0, SortDirection); ),
оставив его равным по умолчанию TRUE, тогда, признаюсь, и уменя сбрасываются флаги vsHasChildren (тоолько что проверил biggrin.gif ).
А если его принудительно установить как FALSE
(т.е. типа SortTree(0, SortDirection, false); ),
то все работает как надо! Сам этого раньше не знал rolleyes.gif
olegenty
Отправлено: 26.10.2006, 15:01


Ветеран

Группа: Модератор
Сообщений: 2412



я инициализировал тоже по-разному.

твой рецепт — что доктор прописал. я и не подумал посмотреть описание метода SortTree, выдрав всё из примера, где параметр опущен.


Спасибо! (ибо моя заглушка спасала меня только с vsHasChildren, но не с vsMultiline)

Наирульнейшее дерево!!!
Doga
Отправлено: 26.10.2006, 16:02


Мастер участка

Группа: Участник
Сообщений: 575



Ну что ж, это хорошо smile.gif

Я вообще то, когда у себя проверял, список параметров для SortTree получил через Class Explorer и их значения выставлял интуитивно по названиям параметров ohmy.gif . И, естественно не знал, что третий параметр имеет значение по умолчанию. Подозрение возникло, когда сравнил наши вызовы этого метода biggrin.gif
olegenty
Отправлено: 26.10.2006, 16:34


Ветеран

Группа: Модератор
Сообщений: 2412



грабля имеет продолжение: редактирование нода приводит к его переинициализации. и никаких скрытых переметров не обнаружено (в методе EditNode). щас буду искать способ лечения. у меня дерево редактируемое самописными редакторами по самое нехочу. пока вернулся к старой заглушке.

непонятно следующее: после редактирования происходит переинициализация. в ней я корректно заполняю States (OnInitNode), и вижу, что vsHasChildren присутствует в States, однако ещё где-то/как-то потом этот параметр сбрасывается. пймать бы, где и как. хоть в сорцы лезь. кстати, так и сделаю, наверное...
Doga
Отправлено: 26.10.2006, 17:51


Мастер участка

Группа: Участник
Сообщений: 575



Я так понимаю, ты хочешь отредактировать дополнительные данные хранимые в свойстве Data ноды.

Для этого, я думаю, EditNode можно и не вызывать. Запускай свой редактор, а потом просто обнови ноду (InvalidateNode), да и это нужно будет только в случае изменения текста самой ноды.

А для редактирования одного лишь текста самой ноды достаточно события OnNewText.
olegenty
Отправлено: 27.10.2006, 06:09


Ветеран

Группа: Модератор
Сообщений: 2412



всё хуже намного: самописный редактор (суть — реализация COM-интерфейса) инициализируется в OnCreateEditor. это регламентируется TVirtualStringTree. Редактирую не только текст, редактирую всё, что не лень. И вот ввиду регламента TVirtualStringTree я привязан к его событиям, определющим редактирование. т.е. без EditNode никак.

событие OnInitChildren не спасает.
Doga
Отправлено: 27.10.2006, 14:02


Мастер участка

Группа: Участник
Сообщений: 575



Блин, даже не знаю, что ещё предложить sad.gif

Может, на форуме softgems'a посмотреть?
olegenty
Отправлено: 27.10.2006, 14:31


Ветеран

Группа: Модератор
Сообщений: 2412



пофигу. сорец дерева ещё не разобрал, но проверил — баг затрагивает только vsHasChildren, поэтому заглушки с фиктивным Child хватит вполне. на чтение форума особо времени нет, к утру бы сдать уже кусочек на тестирование... а том только эта проблема. в общем — всё в пределах допустимых отклонений.
Doga
Отправлено: 27.10.2006, 14:45


Мастер участка

Группа: Участник
Сообщений: 575



QUOTE

в общем — всё в пределах допустимых отклонений.


Ну, это как всегда biggrin.gif
Doga
Отправлено: 31.10.2006, 20:43


Мастер участка

Группа: Участник
Сообщений: 575



Привет!

Ну что, решение найти удалось? Самому интересно ohmy.gif
olegenty
Отправлено: 01.11.2006, 07:42


Ветеран

Группа: Модератор
Сообщений: 2412



Нет, всё осталось с заглушкой. Но я и не искал решения, отдал заказчику Wizard, пока не звонит — значит всё в порядке. Дело в том, что программирую я конечно планово, но в промежутках между выполнением основных функций — руководства группой программистов и сервисных работников. И только по одному направлению, которое полностью висит на мне (в наследство от самого себя). Так вот, пока заказчик не звонит, я занят работой, очень отличной от программирования. И разберусь теперь уже только если будут какие-то конкретные проблемы у пользователей подразделения заказчика.

Вернуться в Вопросы программирования в C++Builder