前言
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抽屉式窗体的资料请关注代码网其它相关文章!
发表评论