Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 17 Jul 2006
Rate this:
Please Sign up or sign in to vote.
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 <span class="code-string">"stdafx.h"</span>
#include <span class="code-string">"GrippieTest.h"</span>
#include <span class="code-string">"Grippie.h"</span>

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Maksim Libenson
Web Developer
Israel Israel

Comments and Discussions

 
QuestionGreat job, thanks! PinmemberMartin Henk20-Feb-14 23:37 
QuestionVS 2008 [modified] Pinmemberchatnal16-Oct-08 9:17 
AnswerRe: VS 2008 Pinmemberzengkun10016-Sep-09 17:28 
GeneralMinor issues... PinmemberSteve Johnson (Sven)22-Apr-08 11:54 
QuestionDoes this work in VC6? PinmemberDavid Howe26-Jul-06 15:18 
AnswerRe: Does this work in VC6? PinmemberMaksim Libenson26-Jul-06 20:01 
AnswerRe: Does this work in VC6? Pinmembercristitomi19-Mar-07 2:23 
Generalanother approach: DrawFrameControl PinmemberMike D.24-Jul-06 10:59 
GeneralRe: another approach: DrawFrameControl PinmemberMaksim Libenson26-Jul-06 20:06 
GeneralGet a look to... PinmemberKochise18-Jul-06 6:20 
GeneralHandling of mouse pointer PinmemberJulberto Danray3-Jun-06 18:19 
GeneralRe: Handling of mouse pointer PinmemberMaksim Libenson3-Jun-06 23:35 
GeneralAvoiding paint side effects PinmemberJulberto Danray1-Jun-06 12:18 
GeneralRe: Avoiding paint side effects PinmemberPavel Yankelevich3-Jun-06 23:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140922.1 | Last Updated 18 Jul 2006
Article Copyright 2006 by Maksim Libenson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid