---- 1. Dicas para usar controles de árvore no Delphi
---- Todos nós sabemos que os desenvolvedores usam Delphi principalmente para desenvolver software de gerenciamento de banco de dados. Por causa disso, o uso de controles de árvore está melhor vinculado ao banco de dados. Delphi fornece um controle de árvore TTreeView, que pode ser usado para descrever relacionamentos hierárquicos complexos.
---- 1. Armazenamento e carregamento de informações do nó da árvore
---- Os métodos comumente usados são usar os métodos LoadFromFile e SavetoFile do controle de árvore para realizar a interação entre o controle de árvore e o arquivo ou usar o método Assign para realizar a interação entre o controle de árvore e o DBMemo; , a interação com o banco de dados. A vantagem deste método é que a programação é relativamente simples. A desvantagem é que o número real de nós do controle da árvore pode ser muito grande. Para "árvores grandes", a quantidade de dados carregados e armazenados aumentará a cada vez. reduza a velocidade, aumente a sobrecarga do sistema e cause redundância de dados. Outro método é gerar apenas nós "visíveis" na árvore. Não há arquivo ou campo de banco de dados dedicado ao registro de toda a estrutura do nó da árvore, e a estrutura do nó da árvore está dispersa em cada registro do banco de dados.
---- O método específico é: criar um banco de dados, os campos são determinados de acordo com o negócio real, deve haver um campo cujas informações serão exibidas no nó do controle da árvore, e também existe um campo para salvar o número de identificação exclusivo do nó O número de identificação consiste em duas partes de igual comprimento. A primeira parte representa o número do nó pai do nó atual e a última parte representa o número do nó atual. uma "lista vinculada" que registra a estrutura dos nós da árvore. Vantagens deste método: Quando os usuários operam uma "árvore grande", eles geralmente não expandem todos os nós, mas usam apenas uma parte limitada. Ao mesmo tempo, eles só podem expandir camada por camada a partir da raiz da árvore. O método gera apenas "" nos nós "visíveis" da árvore, portanto, a velocidade de armazenamento e carregamento de "árvores grandes" é rápida, a quantidade de dados é pequena e a sobrecarga do sistema e a redundância de dados são pequenas. Desvantagens: A programação é mais complicada, mas este método pode ser combinado para formar um novo controle de árvore, o que melhorará muito a eficiência da programação. É importante notar que o número de ID deve ser único, portanto, como gerar o ID de maneira razoável na programação é particularmente importante.
---- 2. Exemplo de estrutura de banco de dados
----Criar um banco de dados Para simplificar o procedimento, crio apenas dois campos de banco de dados, definidos da seguinte forma:
Comprimento do tipo de nome de campo
TextoC10
LongIDC6
----O campo LongID na verdade consiste em dois segmentos, cada segmento tem 3 dígitos e pode representar apenas 1000 registros. Defina LongID como um campo de índice e salve-o como c:esttree ree.dbf. Edite o arquivo DBF, crie um novo registro, defina o campo Texto como TOP e defina o campo LongID como “000” (três espaços antes de três “0”).
---- 3. Crie um programa de demonstração
---- Coloque TreeView1, Table1, PopupMenu1, Edit1 e Edit2 no Form1. O atributo PopupMenu de TreeView1 é definido como PopupMenu1; o atributo DataBaseName de Table1 é definido como c: esttree, o atributo TableName é definido como tree.dbf e o atributo IndexFieldNames é definido como LongID, adicione itens únicos Add1 e Del1 a PopupMenu1, e Legenda são Add e Del respectivamente; Edit1 usa Para inserir o valor do atributo Text do novo nó, Edit2 é usado para inserir o número de ID de 3 dígitos do novo nó. Salve como c:esttree reeunit.pas e c:esttree esttree.dPR. Adicione uma linha após a palavra-chave Type em treeunit.pas: Pstr:^string;{Pstr é um ponteiro de string} Adicione o código para o evento OnCreate do Form1:
procedimento TForm1.FormCreate(Remetente: TObject);
var p:Pstr;Node:TTreeNode;
começar
com Tabela1, Treeview1 faça
começar
abrir;
primeiro;
new(p);{Alocar memória para o ponteiro p}
p^:=FieldByName(′LongID′).AsString;
Nó:=Items.AddChildObject(nil,FieldByName
(′Texto′).AsString,p);
se HasSubInDbf(Node) então Itens
.AddChildObject(Node,′ ′,nil);{Se houver um nó filho, adicione um nó filho vazio}
fim;
fim;
---- HasSubInDbf é uma função personalizada, a variável independente é Node, verifique se o nó Node possui nós filhos, retorne True se houver, caso contrário, retorne False e adicione uma declaração de protótipo à definição de classe de TForm1 (os protótipos de outras funções personalizadas também são declaradas na definição de classe do TForm1 sem maiores explicações), o código da função é o seguinte:
função TForm1.HasSubInDbf(Node:TTreeNode):Boolean;
começar
com Tabela1 faça
começar
Tabela1.FindNearest([copy(Pstr(Node.Data)^,4,3)+′000′]);
resultado:=copiar(FieldByName(′LongID′).
AsString,1,3)=copiar(Pstr(Node.Data)^,4,3);
{Por exemplo, a soma dos três primeiros dígitos do conteúdo do campo LongID do registro atual no banco de dados
Se os últimos três dígitos dos dados do nó Nó forem iguais, então o nó deverá ter nós filhos}
fim;
fim;
Adicione código para o evento OnDeletion do controle TreeView1. Deve-se ressaltar que,
O evento OnDeletion não só pode ser acionado chamando o método Delete, mas também antes que o próprio controle da árvore seja liberado,
O evento OnDeletion também é acionado, por isso é "seguro" adicionar destroy(node.data) aqui:
procedimento TForm1.TreeView1Deletion
(Remetente: TObject; Nó: TTreeNode);
começar
Dispose(Node.Data);{Liberar memória de dados do nó}
fim;
Adicione o seguinte código ao evento OnClick do item de menu Add1:
procedimento TForm1.Add1Click(Remetente: TObject);
var p:pstr;Tmpstr:string;i:integer;
começar
tentar
StrToInt(Edit2.Text);
Tmpstr:=Edit2.Text;{Nota: Na prática, um método melhor deve ser usado para gerar ID}
exceto;
ShowMessage('Digite novamente o conteúdo do Edit2');
abortar;
fim;
com TreeView1 faça
começar
novo(p);
p^:=copiar(Pstr(Dados Selecionados)^,4,3)+TmpStr;
Items.AddChildObject(Selecionado,Edit1.Texto,p);
fim;
com Tabela1 do{Adicionar registro no banco de dados}
começar
Acrescentar;
FieldByName(′Text′).AsString:=Edit1.text;
FieldByName(′LongID′).AsString:=p^;
Publicar;
fim;
TmpStr:=inttostr(strtoint(TmpStr)+1);
para i:=length(TmpStr) até 2 faça TmpStr:=′0′+TmpStr;
Edit2.Text:=TmpStr;
fim;
Adicione o seguinte código ao evento OnClick do item de menu Del1:
procedimento TForm1.Del1Click(Remetente: TObject);
var DelList:TStringList;LongID,NSubLongID:string;
começar
DelList:=TStringList.create;
DelList.Sorted:=Verdadeiro;
DelList.Add(Pstr(TreeView1.Selected.Data)^);
enquanto DelList.Count>0 faz
começar
LongID:=DelList.Strings[0];
DelList.Delete(0);
Tabela1.SetKey;
Tabela1.FieldByName(′LongID′).AsString:=LongID;
se Table1.GotoKey então Table1.Delete;
se HasSubInDbf (TreeView1.Selected) então
começar
NSubLongID:=Tabela1.FieldByName(′LongID′).AsString;
enquanto (copiar(NSubLongID,1,3)=copiar
(LongID,4,3))e(não Tabela1.Eof) faça
começar
dellist.Add(NSubLongId);
Tabela1.Próximo;
NSubLongId:=Tabela1.FieldByName(′LongID′).AsString;
fim;
fim;
fim;
DelList.Free;
TreeView1.Items.Delete(TreeView1.Selected);
fim;
Adicione o código para o evento OnExpanding de TreeView1:
procedimento TForm1.TreeView1Expanding
(Remetente: TObject; Nó: TTreeNode;
var AllowExpansion: Boolean);
var TmpNode:TTreeNode;NSubLongID:
String;p:Pstr;bm:TBookMark;
começar
com Table1, TreeView1 faça
começar
Itens.BeginUpdate;
Definirchave;
FieldByName(′LongID′).AsString:=Pstr(Node.Data)^;
se não for GotoKey, então Items.Delete (Nó)
outro
começar
TmpNode:=Node.GetFirstChild;
se (TmpNode.Text=′ ′)e(TmpNode.Data=nil) então
começar
TmpNode.Delete;
se HasSubInDbf(Nó) então
começar
NSubLongID:=FieldByName(′LongID′).AsString;
enquanto (copiar(NSubLongID,1,3)=copiar(Pstr
(Node.Data)^,4,3))e(não Eof) faça
começar
novo(p);
p^:=FieldByName(′LongID′).AsString;
bm:=GetBookMark;
TmpNode:=Items.AddChildObject(Nó,
FieldByName(′Text′).AsString,p);
se HasSubInDbf(TmpNode) então Itens.
AddChildObject(TmpNode,′ ′,nil);
GotoBookMark(bm);
FreeBookMark(bm);
Próximo;
NSubLongId:=FieldByName(′LongID′).AsString;
fim; fim;
fim;
Itens.EndUpdate;
fim;
fim;
---- O texto acima fala brevemente sobre o método básico de exibição em árvore do banco de dados. Além disso, ao editar o atributo Texto do nó na árvore, o banco de dados é modificado ao mesmo tempo. vários usuários ao mesmo tempo, a consistência do banco de dados e da árvore, e a árvore A cópia e replicação do nó superior não serão descritas em detalhes, e os leitores podem melhorá-la por conta própria.
---- 2. Uso de controle de IP
---- Em programas de rede, frequentemente encontramos situações em que os usuários são obrigados a inserir endereços IP. No entanto, o Delphi não nos fornece um controle que possa ser usado para inserir a string IP, então temos que usar o controle Tedit (caixa de texto de linha única) para aceitar a string IP inserida pelo usuário. No entanto, usar o Tedit para inserir uma string IP não é uma boa ideia, pois é muito inconveniente de manusear. Na verdade, existe um controle do Windows ao nosso lado especificamente para inserir strings de IP. O controle IP rejeitará strings IP ilegais (apenas números entre 0..255 podem ser inseridos em cada parte); permite obter facilmente o valor IP (inteiro de 32 bits) correspondente à string IP no controle. evita o trabalho de conversão entre strings de IP e valores de IP; além disso, você também pode limitar o intervalo de IPs que podem ser inseridos no controle de IP; Esta seção apresenta como usar os controles IP do Windows em nosso programa Delphi.
---- Existem duas bibliotecas de links dinâmicos muito importantes no Windows: commctrl.dll e comctl32.dll, que são bibliotecas de controle personalizadas do Windows (Windows Common Controls). A biblioteca de controles personalizados contém muitos controles comumente usados do Windows, como Statusbar, Coolbar, HotKey, etc. no Delphi, a maioria desses controles foram empacotados como controles visuais. Depois que a Microsoft lançou o Internet Explorer 3, alguns novos controles foram adicionados à biblioteca de controles personalizados, incluindo o controle IP do Windows (controle de edição de endereço IP).
---- 1. Inicialize a biblioteca de controle personalizada do Windows
---- O Windows fornece duas funções de API, InitCommonControls e InitCommonControlsEx, para inicializar bibliotecas de controle personalizadas. Pelos nomes, não é difícil perceber a relação entre essas duas funções da API: a última é um aprimoramento da primeira. Se quiser usar controles IP em seu programa, você deverá usar InitCommonControlsEx para concluir a inicialização de bibliotecas e classes de controle customizadas. O protótipo da função InitCommonControlsEx é o seguinte (sintaxe Pascal):
... ...
Criar controle de IP
... ...
Use controles de IP. No programa, nos comunicamos com o controle IP enviando mensagens para ele.
O controle IP pode responder às seis mensagens a seguir. Essas mensagens e seus significados são mostrados na tabela abaixo:
... ...
Se você deseja obter o valor IP correspondente à string IP no controle IP, você deve enviar
Mensagem IPM_GETADDRESS e requer um endereço inteiro de 32 bits como
O último parâmetro de SendMessage.
... ...
---- 2. Mensagem de notificação de controle de IP
---- Quando a string IP é alterada ou o foco de entrada é transferido, o controle IP enviará a mensagem de notificação IPN_FIELDCHANGED para sua janela pai. Na maioria dos casos, podemos ignorar esta mensagem de notificação. A seguir está um exemplo de tratamento da mensagem de notificação IPN_FIELDCHANGED:
procedimento Tform1.WndProc(var Msg: TMessage);
var p:PNMHDR;
começar
herdado;
se Msg.Msg=WM_NOTIFY
então comece
p:=Ponteiro(Msg.lParam);
se p^.code=IPN_FIELDCHANGED
então comece
{…
Tratamento da mensagem de notificação IPN_FIELDCHANGED do controle IP
…}
fim;
fim;
fim;
---- 3. Métodos e aplicações de geração dinâmica de controles
---- 1.Dois métodos para gerar controles em Delphi
---- (1). Gere controles no design do formulário.
---- Ao projetar um Formulário, é comum selecionar diretamente o controle necessário na caixa de ferramentas de controle, definir suas propriedades e responder aos eventos.
---- (2). Gerar controles dinamicamente no programa.
---- Às vezes, precisamos gerar controles dinamicamente quando o programa está em execução. Isso tem duas vantagens principais: primeiro, pode aumentar a flexibilidade do programa, segundo, se o número de controles gerados estiver relacionado aos resultados intermediários da execução; do programa, obviamente o método um não pode ser realizado e o método de geração dinâmica no programa deve ser usado.
---- O método de geração dinâmica de controles no programa é dividido em três etapas. Primeiro, defina o tipo de controle gerado, depois use a função Criar para gerar o controle e, finalmente, atribua valores às propriedades relevantes do. controlar. Tomando o controle TButton como exemplo, as etapas são as seguintes:
---- a. Definir tipo de controle
var
Botão1:Botão;
---- b. Gerar controles
Botão1:=TButton.Create(self);
Button1.Parent:=Próprio;
//Geralmente, defina seu controle pai como Self. Se o valor de Parent não for definido,
então o controle não estará na tela
//exibi-lo
---- c. Defina outras propriedades e defina funções de resposta de evento relacionadas, como funções de resposta de evento Caption, Left, Top, Height, Width, Visible, Enabled, Hint e onClick, etc.
---- 2. Aplicação do método de controle gerado dinamicamente
---- No desenvolvimento de sistemas de programação e gerenciamento de produção, é necessário gerar dinamicamente gráficos de programação de produção, representados por gráficos de Gantt, e é muito útil usar controles Shape para exibir o status de processamento das peças (o horário de início do processamento e hora de término de cada processo). Utilizando o controle Gráfico, a utilização dos equipamentos de processamento é apresentada em um histograma tridimensional, muito intuitivo. Agora explicaremos o processo de geração dinâmica de controle Shape e controle Chart no programa.
---- (1). Gere dinamicamente o controle Shape para exibir o gráfico do plano de programação de produção (gráfico de Gantt)
procedimento TCreateMultiCharts.ProcCreateCharts;
var
i,j,Linhas,Colunas,RowSpace,ChartsHeight:Integer;
ShapeChart: array de array de TShape;
começar
Rows:=16; //O número de linhas na matriz de controle Shape
Columns:=8; //Forma o número da coluna da matriz de controle
RowSpace:=20; // Espaçamento entre linhas de controle de forma
ChartsHeight:=20; // Altura do controle de forma
SetLength(FormaGráfico,Linhas,Colunas);
//Define o tamanho do array do ShapeChart
para i:=0 para linhas fazer
para j:=0 para Colunas faça
começar
ShapeChart[i][j]:=TShape.Create(self);
com ShapeChart[i,j] do
começar
Parent:=Self; //Esta linha é essencial,
Caso contrário, o controle Shape não será exibido na tela.
Shape:=stRectangle; // A forma do controle de forma é retângulo
Superior:=45+i*(RowSpace+ChartsHeight);
Esquerda:=Rodada(180+Q[i,j].StartTime);
//Como Q[i,j].StartTime é um número real, ele precisa ser arredondado.
Largura:=Rodada(Q[i,j].Valor)
Altura:=Altura do Gráfico;
Brush.Color:=Cor aleatória;
//Função personalizada, instruções estão anexadas
Brush.Style:=bsSolid; //Definir o método de preenchimento
Habilitado:=Verdadeiro;
fim;
fim;
fim;
---- Nota: aQ é uma matriz bidimensional do tipo registro, definida da seguinte forma:
tipo
TempData = Registro
Valor:Real;
Hora de Início:Real;
fim;
Q: array de array de TempData
E os componentes de Q receberam valores em outro processo.
---- b. Para distinguir diferentes partes, Shape é exibido em cores diferentes. Neste momento, a função RandomColor é chamada. A função é:
função TCreateMultiCharts.RandomColor;
var
vermelho, verde, azul: byte;
começar
vermelho:=aleatório(255);
verde:=aleatório(255);
azul:=aleatório(255);
resultado:=vermelho ou (shl verde 8) ou (shl azul 16);
fim;
---- (2). Gere dinamicamente o componente ChartSeries do controle Charts para exibir a utilização do dispositivo.
procedimento TFormMultiMachinesBurthen.
ShowMachineBurthenCharts;
var
eu:Inteiro;
Burthen:Real;
SeriesClass:TChartSeriesClass;
NewSeries:array de TChartSeries;
começar
SetLength(NewSeries,CreateMultiCharts.Rows);
MáquinasBurthenCharts.height:=200;
MáquinasBurthenCharts.Width:=550;
para i:=0 para CreateMultiCharts.Rows fazer
começar
SeriesClass:=TBarSeries; //Define a forma para um gráfico de barras tridimensional
NewSeries[i]:=SeriesClass.Create(Self);
NewSeries[i].ParentChart:=MachinesBurthenCharts;
Nova série[i].Limpar;
Burthen:=MáquinaBurthen[i];
Burthen:=Round(Burthen*100)/100; //Leva apenas dois dígitos após a vírgula decimal
NewSeries[i].add(Burthen,',NewSeries[i].SeriesColor);
fim;
fim;
---- Nota: (a).MachineBurthen[i] é um array real, seu valor é a utilização do dispositivo correspondente, que foi calculado em outra função;
---- (b). MachinesBurthenCharts é um controle TChart, descrito na seção de tipos.
---- 3. Exibição do resultado da execução do programa
---- (1) Gere dinamicamente um controle Shape para exibir o plano de programação de peças (omitido).
---- (2). Gere dinamicamente o componente ChartSeries do controle Chart e exiba a utilização do dispositivo (omitido)