C#仿QQ抽屉式窗体的设计方法:创建特殊窗体

目录

1.WindowFromPoint函数

2.GetParent函数

3.实例

(1) 图片集合编辑器

(2)Form1.Designer.cs

(3)Form1.cs

4.生成效果 


        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.生成效果 

        生成的窗体默认停留在窗体顶部,并且隐藏的。鼠标滑动到其停住的区域该窗体就会弹出。此时可以拖动窗体到左、右、下部,松开鼠标后窗体会停驻在左、右、下部。操作窗体上的最大化、关闭按钮,可以让窗体最大化和关闭。还可以操作窗体的边框,向左、下、右拖动放大缩小窗体;鼠标点击任务栏的图标可以查找窗体当前的停靠位置。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/567304.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Scala 05 —— 函数式编程底层逻辑

Scala 05 —— 函数式编程底层逻辑 该文章来自2023/1/14的清华大学交叉信息学院助理教授——袁洋演讲。 文章目录 Scala 05 —— 函数式编程底层逻辑函数式编程假如...副作用是必须的&#xff1f;函数的定义函数是数据的函数&#xff0c;不是数字的函数如何把业务逻辑做成纯函…

多因素不同水平的正交表设计(并列法)

文章目录 一、问题提出二、举例说明 一、问题提出 参考高等教育课本《实验设计与数据处理》 很多时候&#xff0c;我们要考察的因素水平数不尽相同&#xff0c;这时候一般采用混合水平正交表或者对普通的正交表作修改&#xff0c;其中&#xff0c;混合水平正交表由于水平数不规…

JAVA程序设计-对象设计

无论是根据某马还是某谷的适配教程做项目时候,发现了大部分都是重复的crud,大部分只要做好笔记复习即可,但是却往往忘记了编码设计,所以这里开始复习编码设计,对象设计中,长期使用Mp的那一套导致就是Service Mapper,一套梭哈完了,这样很容易忘记基本功夫 POJO&#xff1a; 简单…

Java、Spring、Dubbo三者SPI机制原理与区别

Java、Spring、Dubbo三者SPI机制原理与区别 什么是SPI SPI全称为Service Provider Interface&#xff0c;是一种动态替换发现的机制&#xff0c;一种解耦非常优秀的思想&#xff0c;SPI可以很灵活的让接口和实现分离&#xff0c;让api提供者只提供接口&#xff0c;第三方来实…

刷题训练之二分查找

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握二分查找算法 > 毒鸡汤&#xff1a;学习&#xff0c;学习&#xff0c;再学习 ! 学&#xff0c;然后知不足。 > 专栏选自&#xff1a;刷题…

网卡技术解密:理解网卡背后的原理

✍✍在这个信息爆炸的时代&#xff0c;网卡承载着无数数据的流动&#xff0c;是我们日常生活和工作不可或缺的一部分。但是&#xff0c;您是否曾经好奇过&#xff0c;这些小小的硬件是如何在瞬息万变的网络世界中稳定地发挥作用的呢&#xff1f; 想象一下&#xff0c;每当我们…

2024中国内燃机展-北京汽车发动机零部件展

2024第二十三届中国国际内燃机与零部件展览会 由中国内燃机工业协会主办、中国机床专用技术设备有限公司、汽车工艺装备成套开发集团协办的2024中国国际内燃机及动力装备博览会&#xff08;简称“动博会”&#xff09;将于2024年10月11日-13日在亦创国际会展中心隆重举办。本届…

智能时代 | 合合信息Embedding模型荣获C-MTEB榜单第一

目录 前言 1. MTEB与C-MTEB 2. acge模型的优势 3. Embedding模型应用 4. 大模型发展的关键技术 结语 前言 随着人工智能的不断发展&#xff0c;大语言模型吸引着社会各界的广泛关注&#xff0c;支撑模型应用落地的Embedding模型成为业内的焦点&#xff0c;大模型的发展给…

Electron 30.0.0 发布,升级 Node 和 V8 引擎

近日&#xff0c;Electron 30.0.0 正式发布&#xff01;你可以通过 npm install electronlatest 进行安装&#xff0c;或者从 Electron 的发布网站下载&#xff0c;继续阅读了解此版本的详细信息。 &#x1f525; 主要更新 Windows 上支持 ASAR 完整性融合。如果未正确配置&am…

【后端】python与django的开发环境搭建指南

安装Git 双击Git 客户端安装文件&#xff0c;在安装页面&#xff0c;单击“Next” 在安装路径选择页面&#xff0c;保持默认&#xff0c;单击“Next” 在功能组件选择页面&#xff0c;保持默认&#xff0c;单击“Next” 在开始菜单文件夹设置页面&#xff0c;保持默认&am…

AI交互数字人对教育领域有何优势?

AI交互数字人不仅能够跨越物理距离的限制&#xff0c;以数字人形象为学生提供“面对面”教学互动体验&#xff0c;还能根据学生的具体需求提供个性化的知识解答。如天津大学推出了数字人老师&#xff0c;以刘艳丽教授形象1&#xff1a;1仿真打造的2.5D数字人&#xff0c;能够应…

png图片如何缩小体积?这个方法效果不错

图片压缩是我们生活中经常都会遇到的问题。在日常工作中图片体积过大的话&#xff0c;在使用过程中就会收到影响&#xff0c;比如加载过慢等。那么&#xff0c;当我们想要对png图片进行压缩处理的时候&#xff0c;要怎么操作呢&#xff1f;很简单&#xff0c;使用图片在线压缩&…

单链表逆置(头插法,递归,数据结构栈的应用)

链表逆置就是把最后一个数据提到最前面&#xff0c;倒数第二个放到第二个……依次类推&#xff0c;直到第一个到最后一个。 由于链表没有下标&#xff0c;所以不能借助下标来实行数据的逆置&#xff0c;要靠空间的转移来完成链表的逆置&#xff0c;这里采用没有头节点的链表来实…

Ansible安装基本原理及操作(初识)

作者主页&#xff1a;点击&#xff01; Ansible专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月23日15点18分 Ansible 是一款功能强大且易于使用的IT自动化工具&#xff0c;可用于配置管理、应用程序部署和云端管理。它使用无代理模式&#xff08;agentles…

学习笔记:Vue2高级篇

Vue2 学习笔记&#xff1a;Vue2基础篇_ljtxy.love的博客-CSDN博客学习笔记&#xff1a;Vue2中级篇_ljtxy.love的博客-CSDN博客学习笔记&#xff1a;Vue2高级篇_ljtxy.love的博客-CSDN博客 Vue3 学习笔记&#xff1a;Vue3_ljtxy.love的博客&#xff09;-CSDN博客 文章目录 7.…

STM32 HAL库F103系列之DAC实验(一)

DAC输出实验 原理图 DAC数据格式 DAC输出电压 DORX - 数据输出寄存器 Vref 3.3V 实验简要 1&#xff0c;功能描述 通过DAC1通道1(PA4)输出预设电压&#xff0c; 然后由ADC1通道1 (PA1) 采集&#xff0c;最后显示ADC转换的数字量及换算后的电压值 2&#xff0c;关闭通道1…

【已解决】三菱PLC与电脑通信步骤

前言 现场弄了一下一台三菱FX5U的PLC结果试了半天都没有连接上&#xff0c;后来琢磨了一下终于算是连接上了。报错的截图如下图所示&#xff1a; 解决步骤 第一步&#xff1a;先将自己电脑的IP地址设置到与PLC的IP地址在同一个网段下&#xff08;前三个是一样&#xff0c;最…

OpenWrt One/AP-24.XY 开源路由器发布,OpenWRT与Banana Pi社区合作

OpenWrt One/AP-24.XY 开源路由器 2024 年&#xff0c;OpenWrt 项目将迎来20 周年&#xff01;OpenWrt 开源社区官方通过推出社区自己的第一个完全上游支持的硬件设计来庆祝这一周年纪念日。并与联发科&#xff0c;Banana Pi开源社区紧密合作&#xff0c;共同完成硬件的设计与…

C++友元类

友元类 友元类的使用 友元不仅仅适合于友元函数&#xff0c;还可以将类作为友元&#xff0c;在这种情况下&#xff0c;友元类的所有方法都可以访问原始类的私有方法和保护成员&#xff0c;什么时候去使用友元类呢&#xff1f; 两个类之间不存在包含和所属关系&#xff0c;但…

HTML中的文档声明

前言 什么是<!DOCTYPE>&#xff1f;是否需要在 HTML5 中使用&#xff1f;什么是严格模式与混杂模式&#xff1f; 文档声明概念 HTML 文档通常以文档声明开始&#xff0c;该声明的作用是帮助浏览器确定其尝试解析和显示的 HTML 文档类型。 <!DOCTYPE html>文档声…