• [原创][开源] SunnyUI.Net 开发日志:UIListBox 增加跟随鼠标滑过高亮


    SunnyUI.Net, 基于 C# .Net WinForm 开源控件库、工具类库、扩展类库、多页面开发框架

     

     SunnyUI.Net 开发日志:ListBox 增加跟随鼠标滑过高亮

     QQ群里,寸木说,ListBox鼠标移动时,当前行需要焦点,我想了想,不难实现啊

    不就是在鼠标移动时重绘Item嘛,何况选中的Item已经改了颜色了。

    见UIListBox代码:

    protected override void OnDrawItem(DrawItemEventArgs e)
            {
                base.OnDrawItem(e);
                BeforeDrawItem?.Invoke(this, Items, e);
                if (Items.Count == 0)
                {
                    return;
                }
    
                e.DrawBackground();
    
                if (e.Index < 0 || e.Index >= Items.Count)
                {
                    return;
                }
    
                StringFormat sStringFormat = new StringFormat();
                sStringFormat.LineAlignment = StringAlignment.Center;
    
                Color backColor = (e.State & DrawItemState.Selected) == DrawItemState.Selected ? ItemSelectBackColor : BackColor;
                Color foreColor = (e.State & DrawItemState.Selected) == DrawItemState.Selected ? ItemSelectForeColor : ForeColor;
    
                Rectangle rect = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1);
                e.Graphics.FillRectangle(BackColor, e.Bounds);
                e.Graphics.FillRoundRectangle(backColor, rect, 5);
                e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, foreColor, e.Bounds, sStringFormat);
            }
    

    看:(e.State & DrawItemState.Selected) == DrawItemState.Selected 选中行状态嘛

    看了e.State有e.State == DrawItemState.HotLight,不就是高亮的么,于是开始撸代码,加状态判断

    Run

    晕。。。没变,这HotLight不起作用,好吧,问度娘。。。

    翻山越岭,跋山涉水。。。

    找到这篇:https://www.jb51.cc/csharp/101121.html

    其中提到:

       我在我的WinForms应用程序中使用OwnerDrawFixed作为DrawMode用于自定义ListBox控件.当用户将鼠标悬停在列表框项目上时,我希望重新绘制ListBoxItem的背景(或执行其他操作),即在MouseMove …DrawItemState.HotLight永远不适用于ListBox,所以我想知道如何模拟它,如何解决这个问题.

    DrawItemState.HotLight永远不适用于ListBox,是永远。。。怎么这么远。。。

    继续往下看:

    解决方法

    我花了两年时间为你找到答案,但这里是:

    DrawItemState.HotLight仅适用于所有者绘制的菜单,而不适用于列表框.对于ListBox,您必须自己跟踪项目:

    public partial class Form1 : Form
    {
      private int _MouseIndex = -1;
     
      public Form1()
      { InitializeComponent(); }
     
      private void listBox1_DrawItem(object sender,DrawItemEventArgs e)
      {
        Brush textBrush = SystemBrushes.WindowText;
     
        if (e.Index > -1)
        {
          if (e.Index == _MouseIndex)
          {
            e.Graphics.FillRectangle(SystemBrushes.HotTrack,e.Bounds);
            textBrush = SystemBrushes.HighlightText;
          }
          else
          {
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
              e.Graphics.FillRectangle(SystemBrushes.Highlight,e.Bounds);
              textBrush = SystemBrushes.HighlightText;
            }
            else
              e.Graphics.FillRectangle(SystemBrushes.Window,e.Bounds);
          }
          e.Graphics.DrawString(listBox1.Items[e.Index].ToString(),e.Font,textBrush,e.Bounds.Left + 2,e.Bounds.Top);
        }
      }
     
      private void listBox1_MouseMove(object sender,MouseEventArgs e)
      {
        int index = listBox1.IndexFromPoint(e.Location);
        if (index != _MouseIndex)
        {
          _MouseIndex = index;
          listBox1.Invalidate();
        }
      }
     
      private void listBox1_MouseLeave(object sender,EventArgs e)
      {
        if (_MouseIndex > -1)
        {
          _MouseIndex = -1;
          listBox1.Invalidate();
        }
      }
    }
    

    兄弟们,人家这花两年时间解决的,应该有用,继续再找找,又找到一篇洋文的:

    https://stackoverflow.com/questions/1316027/listbox-drawitem-hotlight-state-in-the-ownerdraw-mode

    It took me only two years to find the answer for you, but here it is:

    The DrawItemState.HotLight only applies to owner drawn menus, not the listbox.

    For the ListBox, you have to keep track of the item yourself:

    看看,也是两年,估计上面中文的从这个翻译过来。

    除了这俩,还真没找到。

    继续撸代码,果真管用。不过还是有问题,鼠标滑快了,ListBox闪烁的厉害。

    分析代码  listBox1.Invalidate(); 这是刷新全部的。鼠标滑过也就和本次选中和上次选中的有关系。

    就刷这两个Item就行,有了思路,撸代码三连发:

            private int lastIndex = -1;
            private int mouseIndex = -1;
    
            [Browsable(false)]
            public int MouseIndex
            {
                get => mouseIndex;
                set
                {
                    if (mouseIndex != value)
                    {
                        if (lastIndex >= 0 && lastIndex != SelectedIndex)
                        {
                            OnDrawItem(new DrawItemEventArgs(this.CreateGraphics(), Font, GetItemRectangle(lastIndex), lastIndex, DrawItemState.Grayed));
                        }
    
                        mouseIndex = value;
                        if (mouseIndex >= 0 && mouseIndex != SelectedIndex)
                        {
                            OnDrawItem(new DrawItemEventArgs(this.CreateGraphics(), Font, GetItemRectangle(value), value, DrawItemState.HotLight));
                        }
    
                        lastIndex = mouseIndex;
                    }
                }
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                base.OnMouseMove(e);
                MouseIndex = IndexFromPoint(e.Location);
            }
    
            protected override void OnMouseLeave(EventArgs e)
            {
                base.OnMouseLeave(e);
                MouseIndex = -1;
            }
    

    其中 new DrawItemEventArgs(this.CreateGraphics(), Font, GetItemRectangle(value), value, DrawItemState.HotLight) 

    第一个参数Graphics,也找了一会儿,后来看这篇:

    https://www.cnblogs.com/yuanyeguhong/archive/2013/09/20/3330606.html

    其实就是Graphics对象的DrawString方法,而参数e中的Graphics是如何来的呢。
    我们接着分析DrawItemEventArgs这个类,他既然是对listBox1某一项的属性的打包,
    那么我估计其中的Graphics对象就是由listBox1.creatgraphics而来的。
    好了,到此我们就可以自定义重绘listbox某项的函数了,可任意调用的哦!

    好了,至此,问题都已找到答案,再捋一下思路,把逻辑理顺。撸代码,调试,OK!!!

    主要代码如下:

    protected override void OnDrawItem(DrawItemEventArgs e)
            {
                base.OnDrawItem(e);
    
                BeforeDrawItem?.Invoke(this, Items, e);
                if (Items.Count == 0)
                {
                    return;
                }
    
                bool otherState = e.State == DrawItemState.Grayed || e.State == DrawItemState.HotLight;
                if (!otherState)
                {
                    e.DrawBackground();
                }
    
                if (e.Index < 0 || e.Index >= Items.Count)
                {
                    return;
                }
    
                StringFormat sStringFormat = new StringFormat();
                sStringFormat.LineAlignment = StringAlignment.Center;
    
                bool isSelected = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
                Color backColor = isSelected ? ItemSelectBackColor : BackColor;
                Color foreColor = isSelected ? ItemSelectForeColor : ForeColor;
    
                Rectangle rect = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1);
                if (!otherState)
                {
                    e.Graphics.FillRectangle(BackColor, e.Bounds);
                    e.Graphics.FillRoundRectangle(backColor, rect, 5);
                    e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, foreColor, e.Bounds, sStringFormat);
                }
                else
                {
                    if (e.State == DrawItemState.Grayed)
                    {
                        backColor = BackColor;
                        foreColor = ForeColor;
                    }
    
                    if (e.State == DrawItemState.HotLight)
                    {
                        backColor = HoverColor;
                        foreColor = ForeColor;
                    }
    
                    e.Graphics.FillRectangle(BackColor, e.Bounds);
                    e.Graphics.FillRoundRectangle(backColor, rect, 5);
                    e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, foreColor, e.Bounds, sStringFormat);
                }
    
                AfterDrawItem?.Invoke(this, Items, e);
            }
    

    看,DrawItemState.HotLight咱也给实现了,DrawItemState.Grayed 我是随便选的状态,区别于其他。

    想看全部代码,看我的开源项目吧,https://gitee.com/yhuse/SunnyUI ,哎,客官别走嘛,点个Star先。

    原创文章,转载请保留链接 Sunny's blog

  • 相关阅读:
    项目架构
    RoadFlow Asp.Net Core工作流配置文件说明
    RoadFlowCore 解决方案介绍及开发概述
    RoadFlow2.7.5 MyController.cs
    RoadFlow开源工作流源码-项目架构分析
    ORACLE EXP-00011:表不存在的分析和解决方案
    Caused by: java.sql.SQLSyntaxErrorException: ORA-00932: 数据类型不一致: 应为 NUMBER, 但却获得 BINARY
    OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)
    Swift字典
    [iOS翻译]《iOS7 by Tutorials》在Xcode 5里使用单元測试(上)
  • 原文地址:https://www.cnblogs.com/yhuse/p/12933885.html
Copyright © 2020-2023  润新知