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

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

 

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

 

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

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

见UIListBox代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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,所以我想知道如何模拟它,如何解决这个问题.

1

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

继续往下看:

解决方法

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

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就行,有了思路,撸代码三连发:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

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!!!

主要代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

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

分类: SunnyUI

标签: SunnyUIC#

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SunnyUI.Net 是基于.Net Framework 4.0+、.Net Core3.1、.Net 5 框架的 C# WinForm 开源控件库、工具类库、扩展类库、多页面开发框架。 源码编译环境:VS2019 16.8+,.Net5,.Net Core3.1 动态库应用环境:VS2010及以上,.Net Framework 4.0及以上(不包括.Net Framework 4 Client Profile),.Net Core 3.1,.Net 5.0 推荐通过Nuget安装:Install-Package SunnyUI,或者通过Nuget搜索SunnyUI安装。 软件介绍: 1、开源控件库 基于.Net Framework4.0,原生控件开发,参考 Element主题风格,包含 按钮、编辑框、下拉框、数据表格、工控仪表、统计图表在内的常用控件超过 50 个,满足常规开发需求,每个控件都精雕细琢,注重细节; 包含 Element 风格主题 11 个,其他主题 6 个,包含主题管理组件 UIStyleManager,可自由切换主题。 2、工具库 收集整理开发过程中经常用到的工具类库。 3、扩展库 收集整理开发过程中经常用到的扩展类库。 4、多页面框架 参考Element,包括7种常用框架风格,只需几行简单的代码即可创建多页面程序,其支撑组件包括UIForm,UIPage,UIFrame,集合常用控件库即可快速开发WinForm应用程序。 SunnyUI.Net开发框架 更新日志: v3.0.2 UIMarkLabel:增加带颜色标签的Label UIRoundProcess:圆形滚动条 UIBreadcrumb:增加面包屑导航 UILedLabel:增加Led标签 UIHeaderButton:在工具箱中显示 UILineChart:支持拖拽选取放大 UIDateTimePicker:修复下拉选择日期后关闭的Bug UINavMenu:增加设置二级菜单底色 UIColorPicker:增加单击事件以选中颜色 UITitlePage:增加ShowTitle可控制是否显示标题 UINavBar:增加可设置背景图片 框架增加IFrame接口,方便页面跳转 UIDataGridView:修改垂直滚动条和原版一致,并增加翻页方式滚动 UIPagination: 修正因两次查询数量相等而引起的不刷新 UIHeaderButton: 增加字体图标背景时鼠标移上背景色 UITabControl:修改第一个TabPage关不掉的Bug UIDataGridView:增加EnterAsTab属性,编辑输入时,用Enter键代替Tab键跳到下一个单元格 UILineChart:增加鼠标框选放大,可多次放大,右键点击恢复一次,双击恢复 UITitlePanel:修复OnMouseMove事件 UITrackBar:增加垂直显示方式 UIFlowLayoutPanel:修改了一处因为其加入控件大小发生变化而引起的滚动条出错。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值