先看图在说.
实现功能:
1)下拉出颜色选取对话框.
2)后台窗口不失去焦点.
3)点击更多调用windows标准颜色选取对话框选取颜色.
开发背景:
在网上看到一些文章可以基本实现这些功能、但是大多使用前台窗口获得焦点后在迅速把焦点
转移到后台窗口的方法、或是将前台窗口 Show 出通过使去焦点来关闭前台窗口,或者干脆用个控件(用普通的控件如果如果范围超出后台窗口的范围就会被窗口遮挡)
而Windows内置的菜单或下拉框都不会出现使、前台窗口触发失去焦点事件的事件、更不会被遮挡、抱着一个程序员执著的信念、在csdn论坛连发数贴(400 分啊)在加上不断的努力终于有所曾就。
在此感谢 csdn 的各位同僚朋友,没有你们就没有这个世界(哈)。
废话不多说了、进入正题。
程序实现代码解析:
1)文章所用到的基础Windows API 类。
using System;
using System.Runtime.InteropServices;
/// <summary>
/// 系统调用,都是Windows API 相关 注视的地方也许大家有用没有删除,具体说明情察看msdn
/// </summary>
public class SystemShell
{
public const int GWL_STYLE = -16;
//public const int GWL_EXSTYLE = -20;
//public const int WS_VISIBLE =0x10000000;
public const int WS_CHILDWINDOW = 0x40000000;
//public const int WS_CLIPSIBLINGS = 0x04000000;
//public const int WS_CLIPCHILDREN = 0x02000000;
//public const int WS_BORDER = 0x00800000;
//public const long WS_THICKFRAME = 0x00040000;
//public const long WS_OVERLAPPED = 0x00000000;
//public const long WS_DLGFRAME = 0x00400000;
//public const long WS_EX_TOOLWINDOW = 0x00000080;
//public const int WM_NCPAINT = 0x0085;
public const int WM_ACTIVATEAPP = 0x001C;
//public const int WM_ERASEBKGND = 0x0014;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern long SetWindowLong(IntPtr hWnd, int nIndex, long dwNewLong);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern long GetWindowLong( IntPtr hWnd,int nIndex);
//[DllImport("user32.dll", CharSet=CharSet.Auto)]
//public static extern int SendMessage(IntPtr hWnd , int msg , int wParam ,int lParam );
//[DllImport("user32.dll", CharSet=CharSet.Auto)]
//public static extern int GetWindowRect (IntPtr hWnd , ref System.Drawing.Rectangle lpRect);
private SystemShell()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
}
本文章弹出窗口的基类(代码处理流程情根据标号浏览)
/// <summary>
/// NoActForm 实现弹出窗口的基类。
/// </summary>
public class NoActForm : System.Windows.Forms.Form
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
public NoActForm():base()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
//
// NoActForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 273);
//(1)不要标题图标 和 Text 属性,
this.ControlBox = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "NoActForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Load += new System.EventHandler(this.NoActForm_Load);
}
#endregion
private void NoActForm_Load(object sender, System.EventArgs e)
{
//如果不是在设计模式
if (!this.DesignMode)
{
//没有 Owner 是不行的
if (this.Owner == null)
{
throw new ApplicationException("not Owner Form");
}
this.ShowInTaskbar =false;
//(2)关键在这里任何窗口子要加上 WS_CHILDWINDOW 样式即可
long Style = SystemShell.GetWindowLong(this.Handle,SystemShell.GWL_STYLE);
Style |= SystemShell.WS_CHILDWINDOW;
SystemShell.SetWindowLong(this.Handle,SystemShell.GWL_STYLE,Style);
}
}
/// <summary>
/// 自己定义的show
/// </summary>
/// <param name="Ctl">要在那个控件附近show 出本窗口</param>
public virtual void Show(Control Ctl)
{
//取得控件在屏幕的位置
Rectangle rect = Ctl.RectangleToScreen(new Rectangle(0,0,Ctl.Width,Ctl.Height));
this.Left=rect.Left;
this.Top=rect.Top+Ctl.Height;
Rectangle ScreenRect = Screen.PrimaryScreen.WorkingArea;
if( this.Right > ScreenRect.Width || this.Bottom > ScreenRect.Height)
{
this.Left=rect.Left - this.Width + Ctl.Width;
this.Top=rect.Top - this.Height;
}
this.Show();
}
/// <summary>
/// 重写 WndProc
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
//(3)如果整个程序失去就隐藏
if (m.Msg==SystemShell.WM_ACTIVATEAPP && m.WParam==IntPtr.Zero)
{
this.Hide();
}
base.WndProc (ref m);
}
}
具体实现(代码处理流程情根据标号浏览)
/// <summary>
/// ColorSelectForm 的摘要说明。
/// (1)继承 NoActForm
/// </summary>
public class ColorSelectForm : NoActForm
{
/// <summary>
///
/// </summary>
public delegate void MouseSelectColor(Color SelectColor);
/// <summary>
/// (2)颜色选取事件当本窗口 获得颜色时触发
/// </summary>
public event MouseSelectColor SelectColor;
private Control _ShowCtl;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ColorDialog colorDialog1;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
public ColorSelectForm():base()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
this.MouseDown+=new MouseEventHandler(ColorSelectForm_MouseDown);
this.MouseMove+=new MouseEventHandler(ColorSelectForm_MouseMove);
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(ColorSelectForm));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.label1 = new System.Windows.Forms.Label();
this.colorDialog1 = new System.Windows.Forms.ColorDialog();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Cursor = System.Windows.Forms.Cursors.Cross;
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Top;
//(3)将 pictureBox1.Image 放一个色盘 图
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(194, 289);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// label1
//
this.label1.BackColor = System.Drawing.SystemColors.Control;
this.label1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(0, 289);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(194, 25);
this.label1.TabIndex = 1;
this.label1.Text = " 更多....";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// ColorSelectForm
//
this.AutoScale = false;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(194, 314);
this.ControlBox = false;
this.Controls.Add(this.label1);
this.Controls.Add(this.pictureBox1);
this.Cursor = System.Windows.Forms.Cursors.Cross;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "ColorSelectForm";
this.Text = "";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// (4) 封装 Show
/// </summary>
/// <param name="Ctl"></param>
public override void Show(Control Ctl)
{
_ShowCtl =Ctl;
Owner.Cursor = Cursors.Cross;
base.Show(Ctl);
//show 后立刻捕捉鼠标
this.Capture=true;
}
/// <summary>
/// (6)如果鼠标按下进行一系列处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ColorSelectForm_MouseDown(object sender, MouseEventArgs e)
{
//释放鼠标
this.Capture=false;
Point pt = Control.MousePosition;
Color cl =Color.Empty;
while(true)
{
//是否在窗口范围内
if(!(pt.X> this.Right || pt.X < this.Left|| pt.Y>this.Bottom || pt.Y< this.Top))
{
//取label1 在屏幕上的位置
Rectangle rect =label1.RectangleToScreen(new Rectangle(0,0,label1.Width,label1.Height));
//如果鼠标点击在 label1 上弹出 colorDialog1
if (!(pt.X> rect.Right || pt.X < rect.X|| pt.Y> rect.Bottom || pt.Y < rect.Y))
{
if (colorDialog1.ShowDialog() == DialogResult.OK )
{
cl = colorDialog1.Color;
}
break;
}
//取上方 pictureBox 在屏幕上的位置
rect =pictureBox1.RectangleToScreen(new Rectangle(0,0,pictureBox1.Width ,pictureBox1.Height));
//判断鼠标是否点击到了 pictureBox1
if (!(pt.X> rect.Right || pt.X < rect.X|| pt.Y> rect.Bottom || pt.Y < rect.Y))
{
//根据鼠标位置得到选择颜色
Bitmap bmp = (Bitmap)this.pictureBox1.Image;
cl = bmp.GetPixel(e.X,e.Y);
}
}
break;
}
Owner.Cursor = Cursors.Default ;
//如果 SelectColor 事件被映射,而且颜色已经被选择
if (SelectColor!=null && cl!= Color.Empty)
{
//触发颜色选取事件
SelectColor(cl);
}
this.Dispose();
}
/// <summary>
/// (5)如果鼠标进入 label1 的范围将 label1 BackColor 属性改变
/// 类是鼠标悬停的感觉.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ColorSelectForm_MouseMove(object sender, MouseEventArgs e)
{
Point pt = Control.MousePosition;
Color cl = SystemColors.Control;
if(!(pt.X> this.Right || pt.X < this.Left|| pt.Y>this.Bottom || pt.Y< this.Top))
{
Rectangle rect =label1.RectangleToScreen(new Rectangle(0,0,label1.Width,label1.Height));
if (!(pt.X> rect.Right || pt.X < rect.X|| pt.Y> rect.Bottom || pt.Y < rect.Y))
{
cl = Color.FromArgb(224, 224, 224);
}
}
label1.BackColor=cl;
}
}
调用颜色选取窗口(很简单不注视了)
private void button1_Click(object sender, System.EventArgs e)
{
ColorSelectForm ColorForm = new ColorSelectForm();
ColorForm.Owner=this;
ColorForm.SelectColor+=new ColorSelectForm.MouseSelectColor(ColorForm_SelectColor);
ColorForm.Show(sender as Button);
}
private void ColorForm_SelectColor(Color SelectColor)
{
button1.BackColor=SelectColor;
}
备注:
组合下拉框
Grid 下拉框
以上代码均以实现正在整理中,近期发表