Cette source permet d'avoir un calendrier mensuel directement affiché sur le bureau.
Cette source permet notament de voir la techinque du double-buffering.
Pour ceux qui ne savent pas ce que c'est : rapide aperçu...
En gros si on dessine au fur et à mesure un dessin à l'écran à chaque fois qu'on recommence ça ferait apparaitre un clignotement. Pour éviter cela, on dessine dans un buffer (sorte d'écran virtuel) et quand le dessin est terminé on bascule le buffer à l'écran. Du coup on ne voit plus les étapes intermédiaires.
PS : pour configurer le calendrier (couelurs, positions, ...) c'est au tout début du code
Source / Exemple :
//////////////////////////////////////////////////////////////
// Include
//////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
//////////////////////////////////////////////////////////////
// Paramètres du calendrier
//////////////////////////////////////////////////////////////
#define POSITION_X 700
#define POSITION_Y 5
#define ESPACEMENT_HORIZONTAL 30
#define ESPACEMENT_VERTICAL 20
#define FORECOLOR RGB(0,0,0)
#define BACKCOLOR RGB(255,255,255)
#define JOURCOLOR RGB(255,32,32)
#define REFRESH_RATE 1000
//////////////////////////////////////////////////////////////
// Variables globales
//////////////////////////////////////////////////////////////
HWND hDesk;
RECT fullRect;
short nJours[6][7];
SYSTEMTIME st;
char* cJours[7];
//////////////////////////////////////////////////////////////
// Fonctions
//////////////////////////////////////////////////////////////
/**
- Récupère le HWND du bureau
- /
HWND FindDesktopWindow()
{
HWND hWnd = FindWindow("Progman", "Program Manager");
if(GetParent(hWnd) == NULL)
{
HWND hWndEnfant = GetWindow(hWnd, GW_CHILD);
char szBuf[32];
while(hWndEnfant != NULL)
{
GetClassName(hWndEnfant, szBuf, sizeof(szBuf));
if(lstrcmp(szBuf, "SHELLDLL_DefView") == 0)
break;
hWndEnfant = GetWindow(hWndEnfant, GW_HWNDNEXT);
}
if(hWndEnfant != NULL)
{
hWndEnfant = GetWindow(hWndEnfant, GW_CHILD);
while(hWndEnfant != NULL)
{
GetClassName(hWndEnfant, szBuf, sizeof(szBuf));
if(lstrcmp(szBuf, "SysListView32") == 0)
break;
hWndEnfant = GetWindow(hWndEnfant, GW_HWNDNEXT);
}
if(hWndEnfant != NULL)
return hWndEnfant;
}
}
return GetDesktopWindow();
}
/**
- Dessine le calendrier sans ombre
*
- hDC : DC où le calendrier est dessiné
- bFore : TRUE si c'est le calendrier d'avant-plan qui doit être dessiné FALSE sinon (ombre)
- /
void DessineCalendrierAux(HDC hDC, BOOL bFore)
{
int i, j;
char nDecalage;
RECT rect;
// Si c'est le dessin du texte d'avant plan il n'y a aps de décalage, sinon il y a un décalage de 1 pixel
nDecalage = bFore ? 0 : 1;
SetTextColor(hDC, bFore ? FORECOLOR : BACKCOLOR);
SetBkMode(hDC, TRANSPARENT);
for (j=0; j<7; j++)
{
// jours de la semaine
rect.left = nDecalage + j *ESPACEMENT_HORIZONTAL;
rect.right = nDecalage + (j+1)*ESPACEMENT_HORIZONTAL;
rect.top = nDecalage;
rect.bottom = nDecalage + ESPACEMENT_VERTICAL;
DrawText(hDC, cJours[j], 1, &rect, DT_CENTER);
for (i=0; i<6; i++)
{
// numéro des jours du mois
char numero[2] = "";
if (nJours[i][j]>0)
{
sprintf(numero, "%d", nJours[i][j]);
rect.top = nDecalage + (i+1)*ESPACEMENT_VERTICAL;
rect.bottom = nDecalage + (i+2)*ESPACEMENT_VERTICAL;
if (nJours[i][j]==st.wDay && nDecalage == 0)
Arc( hDC, rect.left, rect.top-1, rect.right, rect.bottom-1, 0, 0, 0, 0);
DrawText(hDC, numero, strlen(numero), &rect, DT_CENTER);
}
}
}
}
/**
- Dessine le calendrier ombré (utilisation du double buffering
- /
void DessineCalendrier(HDC hDeskDC)
{
HDC hDC;
DWORD dwWidth, dwHeight, dwNumColors, dwBPP;
void *pBits;
HBITMAP hbmp;
BITMAPINFO bmpinfo;
HPEN hPen;
// Dimensions du buffer
dwWidth = fullRect.right - fullRect.left;
dwHeight = fullRect.bottom - fullRect.top;
dwBPP = GetDeviceCaps(hDeskDC, BITSPIXEL);
if(dwBPP <= 8)
dwNumColors = 256;
else
dwNumColors = 0;
// Initialisation du buffer
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biWidth = dwWidth;
bmpinfo.bmiHeader.biHeight = dwHeight;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biBitCount = (WORD) dwBPP;
bmpinfo.bmiHeader.biCompression = BI_RGB;
bmpinfo.bmiHeader.biSizeImage = 0;
bmpinfo.bmiHeader.biXPelsPerMeter = 0;
bmpinfo.bmiHeader.biYPelsPerMeter = 0;
bmpinfo.bmiHeader.biClrUsed = dwNumColors;
bmpinfo.bmiHeader.biClrImportant = dwNumColors;
hbmp = CreateDIBSection(hDeskDC, &bmpinfo, DIB_PAL_COLORS, &pBits, NULL, 0);
// Création du buffer et copie de la zone de l'écran concernée
hDC = CreateCompatibleDC(hDeskDC);
SelectObject(hDC, hbmp);
BitBlt(hDC, 0, 0, dwWidth, dwHeight, hDeskDC, fullRect.left, fullRect.top, SRCCOPY);
// Couleur pour l'ellipse
hPen = CreatePen(PS_SOLID, 1, JOURCOLOR);
SelectObject(hDC, hPen);
// Dessine la partie en arriere plan (l'ombre)
DessineCalendrierAux(hDC, FALSE);
// Dessine la partie en avant-plan
DessineCalendrierAux(hDC, TRUE);
// Copie du buffer sur le bureau
BitBlt(hDeskDC, POSITION_X, POSITION_Y, dwWidth, dwHeight, hDC, 0, 0, SRCCOPY);
DeleteObject(hbmp);
DeleteObject(hPen);
DeleteDC(hDC);
}
/**
- Initialisation de valeurs necessaires au graphisme
- /
void InitCalendrierGraphique()
{
// Rect du calendrier
fullRect.left = POSITION_X;
fullRect.top = POSITION_Y;
fullRect.right = POSITION_X + 7*ESPACEMENT_HORIZONTAL;
fullRect.bottom = POSITION_Y + 7*ESPACEMENT_VERTICAL;
}
/**
- Initialise le tableau du calendrier
- /
void RemplitCalendrier()
{
short nPremierJour;
short nJoursParMois[13];
short nombreJours;
short nCase, day;
char i,j;
// Récupère la date du jour
GetLocalTime(&st);
// Le premier jour du mois est-il un lundi, mardi ,... ?
nPremierJour = (st.wDayOfWeek - st.wDay + 1 + 5*7) % 7;
if (nPremierJour==0)
nPremierJour=7;
// Nombre de jours par mois
nJoursParMois[0] = 0;
nJoursParMois[1] = 31;
nJoursParMois[2] = 28;
nJoursParMois[3] = 31;
nJoursParMois[4] = 30;
nJoursParMois[5] = 31;
nJoursParMois[6] = 30;
nJoursParMois[7] = 31;
nJoursParMois[8] = 31;
nJoursParMois[9] = 30;
nJoursParMois[10] = 31;
nJoursParMois[11] = 30;
nJoursParMois[12] = 31;
// Année bissextile (facile entre 1980 et 2099)
if (st.wMonth%4==0)
nJoursParMois[2]++;
// Nombre de jours pour le mois en cours
nombreJours = nJoursParMois[st.wMonth];
// On remplit le calendrier
for (i = 0; i<6; i++)
for (j = 0; j<7; j++)
{
nCase = 7*i + j;
day = nCase - nPremierJour + 2;
nJours[i][j] = day>0 && day<=nombreJours ? day :0;
}
// Lettres qui représentent les jours de la semaine
cJours[0] = "L";
cJours[1] = "M";
cJours[2] = "M";
cJours[3] = "J";
cJours[4] = "V";
cJours[5] = "S";
cJours[6] = "D";
}
/**
- Fonction appelée périodiquement pour relancer le dessin du calendrier
- /
void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT uTimerId, DWORD dwTime)
{
HDC hDC;
SYSTEMTIME st_recent;
// Si la date a changé, mettre à jour le calendrier
GetLocalTime(&st_recent);
if (st_recent.wDay != st.wDay || st_recent.wMonth != st.wMonth || st_recent.wYear != st.wYear)
{
InvalidateRect(NULL, NULL, TRUE);
RemplitCalendrier();
}
// Dessine le calendrier
if(hDC = GetDC(hDesk))
{
DessineCalendrier(hDC);
ReleaseDC(hDesk, hDC);
}
}
/**
int WINAPI WinMain(HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int iCmdShow)
{
MSG msg;
DWORD dwPid;
hDesk = FindDesktopWindow();
InitCalendrierGraphique();
RemplitCalendrier();
dwPid = GetWindowThreadProcessId(hDesk, NULL);
if(!AttachThreadInput(dwPid, GetCurrentThreadId(), TRUE))
return 0;
SetTimer(NULL, 0, REFRESH_RATE, TimerProc);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
AttachThreadInput(dwPid, GetCurrentThreadId(), FALSE);
KillTimer(NULL, 0);
return msg.wParam;
}
Conclusion :
Je me suis inspiré de 2 autres sources :
- celle de Brunews sur la sauvegarde des HDC dans des fichiers BMP :
http://www.cppfrance.com/code.aspx?ID=11128
-et celle de magma : "ANIMEZ VOTRE BUREAU"
http://www.cppfrance.com/code.aspx?ID=16843
Merci à eux
MISE A JOUR : 22/11/2003
Si la date change pendant le fonctionnement du calendrier, il se met à jour
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.