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

最新文章

  1. 【手把手教你全文检索】Apache Lucene初探
  2. TouchSlop与VelocityTracker认识
  3. 【Java基础】Java类及成员和修饰符的关系
  4. HRBUST 1987 逃课的孩子
  5. 工厂模式Assembly.Load(path).CreateInstance 反射出错解决办法
  6. 抓取网页中数据 -----51book中城市码
  7. ssm web.xml配置解析
  8. Lua中string.format占位符的使用
  9. 网络ping不通原因总结
  10. C# WPF DevExpress 图表控件之柱状图
  11. 上传的文件放在SVN服务器的哪个目录下
  12. wepy - 使用vsCode编辑器安装插件
  13. Windows任务计划向远程服务器拷贝文件,报登录失败: 未知的用户名或错误密码
  14. java多线程-ReadWriteLock
  15. 邮件发送javamail
  16. DiskLrucCache使用Demo(强烈推荐,非常好用)
  17. Java并发--CountDownLatch CyclicBarrier ReentrantLock
  18. Python 小知识点(1)
  19. Python升级3.6 强力Django+Xadmin打造在线教育平台
  20. 【bzoj4636】蒟蒻的数列

热门文章

  1. 小白也能轻松上手的Prometheus教程
  2. C6 C7的开机启动流程
  3. 【Linux常见命令】tar命令
  4. 【Linux常见问题】CentOS 7 root用户密码忘记,找回密码方法
  5. iOS开发之结合asp.net webservice实现文件上传下载
  6. vue做商品选择如何保持样式
  7. pyhton中绘制多个图像
  8. 面试官:你说你懂i++跟++i的区别,那你会做下面这道题吗?
  9. puamap是什么意思
  10. 使用RSS订阅喜欢的微博博主