Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Getting a window size-grip (“grippie”) without the statusbar

0.00/5 (No votes)
17 Jul 2006 1  
An article that describes how to add a size-grip control to windows.

Sample Image - grippie.gif

Introduction

As mentioned by Jensen Harris, many applications tend to steal screen real-estate from the user by adding a status bar for the sole reason of getting a resize “grippie”:

Girppie

This article is dedicated to eating a pie while keeping it whole. I will show you how to add a “grippie” without using a status bar.

Creating the “grippie”

The first surprise is that a grippie is in fact a scroll bar. Well, at least, it was a surprise for me. Since I am fond of MFC for UI jobs, I am choosing an MFC dialog application to show the trick. First of all, I set my dialog border style to “Resizing”; otherwise, why bother with “grippie” at all? In my dialog, I add a new member variable of type CScrollBar, like this:

// 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;
};

Now, I add a handler for the dialog’s WM_CREATE message and the MFC wizard provides me with the handler OnCreate(LPCREATESTRUCT lpCreateStruct) in my dialog class. I add the following code in the handler to create my “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;
}

Here we are with a nice “grippie”, and it works fine. But wait! The damn thing stays in the same place when you resize the window. Well, no problem, we are going to fix that.

Moving the grippie on window resize

We will fix it by adding a handler for the dialog’s WM_SIZE event:

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);
}

Now, let’s wrap it up in a nice class.

CGrippie class

I will add a class to my project that is derived from CScrollBar and is called 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;
};

Here is the implementation:

// 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);
}

Now, all we need is to change the type of the m_grippie variable in the dialog class to CGrippie and change the implementation of the dialog message handlers like this:

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();
}

Well, in case you are using VS2005, you are done now, but for VS2003 code, there is still a small thing to be handled: that is the mouse pointer shape when it is in the grippie area, but not in the bottom-right corner of the dialog. The shape should be like this: Correct cursor. But instead, it is a regular mouse pointer.

Handling the mouse pointer in VS2003

To fix the problem, I am going to add a handler for the WM_SETCURSOR message. To do so, I am going to add an event to the message map:

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

Override the parent method OnSetCursor in CGrippie with the following code:

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);
}

Well, that is it! We have a grippie in the dialog without that status bar!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here