---- 1. Conseils pour utiliser les contrôles d'arborescence dans Delphi
---- Nous savons tous que les développeurs utilisent principalement Delphi pour développer des logiciels de gestion de bases de données. Pour cette raison, l'utilisation de contrôles arborescents est mieux liée à la base de données. Delphi fournit un contrôle arborescent TTreeView, qui peut être utilisé pour décrire des relations hiérarchiques complexes.
---- 1. Stockage et chargement des informations sur les nœuds de l'arborescence
---- Les méthodes couramment utilisées consistent à utiliser les méthodes LoadFromFile et SavetoFile du contrôle arborescent pour réaliser l'interaction entre le contrôle arborescent et le fichier ou à utiliser la méthode Assign pour réaliser l'interaction entre le contrôle arborescent et DBMemo ; , l'interaction avec la base de données. L'avantage de cette méthode est que la programmation est relativement simple. L'inconvénient est que le nombre réel de nœuds du contrôle d'arborescence peut être très important pour les "grands arbres", la quantité de données chargées et stockées à chaque fois augmentera, ce qui augmentera. réduisez la vitesse, augmentez la surcharge du système et provoquez une redondance des données. Une autre méthode consiste à générer uniquement des nœuds « visibles » dans l'arborescence. Il n'y a pas de champ de fichier ou de base de données dédié à l'enregistrement de la structure entière des nœuds de l'arborescence, et la structure des nœuds de l'arborescence est dispersée dans chaque enregistrement de la base de données.
---- La méthode spécifique est : créer une base de données, les champs sont déterminés en fonction de l'activité réelle, il doit y avoir un champ dont les informations seront affichées sur le nœud du contrôle de l'arborescence, et il y a aussi un champ pour enregistrer le numéro d'identification unique du nœud. Le numéro d'identification se compose de deux parties de longueur égale. La première partie représente le numéro de nœud parent du nœud actuel, et la dernière partie représente le numéro de nœud du nœud actuel. une "liste chaînée" qui enregistre la structure des nœuds de l'arborescence. Avantages de cette méthode : Lorsque les utilisateurs exploitent un « grand arbre », ils ne développent généralement pas tous les nœuds, mais n'en utilisent qu'une partie limitée. En même temps, ils ne peuvent étendre que couche par couche à partir de la racine de l'arborescence. La méthode génère uniquement "" sur l'arborescence. Les nœuds "visibles", par conséquent, la vitesse de stockage et de chargement des "grands arbres" est rapide, la quantité de données est faible et la surcharge du système et la redondance des données sont faibles. Inconvénients : La programmation est plus compliquée, mais cette méthode peut être combinée pour former un nouveau contrôle arborescent, ce qui améliorera considérablement l'efficacité de la programmation. Il convient de noter que le numéro d’identification doit être unique. Il est donc particulièrement important de savoir comment générer raisonnablement l’identifiant en programmation.
---- 2. Exemple de structure de base de données
----Créer une base de données Pour simplifier la procédure, je crée uniquement deux champs de base de données, définis comme suit :
Longueur du type de nom de champ
TexteC10
LongIDC6
----Le champ LongID se compose en fait de deux segments, chaque segment comporte 3 chiffres. LongID ne peut représenter que 1 000 enregistrements. Définissez LongID comme champ d'index et enregistrez-le sous c: esttree ree.dbf. Modifiez le fichier DBF, créez un nouvel enregistrement, définissez le champ Texte sur TOP et définissez le champ LongID sur "000" (trois espaces avant trois "0").
---- 3. Créez un programme de démonstration
---- Placez TreeView1, Table1, PopupMenu1, Edit1 et Edit2 sur Form1. L'attribut PopupMenu de TreeView1 est défini sur PopupMenu1 ; l'attribut DataBaseName de Table1 est défini sur c:esttree, l'attribut TableName est défini sur tree.dbf et l'attribut IndexFieldNames est défini sur LongID ; ajoutez des éléments uniques Add1 et Del1 à PopupMenu1 ; et Légende sont respectivement Ajouter et Suppr ; Edit1 utilise Pour saisir la valeur de l'attribut Texte du nouveau nœud, Edit2 est utilisé pour saisir le numéro d'identification à 3 chiffres du nouveau nœud. Enregistrez sous c:esttree reeunit.pas et c:esttree esttree.dPR. Ajoutez une ligne après le mot-clé Type dans treeunit.pas : Pstr:^string;{Pstr est un pointeur de chaîne} Ajoutez du code pour l'événement OnCreate de Form1 :
procédure TForm1.FormCreate(Expéditeur : TObject);
var p:Pstr;Noeud:TTreeNode;
commencer
avec Table1,Treeview1 faire
commencer
ouvrir;
d'abord;
new(p);{Allouer de la mémoire pour le pointeur p}
p^:=FieldByName(′LongID′).AsString;
Noeud :=Items.AddChildObject(nil,FieldByName
(′Texte′).AsString,p);
si HasSubInDbf (Node) alors éléments
.AddChildObject(Node,′ ′,nil);{S'il y a un nœud enfant, ajoutez un nœud enfant vide}
fin;
fin;
---- HasSubInDbf est une fonction personnalisée, la variable indépendante est Node, vérifie si le nœud Node a des nœuds enfants, renvoie True s'il y en a, sinon renvoie False et ajoute une déclaration de prototype à la définition de classe de TForm1 (les prototypes de d'autres fonctions personnalisées sont également déclarées dans la définition de classe de TForm1 sans autre explication), le code de la fonction est le suivant :
function TForm1.HasSubInDbf(Node:TTreeNode):Boolean;
commencer
avec Table1 faire
commencer
Table1.FindNearest([copy(Pstr(Node.Data)^,4,3)+′000′]);
result:=copy(FieldByName(′LongID′).
AsString,1,3)=copy(Pstr(Node.Data)^,4,3);
{Par exemple, la somme des trois premiers chiffres du contenu du champ LongID de l'enregistrement actuel dans la base de données
Si les trois derniers chiffres des données du nœud Node sont les mêmes, alors le nœud doit avoir des nœuds enfants}
fin;
fin;
Ajoutez du code pour l'événement OnDeletion du contrôle TreeView1. Il convient de souligner que :
Non seulement l'événement OnDeletion peut être déclenché en appelant la méthode Delete, mais également avant que le contrôle arborescent lui-même ne soit libéré,
L'événement OnDeletion est également déclenché, il est donc "sûr" d'ajouter dispose(node.data) ici :
procédure TForm1.TreeView1Deletion
(Expéditeur : TObject ; Nœud : TTreeNode) ;
commencer
Dispose(Node.Data);{Libérer la mémoire des données du nœud}
fin;
Ajoutez le code suivant à l'événement OnClick de l'élément de menu Add1 :
procédure TForm1.Add1Click(Expéditeur : TObject);
var p:pstr;Tmpstr:chaîne;i:entier;
commencer
essayer
StrVersInt(Edit2.Text);
Tmpstr:=Edit2.Text;{Remarque : en pratique, une meilleure méthode doit être utilisée pour générer l'ID}
sauf;
ShowMessage('Entrez à nouveau le contenu de Edit2');
avorter;
fin;
avec TreeView1 faire
commencer
nouveau(p);
p^:=copie(Pstr(Selected.Data)^,4,3)+TmpStr;
Items.AddChildObject(Selected,Edit1.Text,p);
fin;
avec Table1 do{Ajouter un enregistrement dans la base de données}
commencer
Ajouter;
FieldByName(′Text′).AsString:=Edit1.text;
FieldByName(′LongID′).AsString:=p^;
Poste;
fin;
TmpStr:=inttostr(strtoint(TmpStr)+1);
pour i:=length(TmpStr) à 2, faites TmpStr:=′0′+TmpStr;
Edit2.Text:=TmpStr;
fin;
Ajoutez le code suivant à l'événement OnClick de l'élément de menu Del1 :
procédure TForm1.Del1Click(Expéditeur : TObject);
var DelList:TStringList;LongID,NSubLongID:string;
commencer
DelList:=TStringList.create;
DelList.Sorted:=True;
DelList.Add(Pstr(TreeView1.Selected.Data)^);
tandis que DelList.Count>0 fait
commencer
LongID:=DelList.Strings[0];
DelList.Delete(0);
Tableau1.SetKey ;
Table1.FieldByName(′LongID′).AsString:=LongID;
si Table1.GotoKey alors Table1.Delete ;
si HasSubInDbf (TreeView1.Selected) alors
commencer
NSubLongID:=Table1.FieldByName(′LongID′).AsString;
while (copie(NSubLongID,1,3)=copie
(LongID,4,3))et(pas Table1.Eof) font
commencer
dellist.Add(NSubLongId);
Tableau1.Suivant ;
NSubLongId:=Table1.FieldByName(′LongID′).AsString;
fin;
fin;
fin;
DelList.Free;
TreeView1.Items.Delete(TreeView1.Selected);
fin;
Ajoutez du code pour l'événement OnExpanding de TreeView1 :
procédure TForm1.TreeView1Expanding
(Expéditeur : TObject ; Nœud : TTreeNode ;
var AllowExpansion : booléen);
var TmpNode:TTreeNode;NSubLongID :
Chaîne;p:Pstr;bm:TBookMark;
commencer
avec Table1, TreeView1 faire
commencer
Articles.BeginUpdate;
Définir la clé ;
FieldByName(′LongID′).AsString:=Pstr(Node.Data)^;
sinon GotoKey alors Items.Delete (Nœud)
autre
commencer
TmpNode:=Node.GetFirstChild;
si (TmpNode.Text=′ ′)et (TmpNode.Data=nil) alors
commencer
TmpNode.Delete;
si HasSubInDbf (nœud) alors
commencer
NSubLongID:=FieldByName(′LongID′).AsString;
while (copie(NSubLongID,1,3)=copie(Pstr
(Node.Data)^,4,3))et(pas Eof) font
commencer
nouveau(p);
p^:=FieldByName(′LongID′).AsString;
bm:=GetBookMark;
TmpNode:=Items.AddChildObject(Nœud,
FieldByName(′Text′).AsString,p);
si HasSubInDbf (TmpNode) alors éléments.
AddChildObject(TmpNode,′ ′,nil);
Aller àBookMark(bm);
FreeBookMark(bm);
Suivant;
NSubLongId:=FieldByName(′LongID′).AsString;
fin; fin; fin;
fin;
Items.EndUpdate;
fin;
fin;
---- Ce qui précède parle brièvement de la méthode de base d'affichage de l'arborescence de la base de données. De plus, lors de la modification de l'attribut Texte du nœud dans l'arborescence, la base de données est modifiée en même temps lorsque la même base de données est exploitée. plusieurs utilisateurs en même temps, la cohérence de la base de données et de l'arborescence, et la copie et la réplication de l'arborescence du nœud supérieur ne seront pas décrites en détail, et les lecteurs peuvent l'améliorer par eux-mêmes.
---- 2. Utilisation du contrôle IP
---- Dans les programmes réseau, nous rencontrons souvent des situations où les utilisateurs doivent saisir des adresses IP. Cependant, Delphi ne nous fournit pas de contrôle pouvant être utilisé pour saisir la chaîne IP, nous devons donc utiliser le contrôle Tedit (zone de texte sur une seule ligne) pour accepter la chaîne IP saisie par l'utilisateur. Cependant, utiliser Tedit pour saisir une chaîne IP n’est pas une bonne idée car c’est très peu pratique à gérer. En fait, il y a un contrôle Windows à côté de nous spécifiquement pour saisir les chaînes IP. Le contrôle IP rejettera les chaînes IP illégales (seuls les nombres compris entre 0 et 255 peuvent être saisis dans chaque partie) ; cela vous permet d'obtenir facilement la valeur IP (entier 32 bits) correspondant à la chaîne IP dans le contrôle ; vous évite d'avoir à convertir entre les chaînes IP et les valeurs IP ; en outre, vous pouvez également limiter la plage d'adresses IP pouvant être saisies dans le contrôle IP. Cette section présente comment utiliser les contrôles IP Windows dans notre programme Delphi.
---- Il existe deux bibliothèques de liens dynamiques très importantes dans Windows : commctrl.dll et comctl32.dll, qui sont les bibliothèques de contrôles personnalisés de Windows (Windows Common Controls). La bibliothèque de contrôles personnalisés contient de nombreux contrôles Windows couramment utilisés, tels que Statusbar, Coolbar, HotKey, etc. dans Delphi, la plupart de ces contrôles ont été regroupés sous forme de contrôles visuels. Après que Microsoft a lancé Internet Explorer 3, de nouveaux contrôles ont été ajoutés à la bibliothèque de contrôles personnalisés, notamment le contrôle IP Windows (contrôle d'édition d'adresse IP).
---- 1. Initialiser la bibliothèque de contrôles personnalisés Windows
---- Windows fournit deux fonctions API, InitCommonControls et InitCommonControlsEx, pour initialiser les bibliothèques de contrôles personnalisés. D’après les noms, il n’est pas difficile de voir la relation entre ces deux fonctions API : la dernière est une amélioration de la première. Si vous souhaitez utiliser des contrôles IP dans votre programme, vous devez utiliser InitCommonControlsEx pour terminer l'initialisation des bibliothèques et classes de contrôles personnalisés. Le prototype de la fonction InitCommonControlsEx est le suivant (syntaxe Pascal) :
... ...
Créer un contrôle IP
... ...
Utilisez les contrôles IP. Dans le programme, nous communiquons avec le contrôle IP en lui envoyant des messages.
Le contrôle IP peut répondre aux six messages suivants. Ces messages et leurs significations sont indiqués dans le tableau ci-dessous :
... ...
Si vous souhaitez obtenir la valeur IP correspondant à la chaîne IP dans le contrôle IP, vous devez envoyer
IPM_GETADDRESS et nécessite une adresse entière de 32 bits comme
Le dernier paramètre de SendMessage.
... ...
---- 2. Message de notification du contrôle IP
---- Lorsque la chaîne IP est modifiée ou que le focus d'entrée est transféré, le contrôle IP enverra le message de notification IPN_FIELDCHANGED à sa fenêtre parent. Dans la plupart des cas, nous pouvons ignorer ce message de notification. Voici un exemple de gestion du message de notification IPN_FIELDCHANGED :
procédure Tform1.WndProc(var Msg: TMessage);
var p:PNMHDR;
commencer
hérité;
si Msg.Msg=WM_NOTIFY
puis commence
p:=Pointeur(Msg.lParam);
si p^.code=IPN_FIELDCHANGED
puis commence
{…
Gestion du message de notification IPN_FIELDCHANGED du contrôle IP
…}
fin;
fin;
fin;
---- 3. Méthodes et applications de génération dynamique de contrôles
---- 1.Deux méthodes pour générer des contrôles dans Delphi
---- (1). Générer des contrôles dans la conception de formulaire.
---- Lors de la conception d'un formulaire, il est courant de sélectionner directement le contrôle requis dans la boîte à outils de contrôle, puis de définir ses propriétés et de répondre aux événements.
---- (2). Générer dynamiquement des contrôles dans le programme.
---- Parfois, nous devons générer dynamiquement des contrôles lorsque le programme est en cours d'exécution. Cela présente deux avantages majeurs : premièrement, cela peut augmenter la flexibilité du programme, deuxièmement, si le nombre de contrôles générés est lié aux résultats intermédiaires en cours d'exécution ; du programme, évidemment la première méthode ne peut pas être réalisée et la méthode de génération dynamique du programme doit être utilisée.
---- La méthode de génération dynamique des contrôles dans le programme est divisée en trois étapes. Tout d'abord, définissez le type de contrôle généré, puis utilisez la fonction Créer pour générer le contrôle, et enfin attribuez des valeurs aux propriétés pertinentes du contrôle. contrôle. En prenant le contrôle TButton comme exemple, les étapes sont les suivantes :
---- a. Définir le type de contrôle
var
Bouton1 : TBouton ;
---- b. Générer des contrôles
Button1:=TButton.Create(self);
Button1.Parent:=Soi;
//En général, définissez son contrôle parent sur Self. Si la valeur de Parent n'est pas définie,
alors le contrôle ne sera pas sur l'écran
//l'affiche
---- c. Définissez d'autres propriétés et définissez les fonctions de réponse aux événements associées, telles que les fonctions de réponse aux événements Légende, Gauche, Haut, Hauteur, Largeur, Visible, Activé, Hint et onClick, etc.
---- 2. Application de la méthode de contrôle générée dynamiquement
---- Dans le développement de systèmes de planification et de gestion de la production, il est nécessaire de générer dynamiquement des diagrammes de planification de la production, représentés par des diagrammes de Gantt, et il est très utile d'utiliser des contrôles Shape pour afficher l'état de traitement des pièces (l'heure de début du traitement et heure de fin de chaque processus). A l'aide du champ Graphique, l'utilisation des équipements de traitement est affichée dans un histogramme tridimensionnel, très intuitif. Nous allons maintenant expliquer le processus de génération dynamique du contrôle Shape et du contrôle Chart dans le programme.
---- (1). Générer dynamiquement un contrôle de forme pour afficher le diagramme du plan de planification de la production (diagramme de Gantt).
procédure TCreateMultiCharts.ProcCreateCharts ;
var
i, j, lignes, colonnes, espace de lignes, hauteur des graphiques : entier ;
ShapeChart : tableau de tableaux de TShape ;
commencer
Rows:=16; //Le nombre de lignes dans le tableau de contrôle Shape
Colonnes :=8 ; //Numéro de colonne du tableau de contrôle de forme
RowSpace:=20; // Espacement des lignes de contrôle de forme
ChartsHeight:=20; // Hauteur du contrôle de forme
SetLength (ShapeChart, Lignes, Colonnes);
//Définit la taille du tableau ShapeChart
pour i:=0 aux lignes faire
pour j:=0 aux colonnes faire
commencer
ShapeChart[i][j]:=TShape.Create(self);
avec ShapeChart[i,j] faire
commencer
Parent:=Self; //Cette ligne est essentielle,
Dans le cas contraire, le champ Forme ne s'affichera pas à l'écran.
Shape:=stRectangle; // La forme du contrôle de forme est un rectangle
Haut :=45+i*(RowSpace+ChartsHeight);
Gauche :=Round(180+Q[i,j].StartTime);
//Comme Q[i,j].StartTime est un nombre réel, il doit être arrondi.
Largeur : = Rond (Q[i,j].Valeur)
Hauteur :=Hauteur des graphiques ;
Brush.Color:=RandomColor;
//Fonction personnalisée, les instructions sont jointes
Brush.Style:=bsSolid; //Définit la méthode de remplissage
Activé :=Vrai ;
fin;
fin;
fin;
---- Remarque : aQ est un tableau bidimensionnel de type enregistrement, défini comme suit :
taper
TempData=Enregistrement
Valeur : réelle ;
Heure de début : réel ;
fin;
Q : tableau de tableaux de TempData
Et les composantes de Q ont reçu des valeurs dans un autre processus.
---- b. Afin de distinguer les différentes parties, la forme est affichée dans différentes couleurs. A ce moment, la fonction RandomColor est appelée. La fonction est :
fonction TCreateMultiCharts.RandomColor ;
var
rouge, vert, bleu : octet ;
commencer
rouge : = aléatoire (255) ;
vert : = aléatoire (255) ;
bleu : = aléatoire (255) ;
résultat : = rouge ou (vert shl 8) ou (bleu shl 16) ;
fin;
---- (2). Générez dynamiquement le composant ChartSeries du contrôle Charts pour afficher l'utilisation de l'appareil.
procédure TFormMultiMachinesBurthen.
Afficher les graphiques de charge de machine ;
var
je:Entier;
Fardeau : Réel ;
SeriesClass : TChartSeriesClass ;
NewSeries : tableau de TChartSeries ;
commencer
SetLength(NewSeries,CreateMultiCharts.Rows);
MachinesBurthenCharts.hauteur :=200 ;
MachinesBurthenCharts.Width :=550 ;
pour i:=0 à CreateMultiCharts.Rows
commencer
SeriesClass:=TBarSeries; //Définit la forme sur un graphique à barres tridimensionnel
NewSeries[i]:=SeriesClass.Create(Self);
NewSeries[i].ParentChart:=MachinesBurthenCharts;
NouvelleSérie[i].Clair;
Burthen:=MachineBurthen[i];
Burthen:=Round(Burthen*100)/100; //Ne prend que deux chiffres après la virgule
NewSeries[i].add(Burthen,',NewSeries[i].SeriesColor);
fin;
fin;
---- Remarque : (a).MachineBurthen[i] est un tableau réel, sa valeur est l'utilisation du périphérique correspondant, qui a été calculée dans une autre fonction ;
---- (b). MachinesBurthenCharts est un contrôle TChart, décrit dans la section type.
---- 3. Affichage des résultats de l'exécution du programme
---- (1) Générer dynamiquement un champ Forme pour afficher le plan d'ordonnancement des pièces (omis).
---- (2) Générer dynamiquement le composant ChartSeries du contrôle Chart et afficher l'utilisation de l'appareil (omis).