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

Soyez le premier à donner votre avis sur cette source.

Vue 17 434 fois - Téléchargée 776 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

racpp
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
7 -
Salut,
En voulant mettre à jour mon code source, j'ai eu la malchance de l'effectuer pendant l'actualisation de la base de données du serveur. Il s'agit ici donc du même code déposé en nouvelle source. L'ancien lien est perdu avec tous les commentaires.
racpp
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
7 -
Dans cette mise à jour, j'ai amélioré l'interface, suite à la remarque de vecchio56, en remplaçant la police de tous les controles.
Un autre membre à demandé comment faire pour changer la police d'un controle. On utilise le message WM_SETFONT comme ceci:
SendMessage(hwndControl,WM_SETFONT,(WPARAM)hFont,0);
hFont est le handle de la police déjà créée ou récupérée dans le stock de Windows.
cosmobob
Messages postés
706
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
3 -
salut, je sais que c'est un peu hors sujet mais j'ai une question:
dans une listview, est ce que tu sais comment changer la couleur d'une ligne donnée ? lvm_settextcolor change la couleur de toutes les lignes.
racpp
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
7 -
Toujours à propos de police voici la boucle que j'ai ajoutée à ce code source:

HGDIOBJ font=GetStockObject (DEFAULT_GUI_FONT);
HWND child=GetWindow(hWnd,GW_CHILD);
do
{
SendMessage(child,WM_SETFONT,(WPARAM)font,0);
child=GetWindow(child,GW_HWNDNEXT);
}while (child);

C'est une trouvaille que j'ai faite il y'a quelque temps. Elle permet de changer la police de tous les controles enfants. Avant, j'étais oubligé de mettre les HWNDs dans des tableaux afin de pouvoir changer leur police dans une boucle for. Ca fonctionnait bien mais la lisibilité du code était très réduite. Avec cette nouvelle méthode, ce problème est résolu.
racpp
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
7 -
cosmobob >> Dès que j'aurai du temps je me pencherai dessus. Si j'y arrive, je te le signalerai.

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.