web-dev-qa-db-fra.com

C # WinForms met en évidence le treenode lorsque l'arborescence n'a pas le focus

Gretings.

Je fais une interface pour éditer des scénarios pour un jeu. Fondamentalement, il se compose d'événements, qui ont des conditions et des actions imbriquées. J'ai donc prévu d'utiliser deux arborescences - une pour sélectionner l'événement, et l'autre pour sélectionner la condition/action à l'intérieur de l'événement à modifier.

Maintenant, vous voyez, si je sélectionne un événement (dans l'arborescence de gauche) et que j'essaie ensuite de sélectionner quelque chose dans l'arborescence de droite, l'arborescence de gauche cessera d'afficher le rectangle de sélection bleu. C'est évidemment mauvais car maintenant l'utilisateur ne sait pas quel événement est en train de modifier!

Le seul moyen que j'ai trouvé pour conserver une sorte d'information sur la sélection actuelle est d'utiliser SelectedImageIndex, mais c'est une seule petite image qui sera différente.

Existe-t-il un autre moyen de mettre en surbrillance le treenode alors qu'il n'y a pas de focus sur l'arborescence? Je sais que je peux simplement Graphics.DrawRectangle ou quelque chose, mais j'ai entendu que le dessin devrait être fait dans l'événement Paint et l'arborescence n'a pas d'événement Paint ... Donc je suppose que si je le dessine en cas de perte de focus, puis faites glisser le formulaire hors de l'écran ou quelque chose, il sera "effacé"?

Quoi qu'il en soit, dites-moi si vous avez une idée (autre que l'utilisation d'une icône distincte pour le treenode sélectionné et non sélectionné)

Merci!

29
Istrebitel

Ce que vous recherchez est la propriété HideSelection sur le TreeView.

À partir de MSDN:

Obtient ou définit une valeur indiquant si le nœud d'arbre sélectionné reste en surbrillance même lorsque l'arborescence a perdu le focus.

Lien: http://msdn.Microsoft.com/en-us/library/system.windows.forms.treeview.hideselection.aspx

Code:

TreeView.HideSelection = false;
58
aKzenT

Il est toujours affiché mais uniquement en gris clair qui, selon votre écran et la configuration actuelle, peut être presque visible!

Substituez l'événement OnDrawNode. Vous créez donc une nouvelle classe (appelez-la "SpecialTreeView") héritée de Microsoft TreeView comme class SpecialTreeView : TreeView. Ensuite, vous ajoutez le remplacement d'événement suivant:

protected override void OnDrawNode(DrawTreeNodeEventArgs e)
{
    TreeNodeStates treeState = e.State;
    Font treeFont = e.Node.NodeFont ?? e.Node.TreeView.Font;

    // Colors.
    Color foreColor = e.Node.ForeColor;
    string strDeselectedColor = @"#6B6E77", strSelectedColor = @"#94C7FC";
    Color selectedColor = System.Drawing.ColorTranslator.FromHtml(strSelectedColor);
    Color deselectedColor = System.Drawing.ColorTranslator.FromHtml(strDeselectedColor);

    // New brush.
    SolidBrush selectedTreeBrush = new SolidBrush(selectedColor);
    SolidBrush deselectedTreeBrush = new SolidBrush(deselectedColor);

    // Set default font color.
    if (foreColor == Color.Empty)
        foreColor = e.Node.TreeView.ForeColor;

    // Draw bounding box and fill.
    if (e.Node == e.Node.TreeView.SelectedNode)
    {
        // Use appropriate brush depending on if the tree has focus.
        if (this.Focused)
        {
            foreColor = SystemColors.HighlightText;
            e.Graphics.FillRectangle(selectedTreeBrush, e.Bounds);
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, foreColor, SystemColors.Highlight);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
                                         foreColor, TextFormatFlags.GlyphOverhangPadding);
        }
        else
        {
            foreColor = SystemColors.HighlightText;
            e.Graphics.FillRectangle(deselectedTreeBrush, e.Bounds);
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, foreColor, SystemColors.Highlight);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
                                         foreColor, TextFormatFlags.GlyphOverhangPadding);
        }
    }
    else
    {
        if ((e.State & TreeNodeStates.Hot) == TreeNodeStates.Hot)
        {
            e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, hotFont, e.Bounds,
                                         System.Drawing.Color.Black, TextFormatFlags.GlyphOverhangPadding);
        }
        else
        {
            e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
                                         foreColor, TextFormatFlags.GlyphOverhangPadding);
        }
    }
}

Compilez le code et vous devriez voir "SpecialTreeView" dans votre boîte à outils dans le concepteur. Remplacez votre TreeView par celui-ci en utilisant le même nom et la seule chose qui sera différente est les couleurs de sélection. Lorsqu'il est sélectionné, ce sera selectedColor, lorsqu'il n'est pas sélectionné, le deselectedColor.

J'espère que ça aide.

16
MoonKnight

Solution rapide:

Définissez les propriétés:

  • HideSelection = false;
  • DrawMode = TreeViewDrawMode.OwnerDrawText;

Ensuite, dans le gestionnaire d'événements DrawNode, faites simplement:

private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) {
  e.DrawDefault = true;
}

Sur Windwos 7, cela restaure l'ancien rendu, y compris la zone en pointillés autour de la sélection (qui semble en fait un peu dépassée). Le texte sera blanc avec mise au point et noir sans mise au point. Le fond reste bleu et visible.

Cette réponse n'est pas nouvelle, les autres contiennent également ces étapes, mais c'est le minimum nécessaire (au moins dans Windows 7, n'a pas testé d'autres systèmes d'exploitation).

9
Louis Somers

Pas une solution absolument parfaite, mais assez proche:

treeView.HideSelection = false;
treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;
treeView.DrawNode += (o, e) =>
{
    if (!e.Node.TreeView.Focused && e.Node == e.Node.TreeView.SelectedNode)
    {
        Font treeFont = e.Node.NodeFont ?? e.Node.TreeView.Font;
        e.Graphics.FillRectangle(Brushes.Gray, e.Bounds);
        ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, SystemColors.HighlightText, SystemColors.Highlight);
        TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
    }
    else
        e.DrawDefault = true;
};
treeView.MouseDown += (o, e) =>
{
    TreeNode node = treeView.GetNodeAt(e.X, e.Y);
    if (node != null && node.Bounds.Contains(e.X, e.Y))
        treeView.SelectedNode = node;
};
8
Bachor

Similaire à la précédente mais avec une apparence plus similaire à la norme Win10:

treeView.HideSelection = false;
treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;

treeView.DrawNode += (o, e) =>
{
    if (e.Node == e.Node.TreeView.SelectedNode)
    {
        Font font = e.Node.NodeFont ?? e.Node.TreeView.Font;
        Rectangle r = e.Bounds;
        r.Offset(0, 1);
        Brush brush = e.Node.TreeView.Focused ? SystemBrushes.Highlight : Brushes.Gray;
        e.Graphics.FillRectangle(brush, e.Bounds);
        TextRenderer.DrawText(e.Graphics, e.Node.Text, font, r, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
    }
    else
        e.DrawDefault = true;
};

treeView.MouseDown += (o, e) =>
{
    TreeNode node = treeView.GetNodeAt(e.Location);
    if (node != null && node.Bounds.Contains(e.Location)) treeView.SelectedNode = node;
};
1
Ivan

Trouvé un moyen plus simple:

  1. Définissez TreeView.HideSelection = True
  2. Ajoutez ce qui suit à TreeView.AfterSelect-Callback:
    private void treeViewBenutzerverwaltung_AfterSelect(object sender, TreeViewEventArgs e)
    {
        // Select new node
        e.Node.BackColor = SystemColors.Highlight;
        e.Node.ForeColor = SystemColors.HighlightText;
        if (_lastSelectedNode != null)
        {
            // Deselect old node
            _lastSelectedNode.BackColor = SystemColors.Window;
            _lastSelectedNode.ForeColor = SystemColors.WindowText;
        }
        lastSelectedNode = e.Node;
    }
    
0
Sam