A imagem acima é a representação visual criada pela classe dbTree. Mas, por traz dessa imagem tem uma tabela de dados. Vamos Observar, através do IDE, as suas características: O protheus, para montagem do Tree criará um arquivo temporário com a estrutura acima. Onde: T_IDLIST | É um numero sequencial e único para cada registro | T_IDTREE | Representa o Node Pai | T_IDCODE | Representa o Item do Tree | T_ISTREE | “S” se for um NODE | T_PROMPT | Descrição a ser apresentada | T_CARGO | Campo Auxiliar para permitir Localizar e Alterar o Prompt do Tree. No Exemplo CARGO contem um número sequencial de acordo com o número de item no Tree. Nesse caso saberei que o “Item 009” sempre terá T_CARGO como #0013. Utilizado, internamente, pelo metodo TreeSeek para localizar um item do dbTree. | T_BMP001 | Armazena o Número da Imagem 1 utilizada na apresentação do dbTree para o Item em questão. Por exemplo, se o Tree for de uma árvore de diretórios imagem de uma “pasta fechada” quando “recolhido”. | T_BMP002 | Armazena o Número da Imagem 2 utilizada na apresentação do dbTree para o Item em questão. Por exemplo, se o Tree for de uma árvore de diretórios imagem de uma “pasta fechada” quando “expandido”. | T_CLIENT | Flag que identifica se o Client já foi atualizado com a informação corrente. Utilizado internamente para otimização na montagem da imagem referente ao Tree. | Essa tabela será indexada da seguinte forma:
Ordem | Chave | 1 | T_IDLIST | 2 | T_IDTREE | 3 | T_IDCODE | 4 | T_IDCARGO | O nome do índice é criado baseado no nome do arquivo temporário onde o “prefixo” “S” é substituido e o “sufixo” correspondente à ordem do índice é adicionado. Uma outra característica importante a notar é que o nome do arquivo, no dbTree corresponde ao seu ALIAS. Informação essa armazenada na propriedade cArqTree do objeto em questão. Com isso, podemos afirmar que existem duas formas de se pesquisar registros nesse arquivo. A primeira usando o método odbTree:TreeSeek(cChave) e outra, usando o Alias como em: (odbTree:cArqTree)->(dbSeek(cChave,.F.)) Ex.: lFound := odbTree:TreeSeek(“#00013”). A questão é que o método TreeSeek() sempre irá usar a ordem correspondente ao T_CARGO. E, teremos um grande problema ao tentar usar GetCargo logo em Seguida; pois, pressupondo que TreeSeek ira posicionar o dbTree no item localizado, imaginamos que GetCargo() ira retornar a informação de T_CARGO corrente. O que não é verdade. Observe: Então, para muitas opções de pesquisa no dbTree prefiro usar dbSeek diretamente. Uma delas para localizar os Nodes Superiores ou Todos os itens que pertence a um Node. Por exemplo. Para saber todos os itens relativos a “Menu 001” e, sabendo que T_CARGO do “Menu 001” é "#0001". Observe acima que esse item é um Node Superior, pois T_ISTREE está com “S”. Observe também, que T_IDTREE dele está como “0000000" caracterizando que ele faz parte do primeiro nível de Nodes. Então, neste caso para achar todos os itens que correspondam ao nível mais superior do dbTree faríamos. E assim por Diante. No caso acima localizamos os nodes principais. Para Encontrar seus filhos é só usar T_IDCODE na chave para pesquisa a T_IDTREE. Se o Node for um tree basta repetir a operação até !( lFound ) ou T_ISTREE em branco. Poderá montar uma função recursiva para isso. (Consulte o exemplo postado por Luis Lacombe: DbTree recursiva) Vale lembrar que ao usar dbSeek diretamente o Tree Visual não será atualizado. Para isso deverá usar o Método TreeSeek da classe dbTree e que o método espera, como parâmetro T_CARGO. Neste caso, poderia trabalhar em conjunto com dbSeek e TreeSeek criando sua própria função TreeSeek. e usá-la como: Neste caso, o exemplo completo ficaria como: #include "protheus.ch" #include "dbtree.ch"
#xtranslate USER PROCEDURE <p> => PROCEDURE U_<p>
USER PROCEDURE MyTree()
PUBLIC __TTSINUSE := .T. //(Para uso no IDE RecLock precisa disso) PUBLIC __TTSPUSH := Array(0) //(Para uso no IDE RecLock precisa disso) PUBLIC __cLogSiga := "" //(Para uso no IDE GravaLog em RecLock precisa disso)
// Cria um diálogo DEFINE DIALOG oDlg TITLE "Teste de DBTree" FROM 10,10 TO 400,700 COLOR CLR_BLACK,CLR_WHITE PIXEL // Cria o DbTree no diálogo, ocupando o tamanho total do mesmo DEFINE DBTREE odbTree FROM 00,00 TO oDlg:nHeight,oDlg:nWidth OF oDlg CARGO DBADDTREE odbTree PROMPT "Menu 001" RESOURCE "BMPTABLE" CARGO "#0001" DBADDITEM odbTree PROMPT "Item 001" RESOURCE "BMPSXG" CARGO "#0002" DBENDTREE odbTree DBADDITEM odbTree PROMPT "Item 002" RESOURCE "BMPTRG" CARGO "#0003" DBADDITEM odbTree PROMPT "Item 003" RESOURCE "BMPCONS" CARGO "#0004" DBADDITEM odbTree PROMPT "Item 004" RESOURCE "BMPPARAM" CARGO "#0005" DBADDTREE odbTree PROMPT "Menu 002" OPENED RESOURCE "BMPTABLE" CARGO "#0006" DBADDITEM odbTree PROMPT "Item 005" RESOURCE "BMPSXG" CARGO "#0007" DBADDTREE odbTree PROMPT "Menu 003" OPENED RESOURCE "BMPTABLE" CARGO "#0008" DBADDITEM odbTree PROMPT "Item 006" RESOURCE "BMPSXG" CARGO "#0009" DBADDTREE odbTree PROMPT "Menu 004" OPENED RESOURCE "BMPTABLE" CARGO "#0010" DBADDITEM odbTree PROMPT "Item 007" RESOURCE "BMPSXG" CARGO "#0011" DBENDTREE odbTree DBADDITEM odbTree PROMPT "Item 008" RESOURCE "BMPSXG" CARGO "#0012" DBENDTREE odbTree DBENDTREE odbTree DBADDITEM odbTree PROMPT "Item 009" RESOURCE "BMPSXB" CARGO "#0013"
ACTIVATE DIALOG oDlg CENTER ON INIT ShowNodeTree(@odbTree)
Return
Static Function ShowNodeTree(odbTree)
Local cCargo
IF TreeSeek( @odbTree , "#0013" , "T_CARGO" , @cCargo ) MsgInfo( "Seek: " + cCargo + CRLF + "GetCargo: " + odbTree:GetCargo() ) EndIF
Return( TreeSeek( @odbTree , "#0013" , "T_CARGO" , @cCargo ) )
Static Function TreeSeek( odbTree , cKeySeek , cIndexKey , cCargo )
Local aIndexes := Array(0)
Local cAliasTree := odbTree:cArqTree Local cKey := ""
Local lFound := .F. Local nOrder
(cAliasTree)->(aEval(Array(10),{|x,y|cKey:=IndexKey(y),IF(!Empty(cKey),aAdd(aIndexes,{y,cKey}),NIL)}))
DEFAULT cIndexKey := "T_CARGO" cIndexKey := Upper( AllTrim( cIndexKey ) ) nOrder := aScan( aIndexes , { |aBag| aBag[2] == cIndexKey } ) IF ( nOrder == 0 ) cIndexKey := "T_CARGO" nOrder := aScan( aIndexes , { |aBag| aBag[2] == cIndexKey } ) EndIF
(cAliasTree)->( dbSetOrder( aIndexes[nOrder][1] ) ) lFound := ( cAliasTree )->( dbSeek( cKeySeek , .F. ) )
IF ( lFound ) lFound := odbTree:TreeSeek( ( cAliasTree )->T_CARGO ) IF ( lFound ) cCargo := odbTree:GetCargo(( cAliasTree )->T_IDCODE) EndIF EndIF
Return( lFound )
Após a execução do exemplo, o Ponteiro do dbTree estará posicionado no item cujo T_CARGO corresponda a “#0013” ´que é o “Item 009”
|
Rapaz... Me indica onde você aprende essas coisas!
ResponderExcluirMuito obrigado pela dica, você consegue transmitir a informação com muita clareza e objetividade.
Parabéns
Renato,
Excluiruma coisa que faltou mencionar e que é fundamental para a solução definitiva do seu problema é que você pode implementar a sua própria dbTree a partir da dbTree padrão implementado os métodos necessários para o seu dia a dia. Experimente criar a sua. CLASS RB_dbTree FROM dbTREE.
Você dizendo fico até feliz, pois foi exatamente o que tinha feito. Extendi a classe DBTree criando o atributo aIdPai, que é um vetor com o currentNodeId do nó atual e do nó pai, se você permitir eu posto o fonte aqui para compartilhar. Só está com um problema na hora que vou instanciar que não está identificando o o atributo no construtor.
Excluir#include "totvs.ch"
Excluir/***************************************************************
****************************************************************
Classe TExTree
Arvore Extendida para tratar o avanço entre os nós filhos e
relacionar um nó filho com o nó pai
Criado por: Renato de Bianchi
Em: 25/04/2012
****************************************************************
***************************************************************/
user function TExTree
return
class TExTree from DbTree
data aIdPai //ID do nó pai
method New(nTop,nLeft,nBottom,nRight,oWnd,bChange,bRClick,lCargo,lDisable,oFont) constructor //Construtor
method GoToUp() //Posiciona nó pai do nó posicionado
method GoToTop() //Posiciona nó raiz do nó selecionado
method GetNumSon() //Obtêm o número de nós filhos de um nó selecionado
//Metodos sobreescritos
method AddItem(cPrompt,cCargo,cRes1,cRes2,cFile1,cFile2,nTipo)
method AddTree(cPrompt,lOpened,cRes1,cRes2,cFile1,cFile2,cCargo)
method AddTreeItem(cPrompt,cRes,cFile,cCargo)
method DelItem()
endClass
method New(nTop,nLeft,nBottom,nRight,oWnd,bChange,bRClick,lCargo,lDisable,oFont) class TExTree
:New(nTop,nLeft,nBottom,nRight,oWnd,bChange,bRClick,lCargo,lDisable,oFont)
::aIdPai := {}
return SELF
method GetNumSon() class TExTree
local nSon := 0
local nTotNode := len(aIdPai)
local cSeekID := SELF:CurrentNodeId
if nTotNode > 1
for nI := 1 to nTotNode
if ::aIdPai[nI,1] == cSeekID
nSon++
endIf
next
endIf
return nSon
method GoToUp() class TExTree
nPos := aScan(::aIdPai, {|x| x[2]==SELF:CurrentNodeID} )
if nPos > 0
if ::aIdPai != nil .and. ::aIdPai[nPos,1] != "" .and. ::aIdPai[nPos,1] != " "
SELF:ptGotoToNode(::aIdPai[nPos,1])
endIf
endIf
return nil
method GoToTop() class TExTree
nPos := aScan(::aIdPai, {|x| x[2]==SELF:CurrentNodeID} )
if nPos > 0
while ::aIdPai != nil .and. ::aIdPai[nPos,1] != "" .and. ::aIdPai[nPos,1] != " "
SELF:GoToUp()
nPos := aScan(::aIdPai, {|x| x[2]==SELF:CurrentNodeID} )
endDo
endIf
return nil
method AddItem(cPrompt,cCargo,cRes1,cRes2,cFile1,cFile2,nTipo) class TExTree
:AddItem(cPrompt,cCargo,cRes1,cRes2,cFile1,cFile2,nTipo)
cIdPai := SELF:CurrentNodeId
SELF:TreeSeek(cCargo)
aAdd(::aIdPai, {cIdPai, SELF:CurrentNodeId})
return
method AddTree(cPrompt,lOpened,cRes1,cRes2,cFile1,cFile2,cCargo) class TExTree
:AddTree(cPrompt,lOpened,cRes1,cRes2,cFile1,cFile2,cCargo)
SELF:TreeSeek(cCargo)
aAdd(::aIdPai, {" ", SELF:CurrentNodeId})
return
method AddTreeItem(cPrompt,cRes,cFile,cCargo) class TExTree
:AddTreeItem(cPrompt,cRes,cFile,cCargo)
cIdPai := SELF:CurrentNodeId
SELF:TreeSeek(cCargo)
aAdd(::aIdPai, {cIdPai, SELF:CurrentNodeId})
return
method DelItem() class TExTree
cIdDel := SELF:CurrentNodeId
_Super:Método()
aDel(::aIdPai, aScan(::aIdPai, {|x| x[2]==cIdDel} ) )
return
Naldo, vc chegou a fazer um teste com o fonte acima?
ExcluirÉ necessário alterar o trecho:
_Super:Método() para _Super:DelItem()
Mas não sei se a classe DbTree é diferente ou está marcada como final, pois ela não identifica o atributo que eu incluo e não sobrescreve os métodos, se possível faça um teste com o código acima por favor.
Obrigado
Renato, tem um "gatinho" na dbTree que não permite a herança direta. Então, depois de muito tentar, resolvi pera herança indireta. Exemplo no blog.
ExcluirNaldo, boa TARDE
ResponderExcluirEssa tela do seu editor de fontes , com um fundo preto, e letras coloridas, voce teria esse template, para me enviar.
somente para fujir do padrão de Editor. Sei que daria para configurar, porem , se tivesse um template seria mais rapido.
abs