模仿outlook快捷方式栏的一个控件

简介: hi,cnblogs readers,this is my first article here.——jinfd这是我的第一篇在这里的随笔,我在最近两三天把这个控件的主要代码写完了。这是一个用c#写的控件,它的原型是outlook 2000里面左侧的快捷方式栏,类似的控件也会在QQ,Visio等常用软件中找到,我为这个控件写了一个dll,并且做了一个demo演示它。
hi,cnblogs readers,this is my first article here.——jinfd
这是我的第一篇在这里的随笔,我在最近两三天把这个控件的主要代码写完了。
这是一个用c#写的控件,它的原型是outlook 2000里面左侧的快捷方式栏,类似的控件也会在QQ,Visio等常用软件中找到,我为这个控件写了一个dll,并且做了一个demo演示它。

如下图所示:
img_567c30ecc5b9f70aea00a89f37682199.jpg

我把一些主要的控件属性在demo里可以随时更改。它代码量不是很多,dll文件只有36kb。
我没有为这个控件提供额外的面板,但是控件中的每个元素都具有Tag属性。
提供了VisibleGroupChanged, ItemClick等主要事件。在它内部我封装了滚动处理,(按住滚动按钮超过0.5秒后由定时器自动滚动),封装了单选状态时的item互斥性切换。在控件中显示的内容全部是绘制而成,也就是说,它们都是逻辑元素,而非实际的子控件对象。为此,我定义了一个SbComponent类作为所有元素的父类,它主要描述了元素的布局信息,同时也提供了通用的HitTest测试方法以响应鼠标,Items对鼠标提供了悬停反馈,但是GroupHeader没有,因为我觉得它并不是最重要的功能,如果想加还是很简单的。在绘制元素时主要使用了ControlPaint类来实现。

控件的内部组织结构如下图所示:
img_3eea0a4b3bb293042b2491dfb8da1198.jpg


控件的使用非常简单:我借鉴了treeview,listview控件的封装用法,
 1 img_a6339ee3e57d1d52bc7d02b338e15a60.gif SideBar.SideBar sbar = new  SideBar.SideBar();
 2 img_a6339ee3e57d1d52bc7d02b338e15a60.gif // 赋予imagelist
 3 img_a6339ee3e57d1d52bc7d02b338e15a60.gif sbar.ImageList = this .imageList1;
 4 img_a6339ee3e57d1d52bc7d02b338e15a60.gifsbar.AddGroup( " 第一组 " );
 5 img_a6339ee3e57d1d52bc7d02b338e15a60.gifsbar.AddGroup( " 第二组 " );
 6 img_a6339ee3e57d1d52bc7d02b338e15a60.gif // 添加items,参数列表为:itemtext,imageindex
 7 img_a6339ee3e57d1d52bc7d02b338e15a60.gif sbar.Groups[ 0 ].Items.Add( " item0 " , 0 );
 8 img_a6339ee3e57d1d52bc7d02b338e15a60.gifsbar.Groups[ 1 ].Items.Add( " item1 " , 1 );
 9 img_a6339ee3e57d1d52bc7d02b338e15a60.gifsbar.VisibleGroupChanged += new  SbGroupEventHandler(sbar_VisibleGroupChanged);
10 img_a6339ee3e57d1d52bc7d02b338e15a60.gifsbar.ItemClick += new  SbItemEventHandler(sbar_ItemClick);

可以通过鼠标点击自动完成当前显示组的切换,也可以使用代码来完成:
 
1 img_a6339ee3e57d1d52bc7d02b338e15a60.gif // 设置当前显示的组
2 img_a6339ee3e57d1d52bc7d02b338e15a60.gif sbar.VisibleGroupIndex = 1 ;

晚上的时候,我为这个控件加入了对拖放item的功能支持。不过这个功能确实具有一定挑战性,因为涉及到的鼠标处理比较复杂。我们可以看到,鼠标操作的主要特点是:
1.当按下某个控件(例如按钮)时,保持鼠标按下状态,并移开控件,则该控件会弹起,如果此时抬起鼠标,则该控件不会被点击。如果保持鼠标按下并移回控件,控件继续显示成按下状态。即,必须按下和抬起时都捕捉到该控件,点击才有效。估计这是windows设计者考虑到了用户的误操作,允许用户可以此种方法取消点击控件。
2. 当鼠标按下一个item并拖动它到临界区(靠近itemsbox边缘)时,如果item很多,则自动开始滚动。
3. 当鼠标移动到其他GroupHeader时,会切换当前显示的Group。即允许用户将item从一个Group拖动到其他Group中。

上面的挑战性和难点在于,需要根据鼠标的位置计算出需要插入的索引位置,以及要绘制标记插入位置的反馈,并且再位置改变时更新它。具体的细节比较复杂,为此我为sidebar引入了很多成员变量来记录一些必要的信息。也使得mousedown,mouseup,mousemove里面的代码量增加了几乎一倍。。。

不过上面的烦琐细节都被我封装在内部,在外部的使用还是非常简单的。我提供了一个AllowDragItem属性,只需要简单的设置它即可选择是否支持拖放item。同时我考虑为控件增加一个新的事件把它通知给外部。

1 img_a6339ee3e57d1d52bc7d02b338e15a60.gif // 使控件支持鼠标拖放条目
2 img_a6339ee3e57d1d52bc7d02b338e15a60.gif Sbar.AllowDragItem = true ;

你可以在这里下载到这个控件和例子的最新源代码:
http://files.cnblogs.com/hoodlum1980/SideBar20070707.rar

在这个网站上面还有我的其他几个比较小但是有趣的例子源码,也许会在以后详细介绍它们。
——————————————————————————————
小Bug记录:
1.修改了调整字体后布局错误的bug。
2.修改了在demo中的一个疏忽:在显示字体对话框时,错误的将字体初始化为了form1的字体。
3.我把影响外观的一些属性修改后的刷新显示封装在了控件内部。这个并不算什么严重的bug
但会使外部使用时更为简便。例如,对enabled,view(大图标,小图标...),flatstyle等属性的修改,都会在控件内部调用刷新。在外部只要简单的设置它们的值即可。
目录
相关文章
|
7月前
如何隐藏windows10系统任务栏右下角的语言输入法图标?
如何隐藏windows10系统任务栏右下角的语言输入法图标?
windows10为何鼠标右键失灵,桌面右键一直转圈的解决
windows10为何鼠标右键失灵,桌面右键一直转圈的解决
1100 0
electron菜单或托盘点击如何打开新的窗口
electron菜单或托盘点击如何打开新的窗口
electron菜单或托盘点击如何打开新的窗口
|
Windows
Windows程序设计——Windows单选按钮、复选框、分组框控件
Windows程序设计——Windows单选按钮、复选框、分组框控件
637 0
Windows程序设计——Windows单选按钮、复选框、分组框控件
|
Windows
Windows程序设计——(源代码)Windows单选按钮、复选框、分组框控件
Windows程序设计——(源代码)Windows单选按钮、复选框、分组框控件
214 0
win10 uwp 让焦点在点击在页面空白处时回到textbox中
原文:win10 uwp 让焦点在点击在页面空白处时回到textbox中 在网上 有一个大神问我这样的问题:在做UWP的项目,怎么能让焦点在点击在页面空白处时回到textbox中? 虽然我的小伙伴认为他这是一个 xy 问题,但是我还是回答他这个问题。
1169 0
|
数据安全/隐私保护