简体   繁体   中英

How to paint owner drawn ListViewItem differently when hovered?

Below is the code. I saw that the MouseMove event is not always triggered, especially when the mouse is moved very fast, and because of this two items can be marked hovered at the same time, so I now use a variable to hold the last hovered item, but the problem is that there are too many redraws. I also saw that DrawListViewItemEventArgs.State property is just ShowKeyboardCues when it should also contain Hot .

private void Form1_Load(object sender, EventArgs e)
{
    listView1.OwnerDraw = true;
    listView1.View = View.LargeIcon;
    listView1.DrawItem += ListView1_DrawItem;
    listView1.MouseMove += ListView1_MouseMove;

    for (int i = 1; i <= 6; ++i)
    {
        listView1.Items.Add($"item {i}", 0);
    }
}

private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
    ListViewItem item = listView1.GetItemAt(e.X, e.Y);
    if (item != null)
    {
        if (LastHoveredItem != null && LastHoveredItem.Index == item.Index)
        {
            return;
        }
        listView1.RedrawItems(item.Index, item.Index, false);
    }
}

internal ListViewItem LastHoveredItem = null;

private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
    bool hot = e.Item.Bounds.Contains(listView1.PointToClient(Cursor.Position));

    if (LastHoveredItem != null)
    {
        listView1.RedrawItems(LastHoveredItem.Index, LastHoveredItem.Index, false);
    }

    if (hot)
    {
        LastHoveredItem = e.Item;
        e.Graphics.FillRectangle(Brushes.Green, e.Bounds);
    }
    else
    {
        LastHoveredItem = null;
    }

    e.DrawText();
}

Here are a few new methods and the existing methods are updated:

public Form1()
{
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    listView1.OwnerDraw = true;
    listView1.View = View.LargeIcon;
    listView1.DrawItem += ListView1_DrawItem;
    listView1.MouseEnter += ListView1_MouseEnter;
    listView1.MouseMove += ListView1_MouseMove;
    listView1.MouseLeave += ListView1_MouseLeave;

    for (int i = 1; i <= 10; ++i)
    {
        listView1.Items.Add($"item {i}", 0);
    }
}

private void ListView1_MouseEnter(object sender, EventArgs e)
{
    CheckHoveredAndInvalidate();
}

private void ListView1_MouseLeave(object sender, EventArgs e)
{
    RemoveHoveredAndInvalidate();
}

internal static Rectangle GetEntireItemBounds(ListViewItem it)
{
    return it.GetBounds(ItemBoundsPortion.Entire);
}

internal ListViewItem GetEntireItemAtCursorPosition()
{
    Point p = listView1.PointToClient(Cursor.Position);
    foreach (ListViewItem it in listView1.Items)
    {
        if (GetEntireItemBounds(it).Contains(p))
        {
            return it;
        }
    }
    return null;
}

private void ListView1_MouseMove(object sender, MouseEventArgs e)
{
    CheckHoveredAndInvalidate();
}

private void CheckHoveredAndInvalidate()
{
    ListViewItem item = GetEntireItemAtCursorPosition();

    if (item == null)
    {
        RemoveHoveredAndInvalidate();
    }
    else if (item != null)
    {
        if (LastHoveredItem != null)
        {
            if (LastHoveredItem != item)
            {
                ListViewItem item2 = LastHoveredItem;
                LastHoveredItem = item;
                listView1.Invalidate(GetEntireItemBounds(item2));
                listView1.Invalidate(GetEntireItemBounds(item));
            }
            else if (LastHoveredItem == item)
            {
            }
        }
        else if (LastHoveredItem == null)
        {
            LastHoveredItem = item;
            listView1.Invalidate(GetEntireItemBounds(item));
        }
    }
}

private void RemoveHoveredAndInvalidate()
{
    if (LastHoveredItem != null)
    {
        ListViewItem item2 = LastHoveredItem;
        LastHoveredItem = null;
        listView1.Invalidate(GetEntireItemBounds(item2));
    }
    else if (LastHoveredItem == null)
    {
    }
}

private void ListView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
    if (LastHoveredItem == e.Item)
    {
        e.Graphics.FillRectangle(Brushes.Yellow, e.Item.Bounds);
    }
    else
    {
        e.Graphics.FillRectangle(Brushes.Green, e.Item.Bounds);
    }
}

The text drawing part has been omitted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM