Jump to content
Fórum Script Brasil
  • 0

Copiar De Uma Treeview Para Outra


Ivano
 Share

Question

Olá amigos,

Estou precisando copiar "nós" de uma treeView para outra. Só que tem de ser na mesma posição que estava, porque as arvores são iguais...

Alguém sabe me dizer como pegar e passar esse 'caminho'?

Desde já agradeço a ajuda dos amigos! ;-)

Link to comment
Share on other sites

16 answers to this question

Recommended Posts

  • 0

opa

tipo, salva o conteúdo numa stream e depois você puxa na outra treeview exemplo

var

ss: tmemorystream;

begin

ss := tmemorystream.create;

try

treeview1.savetostream(ss);

ss.position := 0;

treeview2.loadfromstream(ss);

finally

ss.free;

end;

abraço

Link to comment
Share on other sites

  • 0
Estou precisando copiar "nós" de uma treeView para outra. Só que tem de ser na mesma posição que estava, porque as arvores são iguais...
Olá Churc,

Não sei se entendi bem, mas assim elas ficarão exatamente iguais, não é?

Eu vou precisar jogar apenas um nó de cada vez, de acordo com o que o usuario selecionar...

[]´s

Se são iguais, mas você quer copiar apenas um nó de cada vez, então você quer fazer como?

Supondo:

+- Pai 1
| +- Filho 1
| | +- Neto 1
| | | L- Bisneto 1
| | L- Neto 2
| L- Filho 2
+- Pai 2
| +- Filho 1
|   L- Neto 1
| +- Filho 2
| | L- Neto 1
| |   +- Bisneto 1
| |   L- Bisneto 2
+- Pai 3
  L- Filho 1
    +- Neto 1
    L- Neto 2

1) Estando selecinado Bisneto 1 (Pai 1\Filho 1\Neto 1), você quer copiar para a outra árvore o Bisneto 1 e seus predecessores (Pai 1, Filho 1 e Neto 1)?

2) Se estiver selecionado Neto 1 (Pai 2\Filho 2), você quer copiar para a outra árvore o Neto 1 e seus predecessores (Pai 2\Filho 2) apenas, ou também seus sucessores (Bisneto 1 e Bisneto 2)?

Link to comment
Share on other sites

  • 0
Só que tem de ser na mesma posição que estava, porque as arvores são iguais...
Então, baseado no que você disse achei que seria uma cópia pois como seria colocados nas "mesmas posições", caso o usuário selecionar, baseado no exemplo do Micheus "Bisneto 1" e "Bisneto 2"?

responde a pergunta do Micheus que ai fica mais fácil de te ajudar...

abs

Link to comment
Share on other sites

  • 0

opa

então, eu fiz de um jeito aqui, não é o melhor jeito mas pelo

menos está funcionando auhauh

está meio gambiarra usar StringList, tentei fazer sem usar mas

tava dando muito trabalho, talvez alguém poste uma rotina

melhor ou voce a melhore... expliquei mais ou menos o que

acontece

Procedure CopiaTreeviews(TreeViewA, TreeViewB: TTreeView);
var
  sl: TStringList;
  Node: TTreeNode;
  i: Integer;
begin
  //checa se foi passado os treeview
  if ((TreeViewA = nil) or (TreeViewB = nil)) then Exit;
  //pega o item selecionado
  Node := TreeViewA.Selected;
  //cria uma lista para poder armazenar os items
  sl := TStringList.Create;
  //como vai sendo pego debaixo pra cima, então vamos
  //adicionar o item selecionado...
  sl.Insert(0, Node.Text);
  //enquanto houver filiações quanto ao item selecionado...
  while (Node <> nil) do
  begin
    //pega a filiação
    Node := Node.Parent;
    //se houver filiação ou a posição for maior ou igual a zero,
    //no caso 0 é o root ou seja, o primeiro item de tudo, o Pai :P
    if ((Assigned(Node)) and (Node.Level >= 0)) then
    //insere no começo da lista, pois como mencionado é pego de baixo
    //para cima
    sl.Insert(0, Node.Text);
  end;
  //agora vamos adicionar na outra treeview os itens pegos...
  for i := 0 to sl.Count - 1 do
  begin
    //se o i = 0 quer dizer que é o Pai, então colocamos ele
    //como primeiro de tudo, e não adicionamos filiação, no caso Nil
    if (i = 0) then
    Node := TreeViewB.Items.AddChild(nil, sl[i]) else
    //se for maior que 0 quer dizer que é filiação, e é passado a
    //filiação anterior que é pega em Node := Treeview2.Items.AddChild(...
    Node := TreeViewB.Items.AddChild(Node, sl[i])
  end;
  sl.Free;
