【问题标题】:Winforms - Listbox item hover and select colorWinforms - 列表框项目悬停并选择颜色
【发布时间】:2020-08-19 01:39:02
【问题描述】:

我正在重新制作一个程序,一切都很顺利,但现在我遇到了问题。我正在重写的程序是 wpf 并且我在 winforms 中工作,该程序有一个列表框,我不能那么容易地重新创建:( 这是带有所选项目的 ListBox 的图片:Selected Item

正如您所见,所选项目变为蓝色,其边框变为蓝色,当您停止关注表单时,它会变为白色:White item

您将鼠标悬停在上面的项目会变成蓝色,但会变浅一点: Hover Item

感谢您的帮助!

顺便说一句,我使用 .NET Framework 4.8

【问题讨论】:

  • 那么您使用 WPF 程序并在 WinForms 中重写?为什么?
  • 我想让它成为另一个程序的自定义用户界面

标签: c# visual-studio winforms listbox


【解决方案1】:

您可以根据原始列表创建自己的列表框。首次编译新列表后,它将出现在工具箱中,以便您可以将其拖放到表单中。或者您可以在 Form.designer.cs 中手动将现有列表框的类型更改为ListBoxEx

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));

此列表框的改进版本可以将不同的选择和热跟踪颜色显示为属性,以便您可以在属性窗口中轻松更改它们。 (属性会自动出现在那里。)

【讨论】:

  • 感谢您对我的帮助!我的问题解决了谢谢!
  • 不客气。另外,由于您是 StackOverflow 的新手,我想通知您,您可以通过勾选答案旁边的勾号来为好的答案投票并接受对您帮助最大的答案。在本网站上,点赞或接受的答案都算作“感谢”。
  • 选中答案左侧的勾号将问题标记为已解决。
猜你喜欢
  • 1970-01-01
  • 2012-05-16
  • 2023-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多