Visual C# .Net 环境中编程实现浮动工具栏
郭胜涛 mailtogst@163.com
DotNet2.0开发框架中提供的ToolStrip和ToolStripPanel控件可以方便开发具有可停靠工具栏功能的Windows应用程序, ToolStrip对象可以在各个ToolStripPanel间完成拖拽停靠,但是如果想实现类似VS IDE 或Office中可以浮动的工具栏必须借助于DevExpress等一些第三方的控件或编写一定的代码。 这里介绍一种比较简单的方法,只需继承ToolStrip类即可实现上述的效果。
基本思路,我们可以从需求中作这样的假设,工具栏最开始时是放置到ToolStripPanel上的, 当工具栏浮动的时候,事实上是改变了其所在的容器对象,从其所在的ToolStripPanel移动到一个漂浮的容器上,因此要实现工具栏的浮动必须解决以下两个问题:
必须有一个浮动的容器来承载ToolStrip对象。 必须知道ToolStrip对象何时改变其所在的容器, 即在浮动的容器和主窗口上ToolStripPanel之间停靠。
对于第一个问题,我们的解决方案是动态的创建一个Form类作为浮动的容器,命名为ToolStripFloatWindow,该Form对象具有以下的属性: FormBorderStyle = FixedToolWindow 边框样式 ShowInTaskbar = false 不在任务栏显示 ShowIcon = false 不显示窗口图标 TopMost = true 在所有窗口之上
为了解决第二个问题,我们查阅MSDN获知,当用鼠标拖拽ToolStrip对象释放鼠标时会触发其EndDrag事件。 我们在这个事件的处理方法中判断当ToolStrip对象的位置被移动到所在的ToolStripPanel之外的时候,创建ToolStripFloatWindow对象,并将ToolStrip对象移动到ToolStripFloatWindow上;要使ToolStrip对象恢复到原来的窗体上只要判断ToolStripFloatWindow对象的位置是否移动到了ToolStripPanel上, 当条件满足时将ToolStrip对象移动回ToolStripPanel中并销毁ToolStripFloatWindow对象。
此外,还要解决当ToolStrip对象放置到ToolStripFloatWindow对象上时, ToolStripFloatWindow对象必须与ToolStrip对象的尺寸一致。 还有ToolStripFloatWindow对象被点击了关闭按钮时不能将自己关闭。
我们可以做两个类来实现上述的思路。如图:
ToolStripFloatWindow类继承自Form类。 MyToolStrip 继承自ToolStrip类。增加了相应的属性和方法。
MyToolStrip类的源代码如下:
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;
using
System.Runtime.InteropServices;
namespace
FloatingToolStrip
...
{ public partial class MyToolStrip : ToolStrip ... { public MyToolStrip() ... { InitializeComponent(); this .EndDrag += new EventHandler(MyToolStrip_EndDrag); this .SizeChanged += new EventHandler(MyToolStrip_SizeChanged); } protected override void OnPaint(PaintEventArgs pe) ... { // TODO: 在此处添加自定义绘制代码 // 调用基类 OnPaint base .OnPaint(pe); } 漂浮状态 #region 漂浮状态 private ToolStripFloatWindow floatWindow; public ToolStripFloatWindow FloatWindow ... { get ... { return this .floatWindow; } set ... { floatWindow = value; if (FloatWindow != null ) ... { floatWindow.LocationChanged += new EventHandler(floatWindow_LocationChanged); floatWindow.FormClosing += new FormClosingEventHandler(floatWindow_FormClosing); } } } public bool isFloating ... { get ... { return (floatWindow != null ); } } private ToolStripPanel tsPanel; public ToolStripPanel ToolStripPanel ... { get ... { return this .tsPanel; } set ... { tsPanel = value; } } #endregion 漂浮实现 #region 漂浮实现 private void floatWindow_LocationChanged( object sender, EventArgs e) ... { // 当floatwindws的位置移动到 toolstrippanel中时,将this放置到 toolstripPanel上 if ( this .floatWindow == null ) ... { return ; } Point currentPt = new Point(floatWindow.Location.X, floatWindow.Location.Y); Point minpt = this .tsPanel.PointToScreen(tsPanel.Location); Point maxpt; if ( this .tsPanel.Height <= 20 ) ... { maxpt = new Point(minpt.X + this .tsPanel.Width, minpt.Y + 20 ); } else ... { maxpt = new Point(minpt.X + this .tsPanel.Width, minpt.Y + this .tsPanel.Height); } if ((currentPt.X > minpt.X) && (currentPt.X < maxpt.X) && (currentPt.Y > minpt.Y) && (currentPt.Y < maxpt.Y)) ... { this .floatWindow.Controls.Remove( this ); this .tsPanel.SuspendLayout(); this .tsPanel.Controls.Add( this ); this .Location = this .tsPanel.PointToClient(currentPt); this .tsPanel.ResumeLayout(); this .floatWindow.Dispose(); this .floatWindow = null ; } } private void MyToolStrip_EndDrag( object sender, EventArgs e) ... { // 判断移出时 if ( this .tsPanel == null ) ... { MessageBox.Show( " 请先设置ToolStripPanel属性 " ); return ; } Point endPoint = Cursor.Position; int openX, openY; openX = endPoint.X; openY = endPoint.Y; Point clientPt = this .tsPanel.Parent.PointToClient(endPoint); if (clientPt.Y > tsPanel.Height) ... { ToolStripFloatWindow fw = new ToolStripFloatWindow(); this .tsPanel.Controls.Remove( this ); fw.Controls.Add( this ); this .Left = 0 ; this .Top = 0 ; this .FloatWindow = fw; Point newLoc = new Point(openX, openY); fw.Show(); fw.Location = newLoc; fw.SetBounds(newLoc.X, newLoc.Y, this .ClientSize.Width, this .ClientSize.Height); } } private void floatWindow_FormClosing( object sender, FormClosingEventArgs e) ... { e.Cancel = true ; } private void MyToolStrip_SizeChanged( object sender, EventArgs e) ... { if ( this .isFloating) ... { this .floatWindow.Width = this .ClientSize.Width; } } #endregion } }
结论。 该方法实现较简单, 当不愿意使用功能较强大的第三方控件库时可以采用这种方法,缺点是负责浮动的容器是一个窗口,不大美观。
运行效果如下:
另附送完整源代码:将地址拷贝到ie地址栏或Flashget下载
http://dl2.youkuaiyun.com/down4/20070824/24152849181.rar (已失效)