65.9K
CodeProject 正在变化。 阅读更多。
Home

吸附窗口

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.08/5 (7投票s)

2008年7月15日

CPOL

2分钟阅读

viewsIcon

37244

downloadIcon

1483

使窗口吸附到屏幕边缘的简单类

Window snaps to screen edges

引言

本文介绍了一个简单的类,可以使窗口吸附到桌面工作区域的边缘,就像流行的 Winamp 程序一样。工作区域是指未被系统任务栏或应用程序桌面工具栏遮挡的屏幕部分(如 MSDN 中所述)。要临时禁用在拖动窗口时的吸附,请按住吸附修改键(默认情况下为 Shift 键)。

本文重用了 Peter Hesselberg 的文章 Make it snappy 中的代码,因此建议先阅读它。 在 CodeProject 上还有类似的的文章,WTL 吸附分割窗口可自动隐藏的吸附工具窗口,但它们处理的是特定问题,而本文则提供了一种通用的方法。

代码

代码使用纯 Win32 API。下载包包括 Dev-C++ (GCC) 和 Win32/WTL VC2005 项目(使用 VC2005 Express + Platform SDK 2003 R2 + WTL 8.0 构建)。

吸附距离和吸附修改键存储在 snap_Marginsnap_ModifierKey 类的公共成员中。 默认情况下,吸附距离设置为窗口标题栏的高度,无吸附键为 Shift 键。 工作区域大小在 WM_ENTERSIZEMOVE 处理程序中检测,以便桌面大小更改时窗口可以正确吸附。 函数声明为 virtual ,因此您可以轻松地进行自己的窗口位置处理。

在 WTL 中使用代码

遵循通常的 WTL 实践,代码扩展为模板类。 将 CSnapWindow 添加到 CMainFrame 继承列表中并链接消息映射

//WTL example

#include "../Snapwindow.h"

class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
            public CMessageFilter, public CIdleHandler, public CSnapWindow<CMainFrame>

...

    BEGIN_MSG_MAP(CMainFrame)
        ...
        CHAIN_MSG_MAP(CSnapWindow<CMainFrame>)
    END_MSG_MAP()

在 Win32 中使用代码

创建一个类实例,并将类成员作为主窗口的消息处理程序添加

//Dev-C++ (GCC) example:

#include "SnapWindow.h"
CSnapWindow snapHandler;

...

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) /* handle the messages */
    {
    case WM_DESTROY:
        PostQuitMessage (0); /* send a WM_QUIT to the message queue */
    break;
/////////////////////////////////////////////
//snap handling
//
    case WM_MOVING:
        return snapHandler.OnSnapMoving(hwnd, message, wParam, lParam);
    break;
    case WM_ENTERSIZEMOVE:
        return snapHandler.OnSnapEnterSizeMove(hwnd, message, wParam, lParam);
    break;
//
/////////////////////////////////////////////
default: /* for messages that we don't deal with */
    return DefWindowProc (hwnd, message, wParam, lParam);
    }
return 0;
}

源代码

类的完整源代码在此处提供,以便您可以立即开始使用它

#ifndef _0C46500C_084D_44ac_8C26_37E38BED2714_
#define _0C46500C_084D_44ac_8C26_37E38BED2714_
#pragma once

#ifdef __ATLBASE_H__
template <class T> class CSnapWindow
#else
class CSnapWindow
#endif
{
public:
    int snap_Margin, snap_ModifierKey;

#ifdef __ATLBASE_H__
    BEGIN_MSG_MAP(CSnapWindow<T>)
        MESSAGE_HANDLER(WM_MOVING, OnSnapMoving)
        MESSAGE_HANDLER(WM_ENTERSIZEMOVE, OnSnapEnterSizeMove)
    END_MSG_MAP()
#endif

#ifdef __ATLBASE_H__ 
    virtual LRESULT OnSnapEnterSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam,
       BOOL& bHandled)
#else
    virtual LRESULT OnSnapEnterSizeMove(HWND hWnd, UINT message, WPARAM wParam,
       LPARAM lParam)
#endif
            {
                snap_cur_pos.x=0;
                snap_cur_pos.y=0;

                snap_rcWindow.bottom=0;
                snap_rcWindow.left=0;
                snap_rcWindow.right=0;
                snap_rcWindow.top=0;

            #ifdef __ATLBASE_H__ 
                T* pT = static_cast<T*>(this);
                GetWindowRect(pT->m_hWnd, &snap_rcWindow );
            #else
                GetWindowRect(hWnd, &snap_rcWindow );
            #endif

                    GetCursorPos( &snap_cur_pos );

                    snap_x = snap_cur_pos.x - snap_rcWindow.left;
                    snap_y = snap_cur_pos.y - snap_rcWindow.top;
                return 0;
                }

#ifdef __ATLBASE_H__ 
    virtual LRESULT OnSnapMoving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
#else
    virtual LRESULT OnSnapMoving(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
#endif
            {
                //no snap if modifier key pressed
                if (GetAsyncKeyState(snap_ModifierKey) < 0) return FALSE;

                snap_prc = (LPRECT)lParam;

                snap_cur_pos.x=0;
                snap_cur_pos.y=0;
                snap_rcWindow.bottom=0;
                snap_rcWindow.left=0;
                snap_rcWindow.right=0;
                snap_rcWindow.top=0;

                GetCursorPos( &snap_cur_pos );
                OffsetRect( snap_prc,
                        snap_cur_pos.x - (snap_prc->left + snap_x) ,
                        snap_cur_pos.y - (snap_prc->top + snap_y) );

                //working area may change during app lifetime
                SystemParametersInfo( SPI_GETWORKAREA, 0, &snap_wa, 0 );

                if (isSnapClose( snap_prc->left, snap_wa.left ))
                    {OffsetRect( snap_prc, snap_wa.left - snap_prc->left, 0);}
                else 
                    if (isSnapClose( snap_wa.right, snap_prc->right )) 
                        {OffsetRect( snap_prc, snap_wa.right - snap_prc->right, 0);}

                if (isSnapClose( snap_prc->top, snap_wa.top )) 
                    {OffsetRect( snap_prc, 0, snap_wa.top - snap_prc->top );}
                else 
                    if (isSnapClose( snap_wa.bottom, snap_prc->bottom )) 
                        {OffsetRect( snap_prc, 0, snap_wa.bottom - snap_prc->bottom );}
                return TRUE;
                }

    virtual BOOL isSnapClose( int a, int b ) { return (abs( a - b ) < snap_Margin);}

    CSnapWindow()
        {
        snap_ModifierKey=VK_SHIFT;
        NONCLIENTMETRICS ncm = { 0 };
        ncm.cbSize = sizeof ncm;
        SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
        snap_Margin=ncm.iCaptionHeight;
        }
private:
    POINT snap_cur_pos;
    RECT snap_rcWindow, snap_wa, *snap_prc;
    int snap_x, snap_y;
};
#endif//_0C46500C_084D_44ac_8C26_37E38BED2714_

问题/建议

请在此文章的留言板中发布任何问题/错误/建议。

© . All rights reserved.