Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ Проблема с компонентом TreeView

Автор: ninja 22.07.2010 21:10

Добрый день!

Необходимо заполниль дерево с помощью компонента TreeView, имя элемента дерева должно состоять из номеров и имен, т.е. например дерево должно выглядеть следующим образом:

Код
1имя1
2имя2
3имя3
   3.1имя4
   3.2имя5
      3.2.1имя6
4имя7
   4.1имя8


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

Родительские элементы нумеруются нормально, а вот с дочерними проблема

void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString name, roditelb;
TTreeNode *node;

if (TreeView1->Items->Count == 0) // добавление первого элемента
{
name = "1:";
name += Edit1->Text+":";
name += ComboBox1->Items->Strings[ComboBox1->ItemIndex];
TreeView1->Items->Add(NULL,name);
}
else
{
if (RadioGroup1->ItemIndex == 0) /// добавление родительских элементов
{
name = IntToStr(TreeView1->Items->Count+1)+":";
name += Edit1->Text+":";
name += ComboBox1->Items->Strings[ComboBox1->ItemIndex];
TreeView1->Items->Add(NULL,name);
}

if (RadioGroup1->ItemIndex == 1) /// добавление дочерних элементов
{
selected2++;
name = IntToStr(selected2)+":";
name = Edit1->Text+":";
name += ComboBox1->Items->Strings[ComboBox1->ItemIndex];
TreeView1->Items->AddChild(TreeView1->Selected,name);
}
}
}




Спасибо за помощь.

Автор: Client 22.07.2010 22:23

name = IntToStr(selected2)+":";
name = Edit1->Text+":"; // тут опечатка у тебя? может по этому и не правильно?
name += ComboBox1->Items->Strings[ComboBox1->ItemIndex];

Автор: ninja 22.07.2010 22:26

Да действительно опечатка, но это всего лишь добаляет имя, тоесть у меня имя берется их 2х компонентов Edit и ComboBox, я просто уже поразному пробывал, текст был закоментирован, я не заметил, если исправить все равно не работает.

Автор: Client 22.07.2010 22:42

присоедини весь проект, а то лень создавать самому smile.gif

Автор: volvo 22.07.2010 22:53

А дочерние можно нумеровать, используя не selected2 (непонятно где и как описанный), а:

		if (RadioGroup1->ItemIndex == 1) /// добавление дочерних элементов
{
name = IntToStr(TreeView1->Selected->Count)+":";
name += Edit1->Text+":";
name += ComboBox1->Items->Strings[ComboBox1->ItemIndex];
TreeView1->Items->AddChild(TreeView1->Selected,name);
}


TreeView1->Selected->Count вернет тебе количество дочерних элементов у Selected, не надо ничего считать вручную, все уже посчитано... Получить из Selected строку до двоеточия и добавить ее в начало нового элемента - не самая большая проблема, правда?

Автор: ninja 22.07.2010 22:53

Вот проект:

Прикрепленный файл  TreeView.rar ( 7.07 килобайт ) Кол-во скачиваний: 381


Владимир спасибо Вам огромное все прекрасно работает, как то я проглядел этот свойство у TreeView

Автор: ninja 23.07.2010 0:00

Еще такой вопрос: как реализовать создание пунктов меню на основе полученного дерева? т.е Мне необходимо создать, используя компонент MainMenu, пункты меню, учитывая все уровни вложенности полученного дерева, не могу понять как мне это сделать.

получилось пока следующее:

TMenuItem *Menu;

for (i = 0; i < TreeView1->Items->Count; i++)
{
Menu = new TMenuItem(0);
Menu->Caption = "Пункт меню " + IntToStr(i+1);
MainMenu1->Items->Add(Menu);
}

Автор: volvo 23.07.2010 4:28

Так лень мне Билдер запускать... Дельфи открытая, поэтому сделаю здесь (переносится на Билдер практически один в один)

procedure BuildMenu(node: TTreeNode; menu: TMenuItem);
var
NewMenu, NewSubMenu: TMenuItem;
TVnode: TTreeNode;
begin
TVnode := node;
while TVnode <> nil do
begin
if TVnode.HasChildren then
begin
NewSubMenu := TMenuItem.Create(menu);
NewSubMenu.Caption := TVnode.Text;
BuildMenu(TVnode.GetFirstChild, NewSubMenu);
menu.Add(NewSubMenu);
end
else
begin
NewMenu := TMenuItem.Create(menu);
NewMenu.Caption := TVnode.Text;
menu.Add(NewMenu);
end;
TVnode := TVnode.GetNextSibling;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var CurrMenu: TMainMenu;
begin
CurrMenu := TMainMenu.Create(Form1);
BuildMenu(TreeView1.Items.GetFirstNode, CurrMenu.Items);
Form1.Menu := CurrMenu;
end;
Вот и все...

Проверял до 5-го уровня вложенности - работает нормально...

Автор: ninja 26.07.2010 1:02

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

void BuildMenu (TTreeNode *node, TMenuItem *menu)
{
TMenuItem *NewMenu, *NewSubMenu;
TTreeNode *TVnode;

TVnode = node;

while (TVnode != NULL)
{
if (TVnode->HasChildren)
{
// NewSubMenu = TMenuItem->Create(menu);

NewSubMenu = new TMenuItem(menu);
NewSubMenu->Caption = TVnode->Text;
BuildMenu(TVnode->getFirstChild(), NewSubMenu);
menu->Add(NewSubMenu);
}
else
{
//NewMenu := TMenuItem.Create(menu);

NewSubMenu = new TMenuItem(menu);
NewMenu->Caption = TVnode->Text;
menu->Add(NewMenu);
}
TVnode = TVnode->getNextSibling();
}
}


