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

在没有状态栏的情况下获得窗口的尺寸调整柄(“grippie”)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.23/5 (17投票s)

2006年4月25日

CPOL

2分钟阅读

viewsIcon

77875

downloadIcon

1215

一篇描述如何向窗口添加大小调整柄控件的文章。

Sample Image - grippie.gif

引言

正如 Jensen Harris 提到的,许多应用程序为了获得一个调整大小的“grippie”而倾向于从用户那里窃取屏幕空间,仅仅是为了添加一个状态栏。

Girppie

这篇文章致力于在保持馅饼完整的同时吃掉它。我将向您展示如何在不使用状态栏的情况下添加“grippie”。

创建“grippie”

第一个惊喜是,grippie 实际上是一个滚动条。好吧,至少对我来说是个惊喜。由于我喜欢使用 MFC 进行 UI 工作,因此我选择一个 MFC 对话框应用程序来演示这个技巧。首先,我将对话框的边框样式设置为“Resizing”;否则,为什么还要费心使用“grippie”?在我的对话框中,我添加了一个类型为 CScrollBar 的新成员变量,如下所示

// GrippieTestDlg.h : header file

#pragma once
// CGrippieTestDlg dialog

class CGrippieTestDlg : public CDialog
{
public:
    CGrippieTestDlg(CWnd* pParent = NULL);
    enum { IDD = IDD_GRIPPIETEST_DIALOG };
protected:
    virtual void DoDataExchange(CDataExchange* pDX);
protected:
    HICON m_hIcon;
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedOk();
private:
    CScrollBar m_grippie;
};

现在,我为对话框的 WM_CREATE 消息添加一个处理程序,MFC 向导在我的对话框类中为我提供了处理程序 OnCreate(LPCREATESTRUCT lpCreateStruct)。我在处理程序中添加以下代码来创建我的“grippie”

#define GRIPPIE_SQUARE_SIZE 11

int CGrippieTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDialog::OnCreate(lpCreateStruct) == -1)
        return -1;

    CRect clientRect;
    GetClientRect(&clientRect);
    
    CRect grippieRect;
    grippieRect.right=clientRect.right;
    grippieRect.bottom=clientRect.bottom;
    grippieRect.left=clientRect.right-GRIPPIE_SQUARE_SIZE;
    grippieRect.top=clientRect.bottom-GRIPPIE_SQUARE_SIZE;
    m_grippie.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP|WS_CLIPSIBLINGS,
    grippieRect, this, 0);
    return 0;
}

我们这里有一个不错的“grippie”,并且运行良好。但是等等!当您调整窗口大小时,这该死的东西停留在同一个地方。好吧,没问题,我们将修复它。

在窗口大小调整时移动 grippie

我们将通过为对话框的 WM_SIZE 事件添加处理程序来修复它

void CGrippieTestDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);
    CRect clientRect;
    GetClientRect(&clientRect);
    if(m_grippie.m_hWnd!=NULL)
        m_grippie.SetWindowPos(NULL,
            clientRect.right-GRIPPIE_SQUARE_SIZE,
            clientRect.bottom-GRIPPIE_SQUARE_SIZE,
            GRIPPIE_SQUARE_SIZE,
            GRIPPIE_SQUARE_SIZE,
            SWP_NOZORDER|SWP_SHOWWINDOW);
}

现在,让我们把它包装在一个漂亮的类中。

CGrippie 类

我将在我的项目中添加一个类,该类派生自 CScrollBar 并称为 CGrippie

// Grippie.h : header file

#pragma once

#define GRIPPIE_SQUARE_SIZE 11

class CGrippie : public CScrollBar
{
    DECLARE_DYNAMIC(CGrippie)
    CGrippie(const CGrippie& other);
    void operator=(const CGrippie& other);
public:
    CGrippie();
    virtual ~CGrippie();
protected:
    DECLARE_MESSAGE_MAP()
public:
    BOOL Create(CWnd* parent);
    void OnParentSize(void);
private:
    CWnd* m_parent;
};

这是实现

// Grippie.cpp : implementation file

#include "stdafx.h"
#include "GrippieTest.h"
#include "Grippie.h"

IMPLEMENT_DYNAMIC(CGrippie, CScrollBar)

CGrippie::CGrippie()
{
    m_parent=NULL;
}

CGrippie::~CGrippie()
{
}

BEGIN_MESSAGE_MAP(CGrippie, CScrollBar)
END_MESSAGE_MAP()

BOOL CGrippie::Create(CWnd* parent)
{
    m_parent=parent;
    if(m_parent==NULL)
        return FALSE;
    CRect clientRect;
    m_parent->GetClientRect(&clientRect);
    
    CRect grippieRect;
    grippieRect.right=clientRect.right;
    grippieRect.bottom=clientRect.bottom;
    grippieRect.left=clientRect.right-GRIPPIE_SQUARE_SIZE;
    grippieRect.top=clientRect.bottom-GRIPPIE_SQUARE_SIZE;
    return CScrollBar::Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, 
                              grippieRect, m_parent, 0);
}

void CGrippie::OnParentSize(void)
{
    if(m_parent==NULL)
        return;
    CRect clientRect;
    m_parent->GetClientRect(&clientRect);
    if(m_hWnd!=NULL)
        SetWindowPos(NULL, clientRect.right-GRIPPIE_SQUARE_SIZE,
                clientRect.bottom-GRIPPIE_SQUARE_SIZE,
                GRIPPIE_SQUARE_SIZE, GRIPPIE_SQUARE_SIZE,
                SWP_NOZORDER|SWP_SHOWWINDOW);
}

现在,我们所需要做的就是将对话框类中的 m_grippie 变量的类型更改为 CGrippie,并像这样更改对话框消息处理程序的实现

int CGrippieTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDialog::OnCreate(lpCreateStruct) == -1)
        return -1;
    m_grippie.Create(this);
    return 0;
}

void CGrippieTestDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);
    m_grippie.OnParentSize();
}

好吧,如果您使用的是 VS2005,那么您现在就完成了,但对于 VS2003 代码,仍然需要处理一件小事:即当鼠标指针位于 grippie 区域中,但不在对话框的右下角时,鼠标指针的形状。形状应该是这样的: 正确的指针。但实际上,它是一个常规鼠标指针。

在 VS2003 中处理鼠标指针

为了解决这个问题,我将为 WM_SETCURSOR 消息添加一个处理程序。为此,我将向消息映射添加一个事件

BEGIN_MESSAGE_MAP(CGrippie, CScrollBar)
    ON_WM_SETCURSOR()
END_MESSAGE_MAP()

使用以下代码覆盖 CGrippie 中的父方法 OnSetCursor

BOOL CGrippie::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if ( pWnd == this  &&  nHitTest == HTCLIENT )
    {
        ::SetCursor( ::LoadCursor( NULL, IDC_SIZENWSE ) );
        return( TRUE );
    }
    return CScrollBar::OnSetCursor(pWnd, nHitTest, message);
}

好吧,就是这样!我们在对话框中有一个 grippie,而没有那个状态栏!

© . All rights reserved.