Introduction
This tutorial looks at the month calender control.
Creating a month calender
Firstly, we need to include the common control header file using #include <CommCtrl.h>. Without that, none of the status bar definitions will be available to us. Secondly, we need to initialize the common controls using InitCommonControlsEx, in order that we can use the month calender control. The following four lines of code will do that.
INITCOMMONCONTROLSEX common_controls;
common_controls.dwSize = sizeof(INITCOMMONCONTROLSEX);
common_controls.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&common_controls);
We are now ready to use the month calender control.
The code below creates a frame window with the entire year's calender displayed.
#include <windows.h>
#include <CommCtrl.h>
#include <ctime>
#include <cstdlib>
using namespace std;
#pragma comment(lib, "comctl32.lib")
class frame_window {
private:
LPWSTR window_class_name;
HINSTANCE instance_handle;
HCURSOR cursor_arrow;
HWND window_handle;
HWND calender_handle;
RECT client_rectangle;
public:
frame_window(LPWSTR window_class_identity) : window_class_name(window_class_identity) {
INITCOMMONCONTROLSEX common_controls;
common_controls.dwSize = sizeof(INITCOMMONCONTROLSEX);
common_controls.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&common_controls);
int screen_width = GetSystemMetrics(SM_CXFULLSCREEN);
int screen_height = GetSystemMetrics(SM_CYFULLSCREEN);
instance_handle = GetModuleHandle(NULL);
WNDCLASS window_class = { CS_OWNDC, main_window_proc, 0, 0,
instance_handle, NULL,
NULL, NULL, NULL,
window_class_name };
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create a standard frame window
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RegisterClass(&window_class);
window_handle = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
window_class_name,
L"Month Calender Example",
WS_OVERLAPPEDWINDOW |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
(screen_width-900)/2, (screen_height-700)/2,
900, 700,
NULL, NULL, instance_handle, NULL);
GetClientRect(window_handle, &client_rectangle);
int width = client_rectangle.right - client_rectangle.left;
int height = client_rectangle.bottom - client_rectangle.top;
calender_handle = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
MONTHCAL_CLASS, NULL,
WS_CHILD | WS_VISIBLE | MCS_MULTISELECT,
10, 10, width-20,
height-20, window_handle, NULL,
instance_handle, NULL);
SetCursor(LoadCursor(NULL, IDC_ARROW));
SetWindowLongPtr(window_handle, GWL_USERDATA, (LONG)this);
ShowWindow(window_handle, SW_SHOW);
UpdateWindow(window_handle);
}
~frame_window() {
UnregisterClass(window_class_name, instance_handle);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows message processing function
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static LRESULT WINAPI main_window_proc(HWND window_handle, UINT message,
WPARAM wparam, LPARAM lparam) {
frame_window *This = (frame_window *)GetWindowLongPtr(window_handle, GWL_USERDATA);
switch ( message ) {
case WM_PAINT:
{
PAINTSTRUCT paint_structure;
RECT client_rect;
HDC paint_device_context, paint_dc;
HBITMAP bitmap;
paint_device_context = BeginPaint(window_handle, &paint_structure);
paint_dc = CreateCompatibleDC(paint_device_context);
GetClientRect(window_handle, &client_rect);
int window_width = client_rect.right - client_rect.left;
int window_height = client_rect.bottom - client_rect.top;
bitmap = CreateBitmap(window_width, window_height, 1, 32, NULL);
HGDIOBJ old_bitmap = SelectObject(paint_dc, bitmap);
// Fill the client aread with the user selected face colour
HBRUSH light_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
FillRect(paint_dc, &paint_structure.rcPaint, light_brush);
DeleteObject(light_brush);
BitBlt(paint_device_context, 0, 0,
client_rect.right-client_rect.left,
client_rect.bottom-client_rect.top,
paint_dc, 0, 0, SRCCOPY);
SelectObject(paint_dc, old_bitmap);
DeleteObject(bitmap);
DeleteDC(paint_dc);
EndPaint(window_handle, &paint_structure);
return 0;
}
case WM_ERASEBKGND:
{
return TRUE;
}
case WM_SIZE:
{
InvalidateRect(window_handle, NULL, TRUE);
return 0;
}
case WM_COMMAND:
{
return 0;
}
case WM_CLOSE:
{
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// The user wants to close the window
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(window_handle, message, wparam, lparam);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows message loop
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void run() {
MSG window_message;
while ( GetMessage(&window_message, NULL, 0, 0) ) {
TranslateMessage(&window_message);
DispatchMessage(&window_message);
}
}
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows main entry point
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI wWinMain(HINSTANCE instance_handle, HINSTANCE, LPWSTR, INT) {
frame_window main_window(L"my base window");
main_window.run();
return 0;
}
Now, unless we were specifically writing some sort of calender program, that is probably over the top. So we will modify the code to display just one month. To do this, we need to know how much real estate the calender control needs to display one month. To do this, we use the SendMessage function specifying a MCM_GETMINREQRECT message, and provide an address for the rectangle that the function will use to return the size required. A code snippet is provided below.
RECT calender_rectangle;
SendMessage(calender_handle, MCM_GETMINREQRECT, 0, (LPARAM)&calender_rectangle);
Getting information from the control
The parent window is notified of a specific date change through the WM_NOTIFY message that is sent to the parent window, the notification code is MCN_SELECT. To obtain a date range selected by the user, look for the MCN_SELCHANGE notification code.
Code Example
The following code example displays the selected date range (which by default is limited to one week).
#include <windows.h>
#include <CommCtrl.h>
#include <ctime>
#include <cstdlib>
using namespace std;
#pragma comment(lib, "comctl32.lib")
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' " \
"version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
class frame_window {
private:
LPWSTR window_class_name;
HINSTANCE instance_handle;
HCURSOR cursor_arrow;
HWND window_handle;
HWND calender_handle;
RECT client_rectangle;
SYSTEMTIME start_time;
SYSTEMTIME end_time;
static wchar_t * weekday[7];
static wchar_t * month[12];
public:
frame_window(LPWSTR window_class_identity) : window_class_name(window_class_identity) {
INITCOMMONCONTROLSEX common_controls;
common_controls.dwSize = sizeof(INITCOMMONCONTROLSEX);
common_controls.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&common_controls);
int screen_width = GetSystemMetrics(SM_CXFULLSCREEN);
int screen_height = GetSystemMetrics(SM_CYFULLSCREEN);
instance_handle = GetModuleHandle(NULL);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Initialize the start and end time
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
GetSystemTime(&start_time);
GetSystemTime(&end_time);
WNDCLASS window_class = { CS_OWNDC, main_window_proc, 0, 0,
instance_handle, NULL,
NULL, NULL, NULL,
window_class_name };
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create a standard frame window
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RegisterClass(&window_class);
window_handle = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
window_class_name,
L"Month Calender Example",
WS_OVERLAPPEDWINDOW |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
(screen_width-900)/2, (screen_height-700)/2,
900, 700,
NULL, NULL, instance_handle, NULL);
GetClientRect(window_handle, &client_rectangle);
int width = client_rectangle.right - client_rectangle.left;
int height = client_rectangle.bottom - client_rectangle.top;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create the calender window
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
calender_handle = CreateWindowEx(0, MONTHCAL_CLASS, NULL,
WS_CHILD | WS_VISIBLE | MCS_MULTISELECT,
0, 0, 0, 0, window_handle, NULL,
instance_handle, NULL);
RECT calender_rectangle;
SendMessage(calender_handle, MCM_GETMINREQRECT, 0, (LPARAM)&calender_rectangle);
SetWindowPos(calender_handle, NULL, 10, 10,
calender_rectangle.right-calender_rectangle.left,
calender_rectangle.bottom-calender_rectangle.top,
SWP_NOZORDER);
SetCursor(LoadCursor(NULL, IDC_ARROW));
SetWindowLongPtr(window_handle, GWL_USERDATA, (LONG)this);
ShowWindow(window_handle, SW_SHOW);
UpdateWindow(window_handle);
}
~frame_window() {
UnregisterClass(window_class_name, instance_handle);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows message processing function
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static LRESULT WINAPI main_window_proc(HWND window_handle, UINT message,
WPARAM wparam, LPARAM lparam) {
frame_window *This = (frame_window *)GetWindowLongPtr(window_handle, GWL_USERDATA);
switch ( message ) {
case WM_PAINT:
{
PAINTSTRUCT paint_structure;
RECT client_rect;
HDC paint_device_context, paint_dc;
HBITMAP bitmap;
paint_device_context = BeginPaint(window_handle, &paint_structure);
paint_dc = CreateCompatibleDC(paint_device_context);
GetClientRect(window_handle, &client_rect);
int window_width = client_rect.right - client_rect.left;
int window_height = client_rect.bottom - client_rect.top;
bitmap = CreateBitmap(window_width, window_height, 1, 32, NULL);
HGDIOBJ old_bitmap = SelectObject(paint_dc, bitmap);
// Fill the client aread with the user selected face colour
HBRUSH light_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
FillRect(paint_dc, &paint_structure.rcPaint, light_brush);
DeleteObject(light_brush);
// Display the dates selected
wchar_t buffer[256];
wsprintf(buffer, L"From %s %d %s %d to %s %d %s %d",
weekday[This->start_time.wDayOfWeek],
This->start_time.wDay,
month[This->start_time.wMonth-1],
This->start_time.wYear,
weekday[This->end_time.wDayOfWeek],
This->end_time.wDay,
month[This->end_time.wMonth-1],
This->end_time.wYear);
SetBkColor(paint_dc, GetSysColor(COLOR_BTNFACE));
SetTextColor(paint_dc, 0);
DrawText(paint_dc, buffer, wcslen(buffer), &client_rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
BitBlt(paint_device_context, 0, 0,
client_rect.right-client_rect.left,
client_rect.bottom-client_rect.top,
paint_dc, 0, 0, SRCCOPY);
SelectObject(paint_dc, old_bitmap);
DeleteObject(bitmap);
DeleteDC(paint_dc);
EndPaint(window_handle, &paint_structure);
return 0;
}
case WM_ERASEBKGND:
{
return TRUE;
}
case WM_SIZE:
{
InvalidateRect(window_handle, NULL, TRUE);
return 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Process the notify message from the month control
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
case WM_NOTIFY:
{
LPNMSELCHANGE selection_change = (LPNMSELCHANGE)lparam;
if ( selection_change->nmhdr.code == MCN_SELCHANGE ) {
memcpy(&This->start_time, &selection_change->stSelStart, sizeof(SYSTEMTIME));
memcpy(&This->end_time, &selection_change->stSelEnd, sizeof(SYSTEMTIME));
}
InvalidateRect(window_handle, NULL, TRUE);
return 0;
}
case WM_COMMAND:
{
return 0;
}
case WM_CLOSE:
{
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// The user wants to close the window
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(window_handle, message, wparam, lparam);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows message loop
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void run() {
MSG window_message;
while ( GetMessage(&window_message, NULL, 0, 0) ) {
TranslateMessage(&window_message);
DispatchMessage(&window_message);
}
}
};
wchar_t * frame_window::weekday[7] = { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" };
wchar_t * frame_window::month[12] = { L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Windows main entry point
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI wWinMain(HINSTANCE instance_handle, HINSTANCE, LPWSTR, INT) {
frame_window main_window(L"my base window");
main_window.run();
return 0;
}
This post has been edited by Martyn.Rae: 24 March 2010 - 08:42 AM





MultiQuote



|