zoukankan      html  css  js  c++  java
  • WinForm上扩展

    Screen_Shot.jpg 介绍 在本文中,我将向您展示一个扩展版本的Windows表单。它比。net框架提供的常规表单具有更多的特性。 最初,我分别实现了这些特性,以帮助MSDN用户处理他们的请求。因此,我决定将它们组合在一起,构建一个在本文中展示的表单。 FormEx的其他功能包括: 标题栏上的漆,形成框架将表单附加到桌面,像Windows Vista和7栏设置形式在全屏模式下(涵盖了包括任务栏)使不动的形式使表单Unsizable(即使FormBorderStyle不固定)得到KeyState(上下/切换和Untoggled)随时禁用窗口的关闭按钮的标题栏。 除了获得键状态外,所有这些特性都可以通过设计器使用,因此使用起来非常容易,我将在下面解释。 使用的代码 正如我提到的,使用这些特性非常容易。在提供的示例项目中,您可以像屏幕截图一样看到它们中的每一个。我们将逐一介绍它们,但首先,让我们看看如何使用该表单。 有两种方法可以将新表单添加到解决方案中: 将本文顶部提供的二进制文件添加到您的项目中。你可以点击解决方案资源管理器->你的项目→右键单击引用…→添加引用…→浏览→或者,您可以将项目包含在源代码中(也提供了),并像上面一样添加引用,但是选择Projects而不是Browse。 完成这些之后,就可以开始编码了。首先从项目中选择一个表单并编辑其源代码。你将不得不修改它来继承FormEx而不是形式: 隐藏,复制Code

    using FormExNS;
    
    namespace TestProject
    {
        public partial class TestForm : FormEx
        { 

    现在,到特点: 1 -在标题栏和窗体框架上绘制: 正如您在屏幕截图中看到的,我在标题栏上画了图。为此,我实现了一个新事件:PaintFrameArea。您所要做的就是进入设计器中的事件并创建一个事件处理程序,就像使用Paint方法一样。它的工作原理完全相同,图形对象被设置为覆盖整个窗口减去客户区域。 这是在Windows以其主题样式绘制窗口之后完成的,因此在调整大小时可能会遇到一些闪烁。您也不应该在控制框上绘制,因为它将覆盖最小化、最大化和关闭按钮(但不是永远,如果您将鼠标移到它们上面,它们将重新出现)。 2 -将表格附在桌面上: 我添加了一个名为DesktopAttached的新属性。通过将该属性设置为true,窗口将“粘”在桌面上,而不会显示在任务栏上。它将在所有常规窗口的下面,很像窗口的侧边栏。 3 -全屏模式: 我添加了一个名为FullScreen的新属性。通过将此属性设置为true,该窗口将占据当前监视器的所有区域,并将始终位于任务栏和任何其他非顶层窗口之上。请注意,如果您将此与DesktopAttached结合使用,该窗口将占据整个屏幕,但将保留在每个窗口和任务栏下。还要注意,当您再次将FullScreen设置为false时,窗口将自动记住它以前的状态。 4 -活动: 我添加了一个名为Movable的新属性。通过将该属性设置为false,该窗口将不再是可移动的。用户将无法通过拖动窗口的标题栏来移动窗口。当窗体不可移动时,也意味着它也没有大小 5 -相当大: 我添加了一个名为可观的新属性。通过将此属性设置为false,该窗口将不再具有可伸缩性,尽管其FormBorderStyle被设置为可伸缩性。如果您想要一个大小相当的窗体的外观,但又想修复它,那么这可能非常有用。该财产不与动产相冲突。 6 -获取键状态: 我为表单添加了两个与KeyState相关的新方法。它们是: GetKeyState(Keys key) -返回类型为枚举,它有两个可能的值:0 - KeyState。上升和1 -关键状态,下降。该参数是Windows窗体提供的标准键值enum (KeyValue GetKeyValue(Keys key)) -返回类型为有两个可能的值:0 - KeyValue。Untoggled和1 -键值。该参数是Windows窗体提供的标准键枚举 7 - CloseButton: 我添加了一个名为关闭按钮的新属性。通过将该属性设置为false,窗口关闭按钮将变成灰色,用户将不再能够关闭窗体。如果父窗体关闭、任务管理器关闭应用程序、窗口关闭或调用application . exit(),则该窗体仍然是可关闭的。 代码是如何工作的 Windows桌面开发人员经常忽略的一件事是表示层是如何工作的。你有没有想过Windows如何处理大小调整,cli盛泰、移动和窗户吗? Windows是通过消息传递系统。每次一个窗口需要重绘,WM_PAINT(客户区)或WM_NCPAINT(框架区)消息发送到表单。当鼠标移到一个表单,表单的大小或移动,也发送一条消息到表单(有时每秒数以百计的消息)。所以发生了几乎所有形式(事件在。net)的形式是通过消息。所有控件和表单在Windows窗体框架实现空指向(ref消息m)方法。所有消息被发送通过这种方法,他们处理的地方。特点1、4和5是直接实现通过重写这个方法和治疗正确的消息。功能3,也部分地依赖于覆盖这个方法。 消息结构,我用三个属性: 味精——这是实际的窗口消息发送到表单按钮——消息的参数(W意味着词,但这只是历史,它实际上是一个长)LParam——另一个消息的参数正确(L代表长) 常量: 隐藏,收缩,复制Code

    //Parameters to EnableMenuItem Win32 function
    private const int SC_CLOSE = 0xF060; //The Close Box identifier
    private const int MF_ENABLED = 0x0;  //Enabled Value
    private const int MF_DISABLED = 0x2; //Disabled Value
    
    //Windows Messages
    private const int WM_NCPAINT = 0x85;//Paint non client area message
    private const int WM_PAINT = 0xF;//Paint client area message
    private const int WM_SIZE = 0x5;//Resize the form message
    private const int WM_IME_NOTIFY = 0x282;//Notify IME Window message
    private const int WM_SETFOCUS = 0x0007;//Form.Activate message
    private const int WM_SYSCOMMAND = 0x112; //SysCommand message
    private const int WM_SIZING = 0x214; //Resize Message
    private const int WM_NCLBUTTONDOWN = 0xA1; //L Mouse Btn on Non-Client Area is Down
    private const int WM_NCACTIVATE = 0x86; //Message sent to the window when it's
                                            //activated or deactivated
                                            
    //WM_SIZING WParams that stands for Hit Tests in the direction the form is resizing
    private const int HHT_ONHEADER = 0x0002; 
    private const int HT_TOPLEFT = 0XD; 
    private const int HT_TOP = 0XC; 
    private const int HT_TOPRIGHT = 0XE;
    private const int HT_RIGHT = 0XB;
    private const int HT_BOTTOMRIGHT = 0X11;
    private const int HT_BOTTOM = 0XF;
    private const int HT_BOTTOMLEFT = 0X10;
    private const int HT_LEFT = 0XA;
    
    //WM_SYSCOMMAND WParams that stands for which operation is being done
    private const int SC_DRAGMOVE = 0xF012; //SysCommand Dragmove parameter
    private const int SC_MOVE = 0xF010; //SysCommand Move with keyboard command

    如果你看一下覆盖指向甲酰类的方法,你会发现我截取一些消息: 隐藏,复制Code

    // Prevents moving or resizing through the task bar
    if ((m.Msg == WM_SYSCOMMAND && (m.WParam == new IntPtr(SC_DRAGMOVE) 
        || m.WParam == new IntPtr(SC_MOVE))))
    {
        if (m_FullScreen || !m_Movable)
            return;
    }
    
    // Prevents Resizing from dragging the borders
    if (m.Msg == WM_SIZING || (m.Msg == WM_NCLBUTTONDOWN && 
    
        (m.WParam == new IntPtr(HT_TOPLEFT) || m.WParam == new IntPtr(HT_TOP)
        || m.WParam == new IntPtr(HT_TOPRIGHT) || m.WParam == new IntPtr(HT_RIGHT) 
        
        || m.WParam == new IntPtr(HT_BOTTOMRIGHT)
        || m.WParam == new IntPtr(HT_BOTTOM) 
        
        || m.WParam == new IntPtr(HT_BOTTOMLEFT) 
        || m.WParam == new IntPtr(HT_LEFT))))
    {
        if (m_FullScreen || !m_Sizable || !m_Movable)
            return;
    }

    正如上面你可以看到的,我拦截WM_SYSCOMMAND信息防止窗口移动。我不能简单地拦截这个消息只用于其他功能的一个窗口,我还检查按钮参数,验证如果WM_SYSCOMMAND消息的类型,试图移动窗口。如果是,我返回的消息被丢弃,所以不会移动的窗口。 您可能想知道为什么我根本不会保存窗口的位置,每次用户试图移动形式。这不是一个好的解决方案的消息将会发送消息,尽管将发生非常快,您可以看到形式移动和它不好看,表单将游标后,将闪烁巨大而你按住鼠标按钮。 块,我拦截弹出式和WM_NCLBUTTONDOWN防止形式调整。弹出发送当用户试图改变窗口的大小的下拉菜单,当你单击表单的图标,并发送WM_NCLBUTTONDOWN每当用户左击的非客户区形式。这个消息与击中测试参数(按钮)让应用程序确定用户是否点击表单的边缘,可调整大小的。如果消息落在这种情况下,我还和消息被丢弃,防止表单大小。 如果以上条件都满足,我将消息转发到基础形式(基地。指向(ref);正常)的加工。这确保了剩下的一个窗口的行为改变。 最后,但并非最不重要,有绘画的处理的非客户区。它完成后调用基础。指向(ref),所以有机会的窗口画自己的边界的主题风格。后来我也拦截消息所以我可以让用户自定义绘图在原图。我拦截的消息是WM_NCPAINT WM_IME_NOTIFY,弹出式和ncactivate消息。所有这些导致非客户区重绘。ncactivate消息消息发送形式失去焦点时,改变其活动状态: 隐藏,收缩,复制Code

    base.WndProc(ref m);
    
    // Handles painting of the Non Client Area
    if (m.Msg == WM_NCPAINT || m.Msg == WM_IME_NOTIFY || m.Msg == WM_SIZE 
        || m.Msg == 0x86)
    {
        // To avoid unnecessary graphics recreation and thus improving performance
        if (m_GraphicsFrameArea == null || m.Msg == WM_SIZE)
        {
            ReleaseDC(this.Handle, m_WndHdc); //Release old handle
            m_WndHdc = GetWindowDC(this.Handle); //Get Graphics of full window area
            m_GraphicsFrameArea = Graphics.FromHdc(m_WndHdc);
            
            Rectangle clientRecToScreen = new Rectangle(
              this.PointToScreen(new Point(this.ClientRectangle.X, 
              this.ClientRectangle.Y)), new System.Drawing.Size(
              this.ClientRectangle.Width, this.ClientRectangle.Height));
              
            Rectangle clientRectangle = new Rectangle(clientRecToScreen.X - 
            this.Location.X, clientRecToScreen.Y - this.Location.Y, 
            clientRecToScreen.Width, clientRecToScreen.Height);
            
            m_GraphicsFrameArea.ExcludeClip(clientRectangle); //Remove client area
        }
        
        RectangleF recF = m_GraphicsFrameArea.VisibleClipBounds;
        
        PaintEventArgs pea = new PaintEventArgs(m_GraphicsFrameArea, new 
          Rectangle((int)recF.X, (int)recF.Y, (int)recF.Width, (int)recF.Height));
          
        OnPaintFrameArea(pea);
        CloseBoxEnable(m_EnableCloseButton);
        this.Refresh(); //Forces repainting of the client area to remove shadows
    } 

    基本上,我在这里做的实现需要重画窗口后: 通过窗口的DeviceContext GetWindowDC Win32 API调用。从设备上下文中,我创建的图形对象将包含整个窗口,不仅客户区普通漆事件。排除该地区的客户区(ExcludeClip),我们想限制只有这幅画。创建PaintEventArgs我们地区的窗口和图形对象,我们可以通过它来新的事件处理程序。使调用OnPaintFrameArea处理我们的新PaintFrameArea事件,通过新创建的PaintEventArgs变量。刷新客户区,因为当用户调整表格的大小,位置和图纸仍将得到“阴影效应”在绘画的形式。 Aero玻璃 当前版本的文章,绘画的Aero玻璃不支持Windows 7 / Vista。与常规的窗户,Aero不是画的形式,它使用DWM[^]这幅画。出于这个原因,绘画拦截WM_NCPAINT不会没有禁用航空工作。我计划很快扩展本文也覆盖的河网。 其他功能呢? 所以如何功能2、3、6、7 ?好吧,他们也和Windows消息传递系统,但是我没有直接改变行为治疗的消息,我让操作系统API调用。 非常有用的东西,大多数开发人员在日常生活中我看到小姐,di是互操作的能力直接说到操作系统。大多数Windows窗体框架只不过是本地OS资源的包装器。我在这里所做的几乎是一样的。我为API调用构建了一个包装器,它不是以普通形式实现的。 下面是使特性2、3、6和7成为可能的所有Win32 API调用。它们对代码的注释是不言自明的。要使用它,您需要引用System.Runtime。InteropServices名称空间。只是把它作为一个使用语句的头的CS文件: 隐藏,收缩,复制Code

    //GetSystemMenu Win32 API Declaration (The Window Title bar is SystemMenu)
    [DllImport("user32.dll")]
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
    
    //EnableMenuItem Win32 API Declaration (Set the enabled values of the 
    //title bar items)
    [DllImport("user32.dll")]
    private static extern int EnableMenuItem(IntPtr hMenu, int wIDEnable, int wValue);
    
    //Get Desktop Window Handle
    [DllImport("user32.dll")]
    private static extern IntPtr GetDesktopWindow();
    
    //Set Parent Window, used to set the desktop's parent as the window parent
    [DllImport("user32.dll")]
    private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    
    //Find any Window in the OS. We will look for the parent of where the desktop is
    [DllImport("User32.dll")]
    public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
    
    //Get the device component of the window to allow drawing on the title bar and 
    //frame
    [DllImport("User32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);
    
    //Releases the Device Component after it's been used
    [DllImport("User32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    正如您所看到的,所有的api都可以将许多我们认为不可能的事情变为可能。实际上,你可以通过这些调用做很多事情。如果您查看下面链接的API引用,您将能够找到本文中使用的每一个方法。例如,在引用中,有ReleaseDC方法: 隐藏,复制Code

    int ReleaseDC(
      __in  HWND hWnd,
      __in  HDC hDC
    );

    这在c#中不起作用,因为它没有HWND或HDC类型。剩余的in告诉我们该方法将读取该参数,而不会输出。这些类型是指向句柄的指针,因此我们可以简单地用IntPtr . net Framework提供的方法替换它们。返回类型很明显,一个整数。 的兴趣点 为了实现所有这些特性,我必须对user32.dll的Win32 api进行多次调用。最烦人的部分是获取所有发送到表单的正确窗口消息和常量值,因为。net框架没有这些消息的任何映射。 作为一种资源,我使用MSDN的Windows API参考,Visual c++ winuser.h头文件和Visual Studio的输出窗口来观察传入的消息(System.Diagnostics.Debug.WriteLine),因为我搅和了表单使其重新绘制。这就是消息0x86(WM_NCACTIVATE)的情况,在本文的前一个版本中没有标记它,因为我没有找到合适的文档(感谢Spectre2x)。 我希望您喜欢这些代码。请随意留下你的反馈。 历史 2010年7月15日-文章发表于2010年7月20日-更新指出0x86消息标签。代码和文章的完整更新将在2010年7月21日完成——更新为在项目和文章上标注0x86 Message。还添加了一个注意到Aero支持 本文转载于:http://www.diyabc.com/frontweb/news5028.html

  • 相关阅读:
    LG4377 「USACO2018OPEN」Talent Show 分数规划+背包
    LG4111/LOJ2122 「HEOI2015」小Z的房间 矩阵树定理
    LG5104 红包发红包 概率与期望
    LG2375/LOJ2246 「NOI2014」动物园 KMP改造
    LG4824 「USACO2015FEB」(Silver)Censoring KMP+栈
    20191004 「HZOJ NOIP2019 Round #9」20191004模拟
    LG5357 「模板」AC自动机(二次加强版) AC自动机+fail树
    LG3812 「模板」线性基 线性基
    数据结构
    git
  • 原文地址:https://www.cnblogs.com/Dincat/p/13462193.html
Copyright © 2011-2022 走看看