void __fastcall TForm1::Button3Click(TObject *Sender)
{

TMainMenu *CurrMenu;

CurrMenu = new TMainMenu(Form1);
BuildMenu(TreeView1->Items->GetFirstNode(), CurrMenu->Items);
Form1->Menu = CurrMenu;

}



Автор: volvo 26.07.2010 1:30

Значит, плохо перевел:

void BuildMenu(TTreeNode *node, TMenuItem *menu)
{
TTreeNode *TVnode = node;
while(TVnode)
{
if(TVnode->HasChildren)
{
TMenuItem *NewSubMenu = new TMenuItem(menu);
NewSubMenu->Caption = TVnode->Text;
BuildMenu(TVnode->getFirstChild(), NewSubMenu);
menu->Add(NewSubMenu);
}
else
{
TMenuItem *NewMenu = new TMenuItem(menu);
NewMenu->Caption = TVnode->Text;
menu->Add(NewMenu);
}
TVnode = TVnode->getNextSibling();
}
}


void __fastcall TForm1::Button3Click(TObject *Sender)
{
TMainMenu *CurrMenu = new TMainMenu(Form1);
BuildMenu(TreeView2->Items->GetFirstNode(), CurrMenu->Items);
Form1->Menu = CurrMenu;
}

только что у меня отработало прекрасно... Только не надо говорить, что это то же самое, хорошо? Это совсем не то же самое smile.gif

Автор: ninja 26.07.2010 1:46

Да действительно не тоже самое, Вы при объявлении переменный сразу присваиваете ей начальное значение, т.е выделяете память для нового объекта, Владимир не могли бы Вы мне объяснить почему именно так работает, а как у меня нет? Спасибо за помощь.

Автор: volvo 26.07.2010 2:37

Цитата
не могли бы Вы мне объяснить почему именно так работает, а как у меня нет?
Могли бы... smile.gif Внимательнее надо быть:
Цитата
	else
{
//NewMenu := TMenuItem.Create(menu);
NewSubMenu = new TMenuItem(menu); // Чего создали? NewSubMenu
NewMenu->Caption = TVnode->Text; // А обращаемся к чему? К NewMenu, а там - мусор...
menu->Add(NewMenu);
}


Автор: ninja 26.07.2010 2:42

мде) что-то я совсем невнимательный ((( спасибо еще раз.

Автор: ninja 30.07.2010 23:50

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


Пробывал сделать таким образом, работает неверно

void __fastcall TForm1::TreeView1Click(TObject *Sender)
{

TreeView1->Items->Item[TreeView1->Selected->Index]->ImageIndex = 2;

}



и так тоже не верно...
void __fastcall TForm1::TreeView1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
int X, int Y)
{
TTreeNode *clickedNode;

clickedNode = TreeView1->GetNodeAt(X,Y);

if (clickedNode != NULL)
{
TreeView1->Items->Item[clickedNode->Index]->ImageIndex = 2;

}

}

Автор: volvo 31.07.2010 15:34

Цитата
таким образом, работает неверно

Цитата
и так тоже не верно...
Глупостями не занимайся... Тебе достаточно только в самом начале назначить для ВСЕХ узлов ImageIndex и SelectedIndex, а дальше - это уже забота TreeView, как при изменении выбранного элемента его правильно отобразить... Смотри:

void __fastcall TForm1::FormCreate(TObject *Sender)
{
for(int i = 0; i < TreeView1->Items->Count; i++)
{
TreeView1->Items->Item[i]->ImageIndex = 0; // Неактивный Node
TreeView1->Items->Item[i]->SelectedIndex = 1; // Активный Node
}
}

Магия, правда? Теперь запускаешь программу, и все работает (все остальные обработчики, которыми ты пытался колдовать с SelectedItem/ImageIndex надо убрать, они не нужны теперь...)

Кстати, можно каждому узлу вообще назначить свою картинку прямо там же, еще до отображения дерева, можно сказать, что картинку отображать не надо (ImageIndex = -1), все, что угодно...

Автор: ninja 31.07.2010 22:23

В том то и дело, что я хотел сделать чтобы пользователь мог сам выбрать картинку, т.е. кликнув по ветке, затем выбрав картинку, она должна появиться в выбранной ветке. Прошу прощения за неверно поставленный вопрос.

Автор: volvo 31.07.2010 23:27

И все равно - не вижу проблемы: Ну, выбрал элемент. Назначил ему какую-то картинку (откуда - это я сам должен догадаться? Тогда все просто: с диска, да, выбрал и записал в ImageList, тут же последний индекс из ImageList-а присвоил в TreeView1->Selected->SelectedIndex). Дальше что? Хоть засоздавайся потом новыми узлами - те, что ужа были назначены (если правильно создавать новые) менять свои изображения не будут. Не веришь?

Прикрепленное изображение

Сначала было добавлено изображение на узел с текстом "12", потом к лежащему выше узлу "11" было добавлено 6 потомков ("adding"), одному из них я опять же сменил картинку, и ПЕРЕД ним опять добавил 3 потомка узлу... Как видишь - ничего не сбилось...

Автор: ninja 1.08.2010 0:01

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