Winforms - 列表框项目悬停并选择颜色。

问题描述 投票:0回答:1

我正在重写一个程序,一切都很顺利,但现在我遇到了一个问题。我正在重写的程序是wpf,我在winforms中工作,程序中有一个列表框,我不能那么容易地重新创建 :( 下面是列表框的图片,其中有一个选中的项目。选择的项目

正如你所看到的,选中的项目会变成蓝色,而它的边框则是另一种蓝色,当你停止关注表单时,它将变成白色。白色的项目

而你悬停的项目会变成蓝色,但更淡一些。悬停项目

谢谢你的帮助

顺便说一下,我使用的是.NET框架4.8。

c# visual-studio winforms listbox
1个回答
1
投票

你可以从原来的列表框中派生出自己的列表框。一旦新的列表第一次被编译,它将出现在工具箱中,这样你就可以把它拖放到你的表格中。或者你可以将现有列表框的类型改为 ListBoxEx 在Form.designer.cs中手动改变列表框的外观。

public class ListBoxEx : ListBox
{
    public ListBoxEx()
    {
        DrawMode = DrawMode.OwnerDrawFixed;
        DoubleBuffered = true; // Eliminates flicker (optional).
    }

    private int _hotTrackedIndex = -1;
    private int HotTrackedIndex
    {
        get => _hotTrackedIndex;
        set {
            if (value != _hotTrackedIndex) {
                if (_hotTrackedIndex >= 0 && _hotTrackedIndex < Items.Count) {
                    Invalidate(GetItemRectangle(_hotTrackedIndex));
                }
                _hotTrackedIndex = value;
                if (_hotTrackedIndex >= 0) {
                    Invalidate(GetItemRectangle(_hotTrackedIndex));
                }
            }
        }
    }

    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        var borderRect = e.Bounds;
        borderRect.Width--;
        borderRect.Height--;
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) {
            if (Focused) {
                e.Graphics.FillRectangle(Brushes.Teal, e.Bounds);
                e.Graphics.DrawRectangle(Pens.LightSkyBlue, borderRect);
            } else {
                e.Graphics.FillRectangle(Brushes.DimGray, e.Bounds);
                e.Graphics.DrawRectangle(Pens.White, borderRect);
            }
        } else if (e.Index == HotTrackedIndex) {
            e.Graphics.FillRectangle(Brushes.DarkSlateGray, e.Bounds);
            e.Graphics.DrawRectangle(Pens.DarkCyan, borderRect);
        } else {
            e.DrawBackground();
        }
        if (Items[e.Index] != null) {
            e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, Brushes.White, 6, e.Bounds.Top, StringFormat.GenericTypographic);
        }
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        HotTrackedIndex = -1;
        base.OnMouseLeave(e);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        HotTrackedIndex = IndexFromPoint(e.Location);
        base.OnMouseMove(e);
    }

    protected override void OnGotFocus(EventArgs e)
    {
        if (SelectedIndex >= 0) {
            RefreshItem(SelectedIndex);
        }
        base.OnGotFocus(e);
    }

    protected override void OnLostFocus(EventArgs e)
    {
        if (SelectedIndex >= 0) {
            RefreshItem(SelectedIndex);
        }
        base.OnLostFocus(e);
    }
}

我们通过重写 OnDrawItem在构造函数中,我们设置 DrawMode = DrawMode.OwnerDrawFixed; 以实现所有者绘图。

我们必须考虑选中的项目和热跟踪的项目,即鼠标移动到的项目。如果要绘制的项目是选中的项目,我们进一步区分列表框是否有焦点的情况。

FillRectangle 绘制背景。DrawRectangle 绘制边框。请注意,边框必须比列表框的边框小一个像素。e.Bounds 矩形,否则将不会绘制右侧和底部的边框。

如果当前项目没有被选中,我们测试它是否被热跟踪。如果是,我们用不同的颜色绘制。否则,我们用 e.DrawBackground();.

然后我们在背景上用 DrawString.


为了使所有这些都能正常工作,我们还必须使列表框中颜色变化的区域无效。我们检测热跟踪的变化,在 OnMouseMoveOnMouseLeave. 我们在那里设置了 HotTrackedIndex. 这是一个在必要时触发绘图的属性。

OnGotFocusOnLostFocus 我们刷新选定的项目,根据焦点状态改变其颜色。


我的颜色与你的图像不匹配,但你可以很容易地调整它们。如果你需要创建非标准颜色的笔刷和钢笔,那么要么将它们创建为静态和只读,要么就不要忘记处置它们。

private static readonly Brush HotTrackBrush = new SolidBrush(new Color(123, 45, 67));
private static readonly Pen HotTrackPen = new Pen(new Color(234, 56, 78));

这个列表框的改进版本可以将不同的选择和热跟踪颜色作为属性暴露出来,这样你就可以在属性窗口中轻松地改变它们。属性会自动出现在那里)。

© www.soinside.com 2019 - 2024. All rights reserved.