实现功能:
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 下拉框
以上代码均以实现正在整理中,近期发表
