Click here to Skip to main content
13,146,742 members (79,750 online)
Click here to Skip to main content
Add your own
alternative version

Stats

9K views
754 downloads
15 bookmarked
Posted 10 May 2016

Tile Grid Control

, 10 May 2016
Rate this:
Please Sign up or sign in to vote.
An MFC CWnd derived grid of user definable tiles.

Introduction

This article presents a CWnd derived MFC control for presenting data as a dynamic grid of tiles. I use the term dynamic because the number of tiles in a row or column depends on the size of the window and the size of the tiles and the layout will change as the tile grid's window size changes. The tiles are layed out as a list where they fill one row or column at a time, rather than the traditional grid where tiles are layed out in designated rows and columns.

The idea for the control came from the tile view in Windows explorer. Originally I tried to twist the icon view of a CListCtrl to do what I wanted, but it was way too limited. First off I could not get the icons big enough for what I wanted, and it was also impossible to get the icons to respond to user input in any intelligent way.

I tried asking my old friend Google to see if she knew of any MFC controls that would do what I wanted, but there was no love found there either. So the only option left was to write a control from scratch that did exactly what I wanted. Presented here is the result.

The Tile Grid Control

The Tile Grid Control is made up of six MFC classes that work together to make the control do what needs to be done. The classes are listed below. I will not list the entire API of the classes here in this article as there are a total of one hundred and sixty one individual functions between the six classes. Listing them here would make this article way too long and make looking up the API way too unwieldy. I have instead included a compiled help file that lists all of the public and protected member functions.

The classes that make up the tile grid control are:

  • CTileGrid
  • The CTileGrid class is the main window class for the tile grid control. It is derived directly from CWnd. This class can be used directly as is, or more likely will serve as the base class for your own custom grid control. The CTileGrid class is responsible for maintaining the layout of all the tiles and for handling all windows messages related to the users interactions with the control.
  •  
  • CTileBase
  • The CTileBase class is the base class from which you would derive your own tile classes. CTileBase is derived from CObject and is declared as an abstact base class. It has a protected constructor so you can not directly construct a CTileBase class object . CTileBase::OnDraw is declared as a pure virtual function so in order to use this class you have to override OnDraw in your derived class to draw the tiles onto the grid.
  • Any user input that happens in the tile grid gets forwarded to the CTileBase tile that the input was directed towards. So the tiles can respond to any mouse actions, and if the tile has the keyboard input focus it can respond to any non-system key presses.
  •  
  • CWindowScroller
  • The CWindowScroller class is used to provide the middle mouse button panning control to the tile grid.
  •  
  • CTileGridTip
  • The CTileGridTip class is a simple CWnd derived class that acts as a single line tooltip window for the CTileGrid control. CTileGridTip can be used as is or it can be used as a base class for a more elaborate tooltip control.
  •  
  • CTileGridView
  • The CTileGridView class was written so the tile grid could be used in an SDI or MDI MFC Doc/View model application. CTileGridView is derived from CView. CTileGridView has a protected constructor so it can only be used as a base class for your own view class. It is a simple class that contains the CTileGrid control in it's client area.
  •  
  • TileBaseReturn
  • The TileBaseReturn class is used as the return value from the CTileGrid::GetTileReturn function. Many of the CTileGrid functions will call into CTileBase functions and the only way for derived classes to get the data returned from the CTileBase functions from within your CTileGrid derived class is to use CTileGrid::GetTileReturn.

Using the Tile Grid Control

The Tile Grid control can be used in many different applications. It can be used as a control on a dialog template, as the main window in a simple application, or as a view in a multiple or single document interface program. No matter which way it is used the first step to use the control in your own application is to add all the files to your project. The files are located in the "TileGrid" folder in the downloads.

The files needed are:

  • TileGrid.h, TileGrid.cpp
  • These files define the CTileGrid and TileBaseReturn classes.
  •  
  • TileBase.h, TileBase.cpp
  • These files define the CTileBase class.
  •  
  • TileGridTip.h, TileGridTip.cpp
  • These files define the CTileGridTip class.
  •  
  • WindowScroller.h, WindowScroller.cpp
  • These files define the CWindowScroller class.
  •  
  • TileGridView.h, TileGridView.cpp
  • These files define the CTileGridView class. The use of these files is optional as they are only needed if the tile grid is to be used as a view in a Doc/View application.

In a dialog template

To add the tile grid to a dialog template simply add it as a custom control and specify the required TGS_* creation styles in the 'Style' property. Add a CTileGrid or derived member variable to the dialog class and in your DoDataExchange function add a DDX_Control function to associate your member variable with the custom control.

