Calendrier incrusté sur le bureau [win32]

Description

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); } } /**
  • Point d'entrée
  • /
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

Codes Sources

A voir également

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.