end;

para usar exemplo,

CopiaTreeviews(TreeView1, TreeView2);

desse jeito não pega multselect... vai precisar?

abraço

Link to comment
Share on other sites

  • 0

testei ele aqui, ficou bem legal! :))

Não precisa multselect não, a unica coisa que vai ter de mudar é que

ele gerar um "nível 0" a cada vez que chamamos a função.

Acho que se comparar antes se o Pai já existe na árvore, daí ele encontra e já copia lá, né?

Cara muito obrigado pela ajuda, você é muito gente boa! :-)

Link to comment
Share on other sites

  • 0

Pessoal, pensei que iria ser fácil, mas está cada vez mais confuso :(

Como eu faço para verificar se o nó Pai correspondente existe na outra árvore e, se não, criar a estrutura e copiar o nó, ou se não copiar apenas o nó pra lá?

Detalhe: Eu posso ter o pai A com os filhos A1 e A3 a esquerda e já ter o Pai "A" correspondente na árvore com o nó filho A2. Então eu querer copiar o A2 para a direita.

O que eu não estou conseguindo fazer:

1-Verificar se já existe esse nó, pegando um "endereço". Assim:

Pega o nome do Pai: "A"

2-Compara na "arvore 2" se existe um pai "A" (isso eu acho que sabendo pegar esse endereço fica mais fácil, usando um count e comparando TODOS, porque o nó não terá a mesma posição "count" )

3- Se for criar a estrutura, verificar se já existe o avô e etc...

O problema maior é pegar esse endereço :(, estou ficando loco com isso!

Isso é difícil assim mesmo de fazer ou eu é que estou marcando touca?

Link to comment
Share on other sites

  • 0

Pessoal, pensei que iria ser fácil, mas está cada vez mais confuso :(

Como eu faço para verificar se o nó Pai correspondente existe na outra árvore e, se não, criar a estrutura e copiar o nó, ou se não copiar apenas o nó pra lá?

Detalhe: Eu posso ter o pai A com os filhos A1 e A3 a esquerda e já ter o Pai "A" correspondente na árvore com o nó filho A2. Então eu querer copiar o A2 para a direita.

Ivano, agora você diz que se um nó existe na lista da direita, mas não existe na da esquerda, você quer copiar ele para a lista da esquerda??? :blink:

Afinal, você quer mover apenas da esquerda para a direita ou em qualquer direção?

Acho que resolvida esta questão, a resolução das outras dúvidas fica mais fácil.

1-Verificar se já existe esse nó, pegando um "endereço". Assim:

Pega o nome do Pai: "A"

É esse endereço vai ter que ser o texto do item, mas respeitando a hierarquia, pelo que você já citou antes, porque eventualmente se você tiver itens com mesmo nome em posições diferentes da árvore, vai virar uma bagunça.
Link to comment
Share on other sites

  • 0

Amigos,

Eu sei está confuso, mas também porque realmente é complicada a coisa.

Estou tentando fazer agora, de forma mais simples.

O que preciso nesse momento agora é saber como avançar um nó.

Tentei encontrar isso nos axemplos acima mas não encontrei.

Fazer algo do tipo: arvore2.nó.next;

Com isso já consigo fazer funcionar o FOR que preciso e a coisa anda.

Isso porque entendo que assim "Selected" irá passar para o próximo, correto?

Obrigado pela atenção e paciência de vocês.

Link to comment
Share on other sites

  • 0

É assim:

Posteriormente eu irei carregar informações de minha base de dados em duas árvores.

Daí alguns pontos deverão aparecer a direita e outros a esquerda, dependendo do "status" dela na tabela. Então alguns pontos "filhos" irão aparecer só na arvore da direita ou só na arvore da esquerda.

Até aí tudo bem.

Depois o usuario irá clicar em um item da esquerda e enviar para a direita. Nesse momento eu vou mudar o status desse item na tabela, o que é tranquilo.

Mas eu tenho de verificar se o pai dele já está na arvore de destino. Se já estiver eu coloco ele lá. Se não estiver tenho de colocar antes o pai dele, ok?

Até qui eu consegui comparar se o nó já existe atraves do parâmetro:

NodeOri := PInteger( arvore.Selected.Data )^;

Mas eu tenho de clicar no item na arvore de destino, se não ele não encontra!

Meu "For" não funciona! olha como esle está nesse momento:

--------------------

var nodeori, nodedes: integer; //TTreeNode;

i: Integer;

nodesel: TTreeNode;

begin

NodeOri := PInteger( arvore.Selected.Data )^;//arvore.Selected;

for i := 0 to arvore2.Items.Count-1 do

Nodedes:= PInteger( arvore2.Selected.Data )^;

if NodeOri = Nodedes then begin

showmessage('Achei! É: '+IntToStr(Nodedes));

i:=i+1;

end;

-------------------

Se eu conseguir correr todos os níveis procurando o pai, e se não encontrar procurar pelo avô, daí eu coloco eles lá.

Se eu não fizer isso terei de carregar o Select várias vezes e vai ficar muito pesado :(

Consegui explicar o problema agora? Entenderem o que eu quero fazer e para que?

Link to comment
Share on other sites

  • 0

Correção! Agora funcionou, estou trabalhando nele, olha só! :)

---------------------------------

var nodeori, nodedes: integer;

i: Integer;

nodesel: TTreeNode;

begin

NodeOri := PInteger( arvore.Selected.Data )^;

for i := 0 to arvore2.Items.Count-1 do begin

form1.Caption:=arvore2.Items.text;

Nodedes:= PInteger( arvore2.items.Data )^;

if NodeOri = Nodedes then begin

showmessage('Achei! É: '+IntToStr(Nodedes));

end;

end;

Link to comment
Share on other sites

  • 0

opa

baseado naquela primeira rotina que te passei, e baseado no que

você disse depois veja se é isso que precisa

Procedure CopiaTreeviews(TreeViewA, TreeViewB: TTreeView);
var
  sl: TStringList;
  Node: TTreeNode;
  i: Integer;
begin
  //checa se foi passado os treeview
  if ((TreeViewA = nil) or (TreeViewB = nil)) then Exit;
  //pega o item selecionado
  Node := TreeViewA.Selected;
  //cria uma lista para poder armazenar os items
  sl := TStringList.Create;
  //como vai sendo pego debaixo pra cima, então vamos
  //adicionar o item selecionado...
  sl.Insert(0, Node.Text);
  //enquanto houver filiações quanto ao item selecionado...
  while (Node <> nil) do
  begin
    //pega a filiação
    Node := Node.Parent;
    //se houver filiação ou a posição for maior ou igual a zero,
    //no caso 0 é o root ou seja, o primeiro item de tudo, o Pai :P
    if ((Assigned(Node)) and (Node.Level >= 0)) then
    //insere no começo da lista, pois como mencionado é pego de baixo
    //para cima
    sl.Insert(0, Node.Text);
  end;
  //agora vamos adicionar na outra treeview os itens pegos...
  for i := 0 to sl.Count - 1 do
  begin
    //se o i = 0 quer dizer que é o Pai
    if (i = 0) then
    begin
      //não adicionamos parentesco
      Node := nil;
      //Se houver items na arvore2 então procuramos por parentesco
      if (TreeViewB.Items.Count > 0) then
      begin
        //começamos pelo primeiro item
        Node := TreeViewB.Items.Item[0];
        //procuramos pela árvore inteira
        while Node <> nil do
        //opa achamos ele :P
        if (AnsiCompareText(sl[i], Node.Text) = 0) then
        Break else
        Node := Node.GetNext;
      end;
      //não achamos parentesco, então adicionamos como uma nova familia...
      if (Node = nil) then
      Node := TreeViewB.Items.AddChildFirst(nil, sl[i]) else
      //se achou a familia, então apenas adiciona o item selecionado a ela
      begin
        TreeViewB.Items.AddChild(Node, sl[sl.Count - 1]);
        Break;
      end;
    end
    else
    //se for maior que 0 quer dizer que é filiação, e é passado a
    //filiação anterior que é pega em Node := Treeview2.Items.AddChild(...
    Node := TreeViewB.Items.AddChild(Node, sl[i])
  end;
  sl.Free;
end;

Fiz a busca baseada no nome do item, então se houver itens com o mesmo nome

vai dar conflito, então altere a busca de Nome pra ponteiros como você fez na sua

rotina acima

abraços

Link to comment
Share on other sites

  • 0

Depois de muita ajuda de vocês consegui fazer funcionar do jeito que eu precisava. Deu trabalho mas ficou bom!

Voi postar aqui como ficou para o caso de algém poder precisar.

A procedure está funcionando do jeito que está. A única coisa é que se ela não encontrar o pai, ela irá incluir apenas o primeiro "ancestral", e não todos até o nó que foi procurado em primeiro lugar.

Muito obrigado a todos! :)

-------------------------------------------------------------

var NodeOriAux, NodePaiOri, NodeOri, NodeDes: integer; //TTreeNode;

qtdNodes, c, i, ii: Integer;

nodesel: TTreeNode;

texto: string;

achou: boolean;

begin

NodePaiOri := PInteger(arvore.Selected.Parent.Data)^;

NodeOri := PInteger(arvore.Selected.Data)^;

texto:=arvore.Selected.text;

c:=0;

i:=0;

for c := 0 to arvore.Items.Count-1 do begin //vai procurar o pai depois se não encontrar o filho, seria bom calcular o nº de antepassados...

for i := 0 to arvore2.Items.Count-1 do begin // Vai procurar em todos os nós da 2º arvore, se preciso

NodeDes:= PInteger( arvore2.items.Data )^; //Node de destino na 2º arvore

if NodePaiOri = NodeDes then begin //O pai do Node de origem é = ao de destino?

showmessage('Achei! o Pai dele é: '+IntToStr(NodeDes)); //Se sim, é nele que vai o node de Origem!

New(rg);

rg^:= NodeOri;

arvore2.Items.AddChildObject(arvore2.items, texto, rg);

Exit;

end;

end;

arvore.TopItem; //Se não sair vai p o topo da árvore 1

ii:=0;

for ii := 0 to arvore.Items.Count-1 do begin //Vai procurar o cara Pai arvore para achar o Avô

NodeOriAux := PInteger(arvore.items[ii].Data )^;

if (NodeOriAux = NodePaiOri) then begin //Se achou...

//qtdNodes:=qtdNodes+1;

NodeOri := PInteger(arvore.items[ii].Data)^; //o node de origem fica sendo o Pai

texto:=arvore.items[ii].text; //atualiza o texto.

NodePaiOri := PInteger(arvore.items[ii].Parent.Data)^; //o avô vira Pai...

break;

end;

end;

end;

end;

Link to comment
Share on other sites

  • 0

Ivano, apenas umas dicas...

seria bom calcular o nº de antepassados...
no objeto TreeNode há a propriedade Level que determina o nível na hierarquia aonde o nó se encontra - veja se era a isso que você se referia.

New(rg);
aparentemente rg é um ponteiro para inteiro, certo?
NodePaiOri := PInteger(arvore.Selected.Parent.Data)^;
Observe que a propriedade Data é do tipo pointer. Se você deseja armazenar uma estrutura simples, como um integer nesta propriedade. Não se dê a o trabalho de alocar memória para isto, desde que a informação caiba no SizeOf(Pointer) -> 4 bytes.

As coisas podem, então, serem mais simples:

- Para escrever o conteúdo faça apenas: Arvore.Selected.Parent.Data := Pointer(NodePaiOri);

- Para ler: NodePaiOri := LongInt(Arvore.Selected.Parent.Data);

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share



  • Forum Statistics

    • Total Topics
      151k
    • Total Posts
      649.1k
×
×
  • Create New...