void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
    DDX_Control(pDX, IDC_CUSTOM1, m_TileGrid);
}

That is it, now the tile grid can be accessed though the CTileGrid member variable.

See the TileGridDialog demo application included in the demo download for an example.

As the main window

To use the tile grid as the main window of an application without Doc/View support it is simply a matter of using the new app creation wizard to create an SDI app and make sure you clear the 'Document/View support' checkbox. Then it is simply a matter making sure your CChildView class is derived from CTileGrid or a class derived from it. Then in CMainFrame::OnCreate place a call to CChildView::Create to create the tile grid, specifying the TGS_* tile grid creation styles that are required.

class CChildView : public CTileGrid
    {
        ...
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
      return -1;

    // create a view to occupy the client area of the frame
    if (!m_wndView.Create(
        AFX_WS_DEFAULT_VIEW | TGS_RESIZABLE | TGS_MULTISELECT | TGS_PANNING,
        CRect(0, 0, 0, 0),
        this,
        AFX_IDW_PANE_FIRST,
        NULL))
    {
        TRACE0("Failed to create view window\n");
        return -1;
    }

See the TileGridView demo application included in the demo download for an example.

In a Doc/View application

To use the CTileGrid control in a CView derived window that can be used in an SDI/MDI application you have to derive your view class from CTileGridView. You then pass the RUNTIME_CLASS of the CTileGrid or derived class to the CTileGridView class constructor.

class CMyAppView : public CTileGridView
{
    DECLARE_DYNCREATE(CMyAppView)
    ...
CMyAppView::CMyAppView()
    : CTileGridView(RUNTIME_CLASS(CTileGrid))
    {
        ...

Set the TGS_* tile grid control styles from your view class' OnCreate member function.

int CMyAppView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    lpCreateStruct->style |= TGS_HORIZONTAL;
    return CTileGridView::OnCreate(lpCreateStruct);
}

See the TileGridDV demo application included in the demo download for an example.

Adding tiles

Once the tile grid window has been created you can add the tiles you want to use. Each tile that you use has to be of a class derived from CTileBase. Every class derived from CTileBase has to, at a minimum, define it's own OnDraw method that will draw the tile onto the tile grid.

The tiles are added to the grid using the CTileGrid::AddTile function. You will also want to set the size of the tiles using the CTileGrid::SetTileSize function. If you do not set the size all the tiles will default to their minimum 2 by 2 pixel size. You may also want to space the tiles apart by using the CTileGrid::SetTileSpacing function. The tiles will be tight together otherwise.

void CMyAppView::OnInitialUpdate()
{
    CTileGridView::OnInitialUpdate();

    CTileGrid& TheGrid = GetTileGrid();     // Get the tile grid
    TheGrid.SetTileSize(50, 50, false);     // all tiles are 50 by 50 pixels
    TheGrid.SetTileSpacing(2);              // 2 pixel space between tiles

    for (int x = 0; x < 50; ++x)            // add 50 tiles
    {
        CMyTile pTile = new CMyTile;        // CMyTile derived from CTileBase
        TheGrid.AddTile(pTile, true);
    }
}

Creating derived classes

ClassInheritableRuntime information macro
CTileBaseYes - RequiredDYNAMIC
CTileGridYes - OptionalDYNCREATE
CTileGridTipYes - OptionalDYNCREATE
CTileGridViewYes - RequiredDYNCREATE
CWindowScrollerNo-
TileBaseReturnNo-

In order to use the CTileBase and CTileGridView classes one has to derive your own classes from them. CTileGrid and CTileGridTip can be used as-is or they can serve as a base class for your own derived classes. The CWindowScroller and TileBaseReturn classes are helper classes and should not be inherited from.

CTileBase has been created using the DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC macros. While it is not neccesary for any derived classes to use these same macros, it is probably not a bad idea to use them.

If you inherit a class from CTileGrid, CTileGridView or CTileGridTip be sure to use the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE macros as these classes are created dynamically. In order to use a derived tooltip class as the tooltip control for the tile grid you have to call CTileGrid::SetTooltip, before CTileGrid::Create is called, specifying the runtime class of your derived tooltip class. If you are using a derived tooltip in a CTileGridView derived view then you would pass the runtime class of the tooltip as the second parameter to the CTileGridView constructor.

History

  • May 10, 2016 - Posted on CodeProject

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

PJ Arends
President
Canada Canada
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
GeneralMy vote of 5 Pin
Forhad Reza16-Nov-16 8:43
memberForhad Reza16-Nov-16 8:43 

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

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170915.1 | Last Updated 10 May 2016
Article Copyright 2016 by PJ Arends
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid