Come aggiungere caselle di controllo e pulsanti di opzione a un TTreeView

Il componente TTreeView Delphi (situato nella scheda della tavolozza dei componenti “Win32”) rappresenta una finestra che visualizza un elenco gerarchico di elementi, come i titoli in un documento, le voci in un indice oi file e le directory su un disco.

Nodo albero con casella di controllo o pulsante di opzione?

TTreeview di Delphi non supporta nativamente le caselle di controllo, ma il controllo WC_TREEVIEW sottostante sì. È possibile aggiungere caselle di controllo alla visualizzazione ad albero sovrascrivendo la procedura CreateParams di TTreeView, specificando lo stile TVS_CHECKBOXES per il controllo. Il risultato è che tutti i nodi nella visualizzazione ad albero avranno delle caselle di controllo ad essi associate. Inoltre, la proprietà StateImages non può più essere utilizzata perché WC_TREEVIEW utilizza internamente questo elenco immagini per implementare le caselle di controllo. Se desideri attivare o disattivare le caselle di controllo, dovrai farlo utilizzando SendMessage o le macro TreeView_SetItem / TreeView_GetItem da CommCtrl.pas. WC_TREEVIEW supporta solo caselle di controllo, non pulsanti di opzione.

L’approccio che scoprirai in questo articolo è molto più flessibile: puoi avere caselle di controllo e pulsanti di opzione mescolati con altri nodi come preferisci senza cambiare TTreeview o creare una nuova classe da esso per farlo funzionare. Inoltre, decidi tu stesso quali immagini utilizzare per le caselle di controllo / pulsanti radio semplicemente aggiungendo le immagini appropriate all’elenco di immagini di StateImages.

Aggiungi una casella di controllo o un pulsante di opzione

Contrariamente a quanto potresti credere, questo è abbastanza semplice da realizzare in Delphi. Ecco i passaggi per farlo funzionare:

  1. Impostare un elenco di immagini (componente TImageList nella scheda della tavolozza dei componenti “Win32”) per la proprietà TTreeview.StateImages contenente le immagini per gli stati selezionati e deselezionati per le caselle di controllo e / o i pulsanti di opzione.
  2. Chiama la procedura ToggleTreeViewCheckBoxes (vedi sotto) negli eventi OnClick e OnKeyDown della visualizzazione ad albero. La procedura ToggleTreeViewCheckBoxes altera lo StateIndex del nodo selezionato per riflettere lo stato selezionato / deselezionato corrente.

Per rendere la tua visualizzazione ad albero ancora più professionale, dovresti controllare dove viene cliccato un nodo prima di attivare o disattivare le immagini di stato: attivando il nodo solo quando viene cliccata l’immagine effettiva, i tuoi utenti possono ancora selezionare il nodo senza cambiarne lo stato.

Inoltre, se non si desidera che gli utenti espandano / comprimano la visualizzazione ad albero, chiamare la procedura FullExpand nell’evento OnShow dei moduli e impostare AllowCollapse su false nell’evento OnCollapsing della visualizzazione ad albero.

Ecco l’implementazione della procedura ToggleTreeViewCheckBoxes:

procedura ToggleTreeViewCheckBoxes (
Nodo: TTreeNode;
cUnChecked,
cControllato,
cRadioUnchecked,
cRadioChecked: intero);
var
tmp: TTreeNode;
beginif Assegnato (nodo) thenbeginif Node.StateIndex = cUnChecked poi
Node.StateIndex: = cChecked
altro if Node.StateIndex = cChecked poi
Node.StateIndex: = cUnChecked
Altrimenti se Node.StateIndex = cRadioUnChecked quindi iniziare
tmp: = Node.Parent;
altrimenti Assegnato (tmp) poi
tmp: = TTreeView (Node.TreeView) .Items.getFirstNode
altro
tmp: = tmp.getFirstChild;
while Assegnato (tmp) dobeginif (tmp.StateIndex in
[cRadioUnChecked, cRadioChecked]) poi
tmp.StateIndex: = cRadioUnChecked;
tmp: = tmp.getNextSibling;
fine;
Node.StateIndex: = cRadioChecked;
fine; // se StateIndex = cRadioUnCheckedfine; // se assegnato (nodo)
fine; (* ToggleTreeViewCheckBoxes *)

Come puoi vedere dal codice sopra, la procedura inizia trovando i nodi delle caselle di controllo e semplicemente attivandoli o disattivandoli. Successivamente, se il nodo è un pulsante di opzione non selezionato, la procedura si sposta sul primo nodo del livello corrente, imposta tutti i nodi di quel livello su cRadioUnchecked (se sono nodi cRadioUnChecked o cRadioChecked) e infine commuta Node su cRadioChecked.

Notare come i pulsanti di opzione già selezionati vengono ignorati. Ovviamente, questo è perché un pulsante di opzione già selezionato verrebbe disattivato, lasciando i nodi in uno stato indefinito. Difficilmente quello che vorresti la maggior parte del tempo.

Ecco come rendere il codice ancora più professionale: nell’evento OnClick del Treeview, scrivi il codice seguente per attivare o disattivare le caselle di controllo solo se è stato cliccato lo stateimage (le costanti cFlatUnCheck, cFlatChecked ecc sono definite altrove come indici nell’elenco di immagini StateImages) :

procedura TForm1.TreeView1Click (Sender: TObject);
var
P: TPoint;
iniziare
GetCursorPos (P);
P: = TreeView1.ScreenToClient (P);
if (htOnStateIcon in
TreeView1.GetHitTestInfoAt (PX, PY)) poi
ToggleTreeViewCheckBoxes (
TreeView1.Selected,
cFlatUnCheck,
cFlatChecked,
cFlatRadioUnCheck,
cFlatRadioChecked);
fine; (* TreeView1Click *)

Il codice ottiene la posizione corrente del mouse, converte in coordinate treeview e controlla se è stato fatto clic su StateIcon chiamando la funzione GetHitTestInfoAt. In tal caso, viene chiamata la procedura di commutazione.

Principalmente, ti aspetteresti che la barra spaziatrice attivi o disattivi le caselle di controllo oi pulsanti di opzione, quindi ecco come scrivere l’evento TreeView OnKeyDown utilizzando quello standard:

procedura TForm1.TreeView1KeyDown (
Mittente: TObject;
var Key: Word;
Shift: TShiftState);
beginif (Chiave = VK_SPACE) e
Assegnato (TreeView1.Selected) poi
ToggleTreeViewCheckBoxes (
TreeView1.Selected,
cFlatUnCheck,
cFlatChecked,
cFlatRadioUnCheck,
cFlatRadioChecked);
fine; (* TreeView1KeyDown *)

Infine, ecco come potrebbero apparire gli eventi OnShow del modulo e OnChanging di Treeview se si desidera impedire il collasso dei nodi della visualizzazione ad albero:

procedura TForm1.FormCreate (Sender: TObject);
iniziare
TreeView1.FullExpand;
fine; (* FormCreate *)
procedura TForm1.TreeView1Collapsing (
Mittente: TObject;
Nodo: TTreeNode;
var AllowCollapse: Boolean);
iniziare
AllowCollapse: = false;
fine; (* TreeView1Collapsing *)

Infine, per verificare se un nodo è controllato, fai semplicemente il seguente confronto (nel gestore di eventi OnClick di un pulsante, ad esempio):

procedura TForm1.Button1Click (Sender: TObject);
var
BoolResult: boolean;
tn: TTreeNode;
beginif Assegnato (TreeView1.Selected) quindi iniziare
tn: = TreeView1.Selected;
BoolResult: = tn.StateIndex in
[cFlatChecked, cFlatRadioChecked];
Memo1.Text: = tn.Text +
# 13 # 10 +
"Selezionato:" +
BoolToStr (BoolResult, True);
fine;
fine; (* Button1Click *)

Sebbene questo tipo di codifica non possa essere considerato mission-critical, può dare alle tue applicazioni un aspetto più professionale e fluido. Inoltre, utilizzando le caselle di controllo ei pulsanti di opzione con giudizio, possono rendere l’applicazione più facile da usare. Di sicuro staranno bene!

L’immagine seguente è stata presa da un’app di prova utilizzando il codice descritto in questo articolo. Come puoi vedere, puoi combinare liberamente i nodi che hanno caselle di controllo o pulsanti di opzione con quelli che non ne hanno, sebbene non dovresti mescolare nodi “vuoti” con nodi “casella di controllo” (dai un’occhiata ai pulsanti di opzione nell’immagine) come questo rende molto difficile vedere quali nodi sono correlati.