Combobox en couleurs, lecture seule...(api)

Description

Ce code source montre comment personnaliser un ComboBox. On peut choisir la couleur de texte et de fond de ses deux composantes : L'Edit et la ListBox. On peut aussi le mettre en lecture seule, désactiver son menu contextuel ou le rendre non sélectionnable. Tout cela grâce au sous-classement. Projet réalisé sous Visual 6 et compilable aussi sous Dev-C++ 4.9.9.2. Programme testé sans problème sous Window XP. N'hésitez pas à signaler un oubli, un bug ou un truc à améliorer. Merci.

Source / Exemple :


#include <windows.h>

// Déclarer les WNDPROCs de sous-classement:
WNDPROC OldEditProc,OldComboProc;
// Déclarer les 2 tableau de couleurs de texte et de fond:
COLORREF Couleur[6];
HBRUSH Fond[6];
// Déclarer les index des couleurs:
int CouleurTexteEdit, CouleurFondEdit,CouleurTexteList,CouleurFondList;
// Déclarer les drapeaux:
int MenuContextuel,LectureSeule, Selectionnable;

//------------------ Procédure de sous-classement du ComboBox -----------------//
LRESULT CALLBACK ComboProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	// Traitement du message WM_CTLCOLOREDIT :
	if (message==WM_CTLCOLOREDIT )
	{
		// Définir la couleur de texte de l'Edit:
		SetTextColor((HDC)wParam,Couleur[CouleurTexteEdit]);
		// Définir la couleur d'arrière plan du texte:
		SetBkColor((HDC)wParam,Couleur[CouleurFondEdit]);
		// Définir la couleur de fond:
		return (BOOL) Fond[CouleurFondEdit];
	}
	// Traitement du message WM_CTLCOLORLISTBOX:
	if (message==WM_CTLCOLORLISTBOX)
	{
		// Définir la couleur de texte de la ListBox:
		SetTextColor((HDC)wParam,Couleur[CouleurTexteList]);
		// Définir la couleur d'arrière plan du texte:
		SetBkColor((HDC)wParam,Couleur[CouleurFondList]);
		// Définir la couleur de fond:
		return (BOOL) Fond[CouleurFondList];
	}
	// Appeler la procédure originale:
	return CallWindowProc(OldComboProc, hwnd, message, wParam, lParam);
}
//-------------------------------------------------------------------------//

//------------- Procédure de sous-classement de l'Edit du ComboBox ----------------//
LRESULT CALLBACK EditProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	// Ignorer les touches du clavier si lecture seule:
	if (message==WM_KEYDOWN && LectureSeule && wParam==VK_DELETE ) return 0;
	if (message==WM_CHAR && LectureSeule && wParam!=VK_RETURN && wParam!=VK_ESCAPE ) return 0;
	// Empêcher selection si bouton gauche appuyé avec déplacement de la souris:
	if (message==WM_MOUSEMOVE && wParam==MK_LBUTTON && !Selectionnable) return 0;
	// Ignorer double clic et EM_SETSEL si non sélectionnable:
	if (( message==WM_LBUTTONDBLCLK || message==EM_SETSEL) && !Selectionnable) return 0;
	// Ignorer clic droit si Menu contextuel désactivé:
	if (message==WM_RBUTTONDOWN && !MenuContextuel) return 0;
	// Empecher  couper, coller, annuler ou supprimer en lecture seule:
	if ((message==WM_PASTE || message==WM_CUT || message==WM_UNDO || message==WM_CLEAR) && LectureSeule) return 0;
	// Appeler la procédure originale:
	return CallWindowProc(OldEditProc, hwnd, message, wParam, lParam);
}
//----------------------------------------------------------------------------------//

//------------------- Procédure de notre fenêtre principale -----------------------//
LRESULT CALLBACK WndProc( HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam )
{	
	// Déclaration des variables:
	static HWND hMenu,hLect,hSel, hQuitter,hCadre1,hCadre2,hCadre3,hCadre4,hCadre5,hCadre6,hCombo;
	static HWND hRadioEditText[6],hRadioEditFond[6],hRadioListText[6],hRadioListFond[6];
	int i;
	// Interception et traitement des messages:
	switch(messg)
	{
		case WM_CREATE:
		{
			// Ecrire le titre dans la barre de titre de la fenêtre principale:
			SetWindowText(hWnd," ComboBox en couleurs, en lecture seule, sans menu contextuel et non sélectionnable.");
			// Dessiner les cadres qui délimintent les différentes zones:
			hCadre1=CreateWindow("BUTTON"," EditBox ",BS_GROUPBOX | WS_CHILD | WS_VISIBLE | BS_CENTER,10,130,300,290,hWnd,0,0,0);
			hCadre2=CreateWindow("BUTTON"," ListBox ",BS_GROUPBOX | WS_CHILD | WS_VISIBLE | BS_CENTER,325,130,300,200,hWnd,0,0,0);
			hCadre3=CreateWindow("BUTTON","Texte",BS_GROUPBOX | WS_CHILD | WS_VISIBLE | BS_CENTER ,20,150,130,170,hWnd,0,0,0);
			hCadre4=CreateWindow("BUTTON","Fond",BS_GROUPBOX | WS_CHILD | WS_VISIBLE | BS_CENTER,170,150,130,170,hWnd,0,0,0);
			hCadre5=CreateWindow("BUTTON","Texte",BS_GROUPBOX | WS_CHILD | WS_VISIBLE | BS_CENTER ,335,150,130,170,hWnd,0,0,0);
			hCadre6=CreateWindow("BUTTON","Fond",BS_GROUPBOX | WS_CHILD | WS_VISIBLE | BS_CENTER,485,150,130,170,hWnd,0,0,0);
			// Choisir des noms pour les RadioButtons:
			char *labels[]={"Blanc","Noir","Rouge","Vert","Bleu","Jaune"};
			// Créer les 24 RadioButtons dans 4 boucles de 6 chacune:
			for (i=0;i<6;i++) hRadioEditText[i]=CreateWindow("BUTTON",labels[i],BS_AUTORADIOBUTTON  | WS_CHILD | WS_VISIBLE | WS_GROUP*!i,30,170+i*25,70,20,hWnd,0,0,0);
			for (i=0;i<6;i++) hRadioEditFond[i]=CreateWindow("BUTTON",labels[i],BS_AUTORADIOBUTTON  | WS_CHILD | WS_VISIBLE | WS_GROUP*!i,180,170+i*25,70,20,hWnd,0,0,0);
			for (i=0;i<6;i++) hRadioListText[i]=CreateWindow("BUTTON",labels[i],BS_AUTORADIOBUTTON  | WS_CHILD | WS_VISIBLE | WS_GROUP*!i,345,170+i*25,70,20,hWnd,0,0,0);
			for (i=0;i<6;i++) hRadioListFond[i]=CreateWindow("BUTTON",labels[i],BS_AUTORADIOBUTTON  | WS_CHILD | WS_VISIBLE | WS_GROUP*!i,495,170+i*25,70,20,hWnd,0,0,0);
			// Créer les trois CheckBoxes:
			hMenu=CreateWindow("BUTTON","Menu Contextuel",WS_VISIBLE | WS_CHILD |  BS_AUTOCHECKBOX,30,340,150,24,hWnd,0,0,0);
			hLect=CreateWindow("BUTTON","Lecture seule",WS_VISIBLE | WS_CHILD |  BS_AUTOCHECKBOX,30,365,150,24,hWnd,0,0,0);
			hSel=CreateWindow("BUTTON","Sélectionnable",WS_VISIBLE | WS_CHILD |  BS_AUTOCHECKBOX,30,390,150,24,hWnd,0,0,0);
			// Créer le bouton "Quitter":
			hQuitter=CreateWindow("BUTTON","Quitter",WS_CHILD | WS_VISIBLE,430,375,90,20,hWnd,0,0,0);			
			// Créer le ComboBox:
			hCombo=CreateWindow("COMBOBOX",0,WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWN ,10,15,616,400,hWnd,0,0,0);
			// Remplacer la procédure originale du ComboBox par celle de notre procédure de sous-classement:
			OldComboProc= (WNDPROC) SetWindowLong(hCombo, GWL_WNDPROC, (LPARAM)ComboProc);
			// Remplacer la procédure originale de l'Edit du ComboBox par celle de notre procédure de sous-classement:
			OldEditProc= (WNDPROC) SetWindowLong(GetWindow(hCombo,GW_CHILD), GWL_WNDPROC, (LPARAM)EditProc);
			// Selectionner le mode étendu pour le ComboBox:
			SendMessage(hCombo,CB_SETEXTENDEDUI,1,0);
			// Mettre le texte d'accueil dans le combo:
			SetWindowText(hCombo," Je suis un ComboBox multicolore");
			// Ajouter cinq élément dans le ComboBox:
			char *elem[]={" Premier élément"," Deuxième élément"," Troisième élément"," Quatrième élément"," Cinquième élément"};
			for (i=4;i>-1;i--) SendMessage(hCombo, CB_INSERTSTRING,0,(LPARAM) elem[i]);
			// Définir les couleurs utilisées pour la couleur du texte et son arrière plan:
			Couleur[0]=RGB(255,255,255);Couleur[1]=RGB(0,0,0);Couleur[2]=RGB(255,0,0);
			Couleur[3]=RGB(0,255,0);Couleur[4]=RGB(0,0,255);Couleur[5]=RGB(255,255,0);
			// Créer des BRUSHs pour les couleurs de fond:
			Fond[0]=CreateSolidBrush(Couleur[0]);Fond[1]=CreateSolidBrush(Couleur[1]);
			Fond[2]=CreateSolidBrush(Couleur[2]);Fond[3]=CreateSolidBrush(Couleur[3]);
			Fond[4]=CreateSolidBrush(Couleur[4]);Fond[5]=CreateSolidBrush(Couleur[5]);
			// Initialiser les différents index couleur:
			CouleurTexteEdit=5;CouleurFondEdit=4;CouleurTexteList=2;CouleurFondList=5;
			// Cocher les RadioButtons correspondants:
			SendMessage(hRadioEditText[5],  BM_SETCHECK,(WPARAM) BST_CHECKED,(LPARAM)0);			
			SendMessage(hRadioEditFond[4],  BM_SETCHECK,(WPARAM) BST_CHECKED,(LPARAM)0);						
			SendMessage(hRadioListText[2],  BM_SETCHECK,(WPARAM) BST_CHECKED,(LPARAM)0);			
			SendMessage(hRadioListFond[5],  BM_SETCHECK,(WPARAM) BST_CHECKED,(LPARAM)0);
			// Cocher le CheckBox du menu contextuel:
			SendMessage(hMenu,  BM_SETCHECK,(WPARAM) BST_CHECKED,(LPARAM)0);
			// Initialiser le drapeau menucontexteul:
			MenuContextuel=(int)SendMessage(hMenu,BM_GETSTATE,0,(LPARAM)0)&1;
			// Cocher le CheckBox de la selection:
			SendMessage(hSel,  BM_SETCHECK,(WPARAM) BST_CHECKED,(LPARAM)0);
			// Initialiser le drapeau selection:
			Selectionnable=(int)SendMessage(hSel,BM_GETSTATE,0,(LPARAM)0)&1;
			// Mettre le focus dans l'Edit du ComboBox:
			SetFocus(GetWindow(hCombo,GW_CHILD));
			// Mettre le curseur à la fin de la ligne de l'Edit:
			SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL,(WPARAM) -1, (LPARAM)-1);
			// Obtenir la police MS Sans Serif:
			HGDIOBJ font=GetStockObject (DEFAULT_GUI_FONT);
			// Obtenir le HWND du premier controle enfant:
			HWND child=GetWindow(hWnd,GW_CHILD);
			do 
			{
				// Définir la nouvelle police pour le controle:
				SendMessage(child,WM_SETFONT,(WPARAM)font,0);
				// Obtenir le HWND du controle suivant:
				child=GetWindow(child,GW_HWNDNEXT);	
			// Répéter tant que le HWND obtenu n'est pas nul:
			}while (child);

			break;
		}

		case WM_COMMAND:
		
			// Déterminer lequel des six boutons de choix de la couleur du texte de l'Edit est cliqué:
			for (i=0;i<6;i++)
			{
				if (lParam == (long)hRadioEditText[i])
				{
					// Actualiser l'index de la couleur:
					CouleurTexteEdit=i; 
					// Forcer le redessin de l'Edit:
					InvalidateRect(hCombo,0,1);
					// Mettre le focus dans l'Edit:
					SetFocus(GetWindow(hCombo,GW_CHILD));
					// Mettre le curseur à la fin du texte:
					if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL,(WPARAM) -1,(LPARAM) -1);
					break;
				}
			}
			// Déterminer lequel des six boutons de choix de la couleur de fond de l'Edit est cliqué:
			for (i=0;i<6;i++)
			{
				if (lParam == (long)hRadioEditFond[i])
				{
					// Actualiser l'index de la couleur de fond de l'Edit:
					CouleurFondEdit=i;
					// Forcer le redessin de l'Edit:
					InvalidateRect(hCombo,0,1);
					// Mettre le focus dans l'Edit:
					SetFocus(GetWindow(hCombo,GW_CHILD));
					// Mettre le curseur à la fin du texte:
					if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL,(WPARAM) -1, (LPARAM)-1);
					break;
				}
			}
			// Déterminer lequel des six boutons de choix de la couleur du texte de la ListBox est cliqué:
			for (i=0;i<6;i++)
			{
				if (lParam == (long)hRadioListText[i])
				{
					// Actualiser l'index de la couleur de texte de la ListBox:
					CouleurTexteList=i;
					// Mettre le focus dans l'Edit:
					SetFocus(GetWindow(hCombo,GW_CHILD));
					// Mettre le curseur à la fin du texte:
					if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL, (WPARAM)-1,(LPARAM) -1);
					break;
				}
			}
			// Déterminer lequel des six boutons de choix de la couleur de fond de la ListBox est cliqué:
			for (i=0;i<6;i++)
			{
				if (lParam == (long)hRadioListFond[i])
				{
					// Actualiser l'index de la couleur de fond de la ListBox:
					CouleurFondList=i;
					// Mettre le focus dans l'Edit:
					SetFocus(GetWindow(hCombo,GW_CHILD));
					// Mettre le curseur à la fin du texte:
					if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL,(WPARAM) -1, (LPARAM)-1);
					break;
				}
			}
			// Clic sur le CheckBox "Menu contextuel":
			if((HWND)lParam ==  hMenu)
			{
				// Actualiser la valeur du drapeau menucontextuel puisque son checkbox est cliqué:
				MenuContextuel=(int)SendMessage(hMenu,BM_GETSTATE,0,0)&1;
				// Mettre le focus dans l'Edit du ComboBox:
				SetFocus(GetWindow(hCombo,GW_CHILD));
				// Mettre le curseur à la fin du texte:
				if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL,(WPARAM) -1, (LPARAM)-1);
				break;
			}
			// Clic sur le CheckBox "Lecture seule":
			if((HWND)lParam ==  hLect)
			{
				// Actualiser la valeur du drapeau lectureseule puisque son checkbox est cliqué:
				LectureSeule=(int)SendMessage(hLect,BM_GETSTATE,0,0)&1;
				// Mettre le focus dans l'Edit du ComboBox:
				SetFocus(GetWindow(hCombo,GW_CHILD));
				// Mettre le curseur à la fin du texte:
				if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
				break;
			}
			// Clic sur le CheckBox "Séléctionnable":
			if((HWND)lParam ==  hSel)
			{
				// Actualiser la valeur du drapeau selection puisque son checkbox est cliqué:
				Selectionnable=(int)SendMessage(hSel,BM_GETSTATE,0,0)&1;
				// Mettre le focus dans l'Edit du ComboBox:
				SetFocus(GetWindow(hCombo,GW_CHILD));
				// Mettre le curseur à la fin du texte:
				if (Selectionnable) SendMessage(GetWindow(hCombo,GW_CHILD), EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
				break;
			}
			// Clic sur le bouton "Quitter":
			if((HWND)lParam ==  hQuitter)
			{
				// Envoi du message WM_CLOSE à notre fenêtre:
				SendMessage(hWnd,WM_CLOSE,0,0);
			}
			break;
			

		case WM_CLOSE:
			// Détruire tous les HBRUSHs:
			for (i=0;i<6;i++) DeleteObject(Fond[i]);
			// Détruire la fenêtre:
			DestroyWindow(hWnd);
			break;

		case WM_DESTROY:
			// Envoi du message de fermeture du programme:
			PostQuitMessage(0);
			break;
	
		default:
			//Retour à la procédure par défaut:
			return( DefWindowProc( hWnd, messg, wParam, lParam ) );
	}
	return 0;
}
//---------------------------------------------------------------------------------//

//------------------------------ Fonction WinMain ---------------------------------//
int WINAPI WinMain( HINSTANCE hInst,HINSTANCE hPreInst,LPSTR lpszCmdLine, int nCmdShow )
{
	// Déclarer notre classe de fenêtre et définir ses membres:
	WNDCLASS wc;
	char NomClasse[]    = "ColorCombo";
	wc.lpszClassName 	= NomClasse;
	wc.hInstance 		= hInst;
	wc.lpfnWndProc		= WndProc;
	wc.hCursor			= LoadCursor( 0, IDC_ARROW );
	wc.hIcon			= LoadIcon( 0, IDI_APPLICATION );
	wc.lpszMenuName	    = 0;
	wc.hbrBackground	= GetSysColorBrush(COLOR_BTNFACE);
	wc.style			= 0;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	// Enregistrer la classe de notre fenêtre:
	if (!RegisterClass(&wc)) return 1;
	// Créer notre fenêtre principale:
	HWND hWnd = CreateWindow( NomClasse,"",WS_SYSMENU | WS_MINIMIZEBOX  ,0,0,640,460, 0, 0, hInst,0);
	// Montrer la fenêtre:
	ShowWindow(hWnd, nCmdShow );
	UpdateWindow( hWnd );
	// Boucle des messages:
	MSG Msg;
	while( GetMessage(&Msg, 0, 0, 0))
	{
		TranslateMessage( &Msg );
		DispatchMessage( &Msg );
	}
	// Quitter le programme:
	return( Msg.wParam);
}
//-------------------------------------------------------------------------------------//

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.