前言
qq软件对于绝大多数的人来说再熟悉不过了,它以使用方便、界面美观及功能完善而著称。
主要通过使用api函数windowfrompoint和getparent实现仿qq的抽屉式窗体:
1.windowfrompoint函数
该函数用于获得包含指定点坐标的窗口的句柄。语法格式如下:
[dliimport("user32.dll")] //需要引入user32.dll动态链接库 public static extern int windowfrompoint(int xpoint,int ypoint) //获得包含指定点坐标的窗口的句柄 参数说明 xpoint:被检测点的横坐标。 ypoint:被检测点的纵坐标。 目返回值:为包含指定点坐标的窗口的句柄,若包含指定点坐标的窗口不存在,则返回值为null;若该坐标对应的点在静态文本控件之上,则返回值是在该静态文本控件下面的窗口的句柄。
2.getparent函数
该函数用于获取指定句柄的父级。语法格式如下:
[dllimport("user32.dll",exactspelling =true,charset =charset.auto)]//需要引入user32.dll动态链接库 public static extern intptr getparent(intptr hwnd); //获取指定句柄的父级 参数说明 hwnd:指定窗口的句柄。 返回值:若果函数执行成功,则返回指定窗口句柄的父级;若函数执行失败,则返回值为null。
3.实例
本实例仿照qq软件界面的基本操作设计了一个抽屉式的窗体:在该窗体中单击任意按钮,程序将显示被单击按钮对应的列表,同时隐藏其他两个按钮对应的列表;用鼠标拖曳该窗体到屏幕的任意边缘,窗体会自动隐藏到该边缘内,当鼠标划过隐藏窗体的边缘时,窗体会显示出来;当鼠标离开窗体时,窗体再次被隐藏。
(1)图片集合编辑器
本实例没有使用资源管理器加载图片。本实例设计了一个imagelist1控件,项目使用的图片都要设计到imagelist1的图像集合编辑器中。
(2)form1.designer.cs
namespace _190 { partial class form1 { /// <summary> /// required designer variable. /// </summary> private system.componentmodel.icontainer components = null; /// <summary> /// clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void dispose(bool disposing) { if (disposing && (components != null)) { components.dispose(); } base.dispose(disposing); } #region windows form designer generated code /// <summary> /// required method for designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void initializecomponent() { components = new system.componentmodel.container(); system.componentmodel.componentresourcemanager resources = new system.componentmodel.componentresourcemanager(typeof(form1)); button1 = new button(); button2 = new button(); button3 = new button(); listview1 = new listview(); imagelist1 = new imagelist(components); judgewinmouposition = new system.windows.forms.timer(components); hidewindow = new system.windows.forms.timer(components); suspendlayout(); // // button1 // button1.dock = dockstyle.top; button1.location = new point(0, 0); button1.name = "button1"; button1.size = new size(153, 23); button1.tabindex = 0; button1.text = "我的好友"; button1.usevisualstylebackcolor = true; button1.click += button1_click; // // button2 // button2.dock = dockstyle.bottom; button2.location = new point(0, 262); button2.name = "button2"; button2.size = new size(153, 23); button2.tabindex = 1; button2.text = "黑名单"; button2.usevisualstylebackcolor = true; button2.click += button2_click; // // button3 // button3.dock = dockstyle.bottom; button3.location = new point(0, 239); button3.name = "button3"; button3.size = new size(153, 23); button3.tabindex = 2; button3.text = "陌生人"; button3.usevisualstylebackcolor = true; button3.click += button3_click; // // listview1 // listview1.dock = dockstyle.fill; listview1.location = new point(0, 23); listview1.name = "listview1"; listview1.size = new size(153, 216); listview1.tabindex = 3; listview1.usecompatiblestateimagebehavior = false; // // imagelist1 // imagelist1.colordepth = colordepth.depth32bit; imagelist1.imagestream = (imageliststreamer)resources.getobject("imagelist1.imagestream"); imagelist1.transparentcolor = color.transparent; imagelist1.images.setkeyname(0, "01.jpg"); imagelist1.images.setkeyname(1, "02.png"); imagelist1.images.setkeyname(2, "03.jpg"); imagelist1.images.setkeyname(3, "04.jpg"); imagelist1.images.setkeyname(4, "05.png"); imagelist1.images.setkeyname(5, "06.jpg"); // // judgewinmouposition // judgewinmouposition.tick += judgewinmouposition_tick; // // hidewindow // hidewindow.tick += hidewindow_tick; // // form1 // autoscaledimensions = new sizef(7f, 17f); autoscalemode = autoscalemode.font; backgroundimagelayout = imagelayout.stretch; clientsize = new size(153, 285); controls.add(listview1); controls.add(button3); controls.add(button2); controls.add(button1); name = "form1"; startposition = formstartposition.centerscreen; text = "仿qq抽屉式窗体"; load += form1_load; locationchanged += form1_locationchanged; resize += form1_resize; resumelayout(false); } #endregion private button button1; private button button2; private button button3; private listview listview1; private imagelist imagelist1; private system.windows.forms.timer judgewinmouposition; private system.windows.forms.timer hidewindow; } }
(3)form1.cs
// 仿qq抽屉式窗体 using system.runtime.interopservices; namespace _190 { public partial class form1 : form { #region 声明本程序中用到的api函数 //获取当前鼠标下可视化控件的函数 [libraryimport("user32.dll")] public static partial int windowfrompoint(int xpoint, int ypoint); //获取指定句柄的父级函数 [libraryimport("user32.dll")] public static partial intptr getparent(intptr hwnd); //获取屏幕的大小 [libraryimport("user32.dll", entrypoint = "getsystemmetrics")] private static partial int getsystemmetrics(int mval); #endregion public form1() { initializecomponent(); } #region 运行本程序需要声明的变量 private intptr currenthandle; //记录鼠标当前状态下控件的句柄 private int windowflag; //标记是否对窗体进行拉伸操作 private int intoriheight; #endregion private void form1_load(object sender, eventargs e) { intoriheight = height; desktoplocation = new point(794, 0); //为当前窗体定位 judgewinmouposition.enabled = true; //计时器judgewinmouposition开始工作 listview1.clear(); listview1.largeimagelist = imagelist1; listview1.items.add("小猪", "小猪", 0); listview1.items.add("小狗", "小狗", 1); listview1.items.add("娇娇", "娇娇", 2); } public int oriheight { get { return intoriheight; } } /// <summary> /// 我的好友 /// </summary> private void button1_click(object sender, eventargs e) { listview1.dock = dockstyle.none; button1.dock = dockstyle.top; button2.dock = dockstyle.bottom; button3.dock = dockstyle.bottom; button3.sendtoback(); listview1.bringtofront(); listview1.dock = dockstyle.bottom; listview1.clear(); listview1.items.add("小猪", "小猪", 0); listview1.items.add("小狗", "小狗", 1); listview1.items.add("娇娇", "娇娇", 2); } /// <summary> /// 陌生人 /// </summary> private void button3_click(object sender, eventargs e) { listview1.dock = dockstyle.none; button2.dock = dockstyle.top; button1.dock = dockstyle.top; button1.sendtoback(); button3.dock = dockstyle.bottom; listview1.dock = dockstyle.bottom; listview1.clear(); listview1.items.add("北风", "北风", 3); } /// <summary> /// 黑名单 /// </summary> private void button2_click(object sender, eventargs e) { listview1.dock = dockstyle.none; button3.dock = dockstyle.top; //设置button3按钮绑定到窗体的上边缘 button2.dock = dockstyle.top; //设置button2按钮绑定到窗体的上边缘 button2.sendtoback(); //保证button2在button3的后面 button1.dock = dockstyle.top; button1.sendtoback(); //保证button1在button2的后面 listview1.dock = dockstyle.bottom; listview1.clear(); listview1.items.add("冰雨", "冰雨", 5); } /// <summary> /// 判断当前窗体处于哪个状态 /// </summary> private void hidewindow_tick(object sender, eventargs e) { switch (convert.toint32(windowflag.tostring())) { case 1: //当窗体处于最上端时 if (top < 3) //当窗体与容器工作区的上边缘的距离小于5px时 top = -(height - 2); //设定当前窗体距容器工作区上边缘的值 break; case 2: //当窗体处于最左端时 if (left < 3)//当窗体与容器工作区的左边缘的距离小于5px时 left = -(width - 2); //设定当前窗体据容器工作区左边缘的值 break; case 3: //当窗体处于最右端时 if ((left + width) > (getsystemmetrics(0) - 3)) //当窗体与容器工作区的右边缘的距离小于5px时 left = getsystemmetrics(0) - 2; //设定当前窗体距容器工作区左边缘的值 break; case 4: //当窗体处于最低端时 if (bottom > screen.allscreens[0].bounds.height - 3)//当窗体与容器工作区的下边缘的距离小于5px时 top = screen.allscreens[0].bounds.height - 5; //设定当前窗体距容器工作区上边缘之间的距离 break; } } private void judgewinmouposition_tick(object sender, eventargs e) { if (top < 3) //当本窗体距屏幕的上边距小于3px时 { if (handle == mousenowposition(cursor.position.x, cursor.position.y))//当鼠标在该窗体上时 { windowflag = 1; //设定当前的窗体状态 hidewindow.enabled = false; //设定计时器hidewindow为不可用状态 top = 0; //设定窗体上边缘与容器工作区上边缘之间的距离 } else //当鼠标没在窗体上时 { windowflag = 1; //设定当前的窗体状态 hidewindow.enabled = true; //启动计时器hidewindow } } //当本窗体距屏幕的上边距大于3px时 else { //当本窗体在屏幕的最左端或者最右端、最下端时 if (left < 3 || (left + width) > (getsystemmetrics(0) - 3) || (top + height) > (screen.allscreens[0].bounds.height - 3)) { if (left < 3) //当窗体处于屏幕左侧时 { if (handle == mousenowposition(cursor.position.x, cursor.position.y)) //当鼠标在该窗体上时 { height = screen.allscreens[0].bounds.height - 40; top = 3; windowflag = 2; //设定当前的窗体状态 hidewindow.enabled = false;//设定计时器hidewindow为不可用状态 left = 0; //设定窗体的左边缘与容器工作区的左边缘之间的距离 } else //当鼠标没在该窗体上时 { windowflag = 2; //设定当前的窗体状态 hidewindow.enabled = true;//设定计时器hidewindow为可用状态 } } if ((left + width) > (getsystemmetrics(0) - 3)) //当窗体处于屏幕的最右侧时 { if (handle == mousenowposition(cursor.position.x, cursor.position.y))//当鼠标处于窗体上时 { height = screen.allscreens[0].bounds.height - 40; top = 3; windowflag = 3; //设定当前的窗体状态 hidewindow.enabled = false; //设定计时器hidewindow为不可用状态 left = getsystemmetrics(0) - width; //设定该窗体与容器工作区左边缘之间的距离 } else //当鼠标离开窗体时 { windowflag = 3; //设定当前的窗体状态 hidewindow.enabled = true; //设定计时器hidewindow为可用状态 } } //当窗体距屏幕最下端的距离小于3px时 if ((top + height) > (screen.allscreens[0].bounds.height - 3)) { if (handle == mousenowposition(cursor.position.x, cursor.position.y)) //当鼠标在该窗体上时 { windowflag = 4; //设定当前的窗体状态 hidewindow.enabled = false;//设定计时器hidewindow为不可用状态 top = screen.allscreens[0].bounds.height - height;//设定该窗体与容器工作区上边缘之间的距离 } else { if ((left > width + 3) && (getsystemmetrics(0) - right) > 3) { windowflag = 4; //设定当前的窗体状态 hidewindow.enabled = true; //设定计时器hidewindow为可用状态 } } } } } } #region 获取鼠标当前状态下控件的句柄 /// <summary> /// 获取鼠标当前状态下控件的句柄 /// </summary> /// <param name="x">当前鼠标的x坐标</param> /// <param name="y">当前鼠标的y坐标</param> /// <returns></returns> public intptr mousenowposition(int x, int y) { intptr originalhandle;//声明保存原始句柄的变量 originalhandle = windowfrompoint(x, y);//获取包含鼠标原始位置的窗口的句柄 currenthandle = originalhandle; //设置当前句柄 while (originalhandle != 0) //循环判断鼠标是否移动 { currenthandle = originalhandle; //记录当前的句柄 originalhandle = getparent(currenthandle);//更新原始句柄 } return currenthandle; //返回当前的句柄 } #endregion private void form1_locationchanged(object sender, eventargs e) { if (left > 3 && right < (getsystemmetrics(0) - 3)) { if (height == screen.allscreens[0].bounds.height - 40) { height = oriheight; } } } private void form1_resize(object sender, eventargs e) { listview1.height = height - button3.height * 3 - 30; } } }
4.生成效果
生成的窗体默认停留在窗体顶部,并且隐藏的。鼠标滑动到其停住的区域该窗体就会弹出。此时可以拖动窗体到左、右、下部,松开鼠标后窗体会停驻在左、右、下部。操作窗体上的最大化、关闭按钮,可以让窗体最大化和关闭。还可以操作窗体的边框,向左、下、右拖动放大缩小窗体;鼠标点击任务栏的图标可以查找窗体当前的停靠位置。
以上就是c#实现仿qq抽屉式窗体的设计方法的详细内容,更多关于c#仿qq抽屉式窗体的资料请关注代码网其它相关文章!
发表评论