---- 1. Consejos para usar controles de árbol en Delphi
---- Todos sabemos que los desarrolladores utilizan principalmente Delphi para desarrollar software de administración de bases de datos. Debido a esto, el uso de controles de árbol está mejor vinculado a la base de datos. Delphi proporciona un control de árbol TTreeView, que se puede utilizar para describir relaciones jerárquicas complejas.
---- 1. Almacenamiento y carga de información de nodos de árbol
---- Los métodos más utilizados son utilizar los métodos LoadFromFile y SavetoFile del control de árbol para realizar la interacción entre el control de árbol y el archivo o utilizar el método Assign para realizar la interacción entre el control de árbol y DBMemo; , la interacción con la base de datos. La ventaja de este método es que la programación es relativamente simple. La desventaja es que el número real de nodos del control del árbol puede ser muy grande. Para los "árboles grandes", la cantidad de datos cargados y almacenados aumentará cada vez, lo que aumentará. reduce la velocidad, aumenta la sobrecarga del sistema y provoca redundancia de datos. Otro método es generar solo nodos "visibles" en el árbol. No hay ningún archivo o campo de base de datos dedicado a registrar toda la estructura de nodos del árbol, y la estructura de nodos del árbol está dispersa en cada registro de la base de datos.
---- El método específico es: crear una base de datos, los campos se determinan de acuerdo con el negocio real, debe haber un campo cuya información se mostrará en el nodo del control de árbol, y también hay un campo para guardar el Número de identificación único del nodo. El número de identificación consta de dos partes de igual longitud. La primera parte representa el número de nodo principal del nodo actual y la última parte representa el número de nodo del nodo actual. una "lista enlazada" que registra la estructura de los nodos en el árbol. Ventajas de este método: cuando los usuarios operan un "árbol grande", generalmente no expanden todos los nodos, sino que solo usan una parte limitada. Al mismo tiempo, solo pueden expandirse capa por capa desde la raíz del árbol. El método solo genera "" en el árbol. Nodos "visibles", por lo que la velocidad de almacenamiento y carga de "árboles grandes" es rápida, la cantidad de datos es pequeña y la sobrecarga del sistema y la redundancia de datos son pequeñas. Desventajas: la programación es más complicada, pero este método se puede combinar para formar un nuevo control de árbol, lo que mejorará en gran medida la eficiencia de la programación. Vale la pena señalar que el número de identificación debe ser único, por lo que es particularmente importante cómo generar la identificación de manera razonable en la programación.
---- 2. Ejemplo de estructura de base de datos
----Crear una base de datos Para simplificar el procedimiento, solo creo dos campos de base de datos, definidos de la siguiente manera:
Longitud del tipo de nombre de campo
TextoC10
LargoIDC6
----El campo LongID en realidad consta de dos segmentos, cada segmento tiene 3 dígitos. LongID solo puede representar 1000 registros. Defina LongID como un campo de índice y guárdelo como c: esttree ree.dbf. Edite el archivo DBF, cree un nuevo registro, establezca el campo Texto en ARRIBA y establezca el campo LongID en "000" (tres espacios antes de tres "0").
---- 3. Cree un programa de demostración
---- Coloque TreeView1, Table1, PopupMenu1, Edit1 y Edit2 en Form1. El atributo PopupMenu de TreeView1 se establece en PopupMenu1; el atributo DataBaseName de Table1 se establece en c: esttree, el atributo TableName se establece en tree.dbf y el atributo IndexFieldNames se establece en LongID; agregue elementos individuales Add1 y Del1 a PopupMenu1; y Título es Agregar y Del respectivamente; Edit1 usa Para ingresar el valor del atributo Texto del nuevo nodo, Edit2 se usa para ingresar el número de identificación de 3 dígitos del nuevo nodo. Guárdelo como c:esttree reeunit.pas y c:esttree esttree.dPR. Agregue una línea después de la palabra clave Type en treeunit.pas: Pstr:^string;{Pstr es un puntero de cadena} Agregue código para el evento OnCreate de Form1:
procedimiento TForm1.FormCreate(Remitente: TObject);
var p:Pstr;Nodo:TTreeNode;
comenzar
con Table1, Treeview1 hacer
comenzar
abierto;
primero;
new(p);{Asignar memoria para el puntero p}
p^:=FieldByName(′LongID′).AsString;
Nodo:=Items.AddChildObject(nil,FieldByName
(′Texto′).AsString,p);
si HasSubInDbf (Nodo) entonces Elementos
.AddChildObject(Node,′ ′,nil);{Si hay un nodo secundario, agregue un nodo secundario vacío}
fin;
fin;
---- HasSubInDbf es una función personalizada, la variable independiente es Node, verifica si el nodo Node tiene nodos secundarios, devuelve True si los hay; de lo contrario, devuelve False y agrega una declaración de prototipo a la definición de clase de TForm1 (los prototipos de Otras funciones personalizadas también se declaran en la definición de clase de TForm1 sin más explicaciones), el código de la función es el siguiente:
función TForm1.HasSubInDbf(Nodo:TTreeNode):Booleano;
comenzar
con la Tabla 1 hacer
comenzar
Table1.FindNearest([copy(Pstr(Node.Data)^,4,3)+′000′]);
resultado:=copiar(FieldByName(′LongID′).
AsString,1,3)=copiar(Pstr(Node.Data)^,4,3);
{Por ejemplo, la suma de los primeros tres dígitos del contenido del campo LongID del registro actual en la base de datos
Si los últimos tres dígitos de los datos del nodo son iguales, entonces el nodo debe tener nodos secundarios}
fin;
fin;
Agregar código para el evento OnDeletion del control TreeView1 Cabe señalar que,
El evento OnDeletion no solo se puede activar llamando al método Delete, sino también antes de que se libere el control del árbol.
El evento OnDeletion también se activa, por lo que es "seguro" agregar dispose(node.data) aquí:
procedimiento TForm1.TreeView1Deletion
(Remitente: TObject; Nodo: TTreeNode);
comenzar
Dispose(Node.Data);{Liberar memoria de datos del nodo}
fin;
Agregue el siguiente código al evento OnClick del elemento de menú Add1:
procedimiento TForm1.Add1Click (Remitente: TObject);
var p:pstr;Tmpstr:cadena;i:entero;
comenzar
intentar
StrToInt(Editar2.Texto);
Tmpstr:=Edit2.Text;{Nota: en la práctica, se debe utilizar un método mejor para generar ID}
excepto;
ShowMessage('Vuelva a ingresar el contenido de Edit2');
abortar;
fin;
con TreeView1 hacer
comenzar
nuevo(p);
p^:=copiar(Pstr(Datos.Seleccionados)^,4,3)+TmpStr;
Items.AddChildObject(Seleccionado,Editar1.Texto,p);
fin;
con la Tabla1 haz {Agregar registro en la base de datos}
comenzar
Añadir;
FieldByName(′Text′).AsString:=Edit1.text;
FieldByName(′LongID′).AsString:=p^;
Correo;
fin;
TmpStr:=inttostr(strtoint(TmpStr)+1);
para i:=length(TmpStr) a 2 haga TmpStr:=′0′+TmpStr;
Edit2.Text:=TmpStr;
fin;
Agregue el siguiente código al evento OnClick del elemento de menú Del1:
procedimiento TForm1.Del1Click(Remitente: TObject);
var DelList:TStringList;LongID,NSubLongID:cadena;
comenzar
DelList:=TStringList.create;
DelList.Sorted:=Verdadero;
DelList.Add(Pstr(TreeView1.Selected.Data)^);
mientras que DelList.Count>0 lo hace
comenzar
LongID:=DelList.Strings[0];
DelList.Delete(0);
Tabla1.SetKey;
Table1.FieldByName(′LongID′).AsString:=LongID;
si Table1.GotoKey entonces Table1.Delete;
si HasSubInDbf (TreeView1.Selected) entonces
comenzar
NSubLongID:=Table1.FieldByName(′LongID′).AsString;
mientras (copiar(NSubLongID,1,3)=copiar
(LongID,4,3))y(no Table1.Eof) no
comenzar
dellist.Add(NSubLongId);
Tabla 1.Siguiente;
NSubLongId:=Table1.FieldByName(′LongID′).AsString;
fin;
fin;
fin;
DelList.Gratis;
TreeView1.Items.Delete(TreeView1.Selected);
fin;
Agregue código para el evento OnExpanding de TreeView1:
procedimiento TForm1.TreeView1Expanding
(Remitente: TObject; Nodo: TTreeNode;
var AllowExpansion: booleano);
var TmpNode:TTreeNode;NSubLongID:
Cadena;p:Pstr;bm:TBookMark;
comenzar
con Table1, TreeView1 hacer
comenzar
Artículos.BeginUpdate;
Establecer clave;
FieldByName(′LongID′).AsString:=Pstr(Node.Data)^;
si no es GotoKey, entonces Items.Delete(Node)
demás
comenzar
TmpNode:=Nodo.GetFirstChild;
si (TmpNode.Text=′ ′)y(TmpNode.Data=nil) entonces
comenzar
TmpNode.Delete;
si HasSubInDbf(Nodo) entonces
comenzar
NSubLongID:=FieldByName(′LongID′).AsString;
mientras (copiar(NSubLongID,1,3)=copiar(Pstr
(Node.Data)^,4,3))y(no Eof) lo hacen
comenzar
nuevo(p);
p^:=FieldByName(′LongID′).AsString;
bm:=GetBookMark;
TmpNode:=Items.AddChildObject(Nodo,
FieldByName(′Text′).AsString,p);
si HasSubInDbf(TmpNode) entonces Elementos.
AddChildObject(TmpNode,′ ′,nil);
Ir a BookMark(bm);
FreeBookMark(bm);
Próximo;
NSubLongId:=FieldByName(′LongID′).AsString;
fin; fin; fin;
fin;
Artículos.EndUpdate;
fin;
fin;
---- Lo anterior habla brevemente sobre el método básico de visualización del árbol de la base de datos. Además, al editar el atributo de texto del nodo en el árbol, la base de datos se modifica al mismo tiempo. múltiples usuarios al mismo tiempo, la consistencia de la base de datos y el árbol, y el árbol La copia y replicación del nodo superior no se describirá en detalle, y los lectores pueden mejorarlo por sí mismos.
---- 2. Uso del control de ip
---- En los programas de red, a menudo nos encontramos con situaciones en las que los usuarios deben ingresar direcciones IP. Sin embargo, Delphi no nos proporciona un control que pueda usarse para ingresar la cadena IP, por lo que tenemos que usar el control Tedit (cuadro de texto de una sola línea) para aceptar la cadena IP ingresada por el usuario. Sin embargo, usar Tedit para ingresar una cadena de IP no es una buena idea ya que es muy incómodo de manejar. De hecho, hay un control de Windows a nuestro lado específicamente para ingresar cadenas de IP. El control de IP rechazará cadenas de IP ilegales (solo se pueden ingresar números entre 0 y 255 en cada parte, lo que le permite obtener fácilmente el valor de IP (entero de 32 bits) correspondiente a la cadena de IP en el control. le ahorra la molestia de convertir entre cadenas de IP y valores de IP; además, también puede limitar el rango de IP que se pueden ingresar en el control de IP; Esta sección presenta cómo usar los controles IP de Windows en nuestro programa Delphi.
---- Hay dos bibliotecas de enlaces dinámicos muy importantes en Windows: commctrl.dll y comctl32.dll, que son bibliotecas de controles personalizados de Windows (Controles comunes de Windows). La biblioteca de controles personalizados contiene muchos controles de Windows de uso común, como Statusbar, Coolbar, HotKey, etc. en Delphi, la mayoría de estos controles se han empaquetado como controles visuales. Después de que Microsoft lanzó Internet Explorer 3, se agregaron algunos controles nuevos a la biblioteca de controles personalizados, incluido el control IP de Windows (control de edición de dirección IP).
---- 1. Inicialice la biblioteca de controles personalizados de Windows
---- Windows proporciona dos funciones API, InitCommonControls e InitCommonControlsEx, para inicializar bibliotecas de controles personalizados. Por los nombres, no es difícil ver la relación entre estas dos funciones API: la última es una mejora de la primera. Si desea utilizar controles de IP en su programa, debe utilizar InitCommonControlsEx para completar la inicialización de bibliotecas y clases de controles personalizados. El prototipo de la función InitCommonControlsEx es el siguiente (sintaxis Pascal):
... ...
Crear control de IP
... ...
Utilice controles de IP. En el programa, nos comunicamos con el control de IP enviándole mensajes.
El control de IP puede responder a los siguientes seis mensajes. Estos mensajes y sus significados se muestran en la siguiente tabla:
... ...
Si desea obtener el valor de IP correspondiente a la cadena de IP en el control de IP, debe enviar
mensaje IPM_GETADDRESS y requiere una dirección entera de 32 bits como
El último parámetro de SendMessage.
... ...
---- 2. Mensaje de notificación de control de IP
---- Cuando se cambia la cadena de IP o se transfiere el foco de entrada, el control de IP enviará el mensaje de notificación IPN_FIELDCHANGED a su ventana principal. En la mayoría de los casos, podemos ignorar este mensaje de notificación. El siguiente es un ejemplo de manejo del mensaje de notificación IPN_FIELDCHANGED:
procedimiento Tform1.WndProc(var Msg: TMessage);
varp:PNMHDR;
comenzar
heredado;
si Msg.Msg=WM_NOTIFY
entonces comienza
p:=Puntero(Msg.lParam);
si p^.code=IPN_FIELDCHANGED
entonces comienza
{…
Manejo del mensaje de notificación IPN_FIELDCHANGED del control de IP
…}
fin;
fin;
fin;
---- 3. Métodos y aplicaciones de controles generados dinámicamente.
---- 1.Dos métodos para generar controles en Delphi
---- (1). Generar controles en el diseño de formularios.
---- Al diseñar un formulario, es común seleccionar directamente el control requerido en la caja de herramientas de control, luego configurar sus propiedades y responder a los eventos.
---- (2). Generar controles dinámicamente en el programa.
---- A veces, necesitamos generar controles dinámicamente cuando el programa se está ejecutando. Esto tiene dos ventajas principales: en primer lugar, puede aumentar la flexibilidad del programa, en segundo lugar, si la cantidad de controles generados está relacionada con los resultados de ejecución intermedios; del programa, obviamente el método uno no se puede implementar y se debe utilizar el método de generación dinámica en el programa.
---- El método de generación dinámica de controles en el programa se divide en tres pasos: primero, defina el tipo de control generado, luego use la función Crear para generar el control y finalmente asigne valores a las propiedades relevantes del. control. Tomando el control TButton como ejemplo, los pasos son los siguientes:
---- a. Definir el tipo de control.
var
Botón1:TBotón;
---- b. Generar controles
Botón1:=TButton.Create(self);
Botón1.Padre:=Yo;
// Generalmente, establezca su control principal en Self. Si el valor de Parent no está establecido,
entonces el control no estará en la pantalla
// mostrarlo
---- c. Establezca otras propiedades y defina funciones de respuesta a eventos relacionadas, como Título, Izquierda, Superior, Alto, Ancho, Visible, Habilitado, Sugerencia y funciones de respuesta a eventos al hacer clic, etc.
---- 2. Aplicación del método de control generado dinámicamente
---- En el desarrollo de sistemas de gestión y programación de producción, es necesario generar dinámicamente gráficos de programación de producción, representados por diagramas de Gantt, y es muy útil utilizar controles de Forma para mostrar el estado de procesamiento de las piezas (la hora de inicio del procesamiento). y hora de finalización de cada proceso). Al utilizar el control Gráfico, la utilización del equipo de procesamiento se muestra en un histograma tridimensional, lo cual es muy intuitivo. Ahora explicaremos el proceso de generar dinámicamente el control de Forma y el control de Gráfico en el programa.
---- (1). Generar dinámicamente un control de forma para mostrar el gráfico del plan de programación de producción (diagrama de Gantt).
procedimiento TCreateMultiCharts.ProcCreateCharts;
var
i,j,Filas,Columnas,Espacio entre filas,Altura del gráfico:Entero;
ShapeChart:matriz de matriz de TShape;
comenzar
Filas:=16; //El número de filas en la matriz de control Forma
Columnas:=8; //Número de columna de la matriz de control de forma
RowSpace:=20; // Control de forma del espaciado entre filas
ChartsHeight:=20 // Altura del control de forma
EstablecerLongitud(Gráfico de formas,Filas,Columnas);
//Establece el tamaño de la matriz ShapeChart
para i:=0 a las filas
para j:=0 a las columnas
comenzar
ShapeChart[i][j]:=TShape.Create(self);
con ShapeChart[i,j] hacer
comenzar
Parent:=Self; //Esta línea es esencial,
De lo contrario, el control Forma no se mostrará en la pantalla.
Shape:=stRectangle // La forma de control de forma es rectángulo
Arriba:=45+i*(RowSpace+ChartsHeight);
Izquierda:=Round(180+Q[i,j].StartTime);
//Debido a que Q[i,j].StartTime es un número real, es necesario redondearlo.
Ancho:=Redondo(Q[i,j].Valor)
Altura:=AlturaGráficos;
Pincel.Color:=ColorAleatorio;
//Función personalizada, se adjuntan instrucciones
Brush.Style:=bsSolid //Establece el método de relleno
Habilitado:=Verdadero;
fin;
fin;
fin;
---- Nota: aQ es una matriz bidimensional de tipo registro, definida de la siguiente manera:
tipo
TempData=Registro
Valor:Real;
Hora de inicio:Real;
fin;
P: matriz de matriz de TempData
Y a los componentes de Q se les han asignado valores en otro proceso.
---- b. Para distinguir diferentes partes, Shape se muestra en diferentes colores. En este momento, se llama a la función RandomColor. La función es:
función TCreateMultiCharts.RandomColor;
var
rojo, verde, azul: byte;
comenzar
rojo:=aleatorio(255);
verde:=aleatorio(255);
azul:=aleatorio(255);
resultado:=rojo o (verde shl 8) o (azul shl 16);
fin;
---- (2) Genere dinámicamente el componente ChartSeries del control Charts para mostrar la utilización del dispositivo.
procedimiento TFormMultiMachinesBurthen.
MostrarMachineBurthenCharts;
var
i:Entero;
Carga: Real;
Clase de serie: TChartSeriesClass;
NewSeries: conjunto de TChartSeries;
comenzar
SetLength(NewSeries,CreateMultiCharts.Rows);
MáquinasBurthenCharts.height:=200;
MáquinasBurthenCharts.Width:=550;
para i:=0 para CreateMultiCharts.Rows hacer
comenzar
SeriesClass:=TBarSeries //Establece la forma en un gráfico de barras tridimensional;
NewSeries[i]:=SeriesClass.Create(Self);
NewSeries[i].ParentChart:=MachinesBurthenCharts;
Nueva Serie[i].Claro;
Carga:=MáquinaBurthen[i];
Burthen:=Round(Burthen*100)/100 //Toma solo dos dígitos después del punto decimal
NewSeries[i].add(Burthen,',NewSeries[i].SeriesColor);
fin;
fin;
---- Nota: (a).MachineBurthen[i] es una matriz real, su valor es la utilización del dispositivo correspondiente, que ha sido calculado en otra función;
---- (b). MachinesBurthenCharts es un control TChart, descrito en la sección de tipos.
---- 3. Visualización del resultado de ejecución del programa
---- (1) Generar dinámicamente un control Forma para mostrar el plan de programación de piezas (omitido)
---- (2) Genere dinámicamente el componente ChartSeries del control Chart y muestre la utilización del dispositivo (omitido).