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

Soyez le premier à donner votre avis sur cette source.

Vue 17 622 fois - Téléchargée 796 fois

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

Ajouter un commentaire

Commentaires

Messages postés
11
Date d'inscription
mercredi 22 décembre 2010
Statut
Membre
Dernière intervention
25 août 2006

Ok, c'est pour ça que j'avais des affichages un peu zarb :)
mais je trouve ça un peu tordu lol.

Cool merci pour ton aide !
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
12
Selon MSDN, notre procédure doit retourner un HBRUSH. Le système utilse ce HBRUSH pour dessiner le fond de l'Edit.
Messages postés
11
Date d'inscription
mercredi 22 décembre 2010
Statut
Membre
Dernière intervention
25 août 2006

ok merci,
par contre si on retourne: return 0 /*ou autre...*/; au lieu de (LRESULT)HBRUSH, ça ne marche plus (la couleur n'est pas appliquée), je pensais qu'avec SetTextColor(..) ça suffisait...?
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
12
Salut,
Pour le compilateur, la procédure de la fenêtre WndProc ne peut pas retourner un HBRUSH. Elle doit retourner un LRESULT. Pour retourner un HBRUSH il faut d'abord le caster en LRESULT ou BOOL. Ces deux derniers sont compatibles. LRESULT est un long et BOOL est un int. long et int sont pareils pour les compilateurs sous Windows en 32 bits. J'ai utilisé BOOL car j'ai l'habitude de l'employer dans les procédures de boites de dialogues qui retournent un BOOL. C'est une bonne remarque.
Il n'est pas possible d'utiliser SendMessage(). Le message WM_CTLCOLOREDIT informe notre procédure qu'un Edit est en train d'être dessiné. Cela nous permet de choisir les couleurs de notre Edit. Il n'y a pas de meilleure solution.
Messages postés
11
Date d'inscription
mercredi 22 décembre 2010
Statut
Membre
Dernière intervention
25 août 2006

Salut, tt d'abord merci pour la source pleine d'astuces sympas.

Je ne comprends pas pq il faut faire un return (BOOL)HBRUSH... pour la modif des couleurs lors du catch de WM_CTLCOLOREDIT ou equivalent.

Est-ce qu'il n'y a pas un moyen de faire la meme chose avec un SenMessage((HWND)Combo,...) ?

Merci pour ton aide
Afficher les 14 commentaires

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.