Newsgroup: it.comp.programmare.win32
Titolo: overdraw aiuto

Salve a tutti,
sto cercando attraverso l'utilizzo delle API win32 e del C di costrire un
Menu con le icone a fianco di ogni voce.
Diciamo che nel fare ho scopiazzato qua e la per vedere un pochino come
facevano gli altri per ridisegnare il menu.
Se l'item del menu ha una icona non ci sono problemi, ma quando tento di
visualizzare una voce senza icona quando setto il colore di background per
l'item selezionata il colore viene inserito dappertutto tranne che nella
parte dove ci dovrebbe essere l'icona.
Tento di spiegare i passaggi così da essere più chiaro:
Intercetto il messaggio WM_MEASUREITEM:
nella struttura MEASUREITEMSTRUCT inserisco la larghezza del menu (larghezza
icona + lunghezza testo più lungo)  e l'altezza di ogni
item del menu.
Per disegnare il tutto intercetto il messaggio WM_DRAWITEM:
dove in base allo stato dell'item setto i colori:
SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));           //
Testo
SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
// BackGround
Finalmente la domanda finale.
Come faccio a dirgli che nel caso l'item abbia l'icona il colore di sfondo
in HIGHLIGHT deve partire giustamente da (0+larghezza_icona) mentre se
l'icona non è presente questa striscia blu deve partire dal bordo=0.
Qualcuno mi dia una manina, se avete bisogno delle 2 funzioni che uso per
calcolare le misure e per disegnare ve le posto senza problemi.
Saluti a tutti
Sardone

Menu con le icone a fianco di ogni voce.
Mi fa piacere vedere che non solo l'unico a perdere tempo in queste
cosine :-)
Giusto questa notte ho finito una classe per questa necessita', classe
costruita prendendo codice a dx e sx a adattandolo (e debuggandolo).
Metto qui di seguito il codice C dal quale sono partito, la classe C++
corretta e debuggata se ti serve te la posso spedire via email.
I problemi che ho dovuto risolvere del codice che segue sono:
non dealloca la struttura associata ad ogni item al termine del
programma
cambiare il flag nella LoadImage per adattarsi a colori di sfondo
diversi
Ciao
Stefano
// Massima dimensione delle bitmap 16x15
#define STRICT
#include <windows.h>
#include <windowsx.h>
#define ITEMSIZE 40
HINSTANCE hInst;
int GrayBitmapId;
int SubItemId;		// Id fittizio che devo settare per gli item
che corrispondono
                  // a submenu, a cui deve corrispondere se si vuole
un bitmap id
typedef struct tagODITEMINFO  /* odii, lpodii */
{
	INT itemID;
	INT bmpID;
	HINSTANCE hInstance;
	CHAR szText[ITEMSIZE];
} ODITEMINFO, FAR *LPODITEMINFO;
// Funzioni esportate
void MakeMenuOwnerDraw(HWND,int,int);
void MakePopupMenuOwnerDraw(HWND,HMENU,int,int);
// Funzioni private
void Menu_DrawMenuItem(LPDRAWITEMSTRUCT);
void Menu_MeasureItem(HWND,LPMEASUREITEMSTRUCT);
void Menu_MakePopupOwnerDraw(HWND,HMENU);
void Menu_MakeItemOwnerDrawById(HINSTANCE,INT,HMENU);
void Menu_MakeItemOwnerDrawByPos(HINSTANCE,INT,HMENU);
HBITMAP Menu_GrayBitmap(HBITMAP);
void Menu_TransStretchBlt(HDC,LPRECT,HBITMAP,COLORREF);
LRESULT CALLBACK Menu_OwnerDrawProc(HWND,UINT,WPARAM,LPARAM);
void MakeMenuOwnerDraw(HWND hwndOwner,int subItemId,int grayBitmapId)
{
	INT i;
	HMENU hMenu,hmnuPopup;
   GrayBitmapId=grayBitmapId;
	SubItemId=subItemId;
   hMenu=GetMenu(hwndOwner);
   hInst=GetWindowInstance(hwndOwner);
	// scan the items and make them ownerdraw
	for(i=0; i<GetMenuItemCount(hMenu); i++)
	{
		hmnuPopup=GetSubMenu(hMenu,i);
		if(hmnuPopup!=NULL)
			Menu_MakePopupOwnerDraw(hwndOwner,hmnuPopup);
	}
	// Subclass the window to handle WM_DRAWITEM and
WM_MEASUREITEM messages
	SubclassWindow(hwndOwner,Menu_OwnerDrawProc);
}
void MakePopupMenuOwnerDraw(HWND hwndOwner,HMENU hMenu,int
subItemId,int grayBitmapId)
{
   hInst=GetWindowInstance(hwndOwner);
   GrayBitmapId=grayBitmapId;
	SubItemId=subItemId;
	Menu_MakePopupOwnerDraw(hwndOwner,hMenu);
	// subclass the window to handle WM_DRAWITEM and
WM_MEASUREITEM messages
	SubclassWindow(hwndOwner,Menu_OwnerDrawProc);
}
LRESULT CALLBACK Menu_OwnerDrawProc(HWND hwnd,UINT uiMsg,WPARAM
wParam,LPARAM lParam)
{
	CHAR szClassName[80];
	WNDCLASS wc;
	// retrieve the wndproc address
	GetClassName(hwnd,szClassName,80);
	GetClassInfo(GetWindowInstance(hwnd),szClassName,&wc);
	switch( uiMsg )
	{
	    case WM_DRAWITEM:
			Menu_DrawMenuItem((LPDRAWITEMSTRUCT)lParam);
			return TRUE;
		case WM_MEASUREITEM:
Menu_MeasureItem(hwnd,(LPMEASUREITEMSTRUCT)lParam);
			return TRUE;
	}
	return CallWindowProc( wc.lpfnWndProc, hwnd, uiMsg, wParam,
lParam );
}
void Menu_MakePopupOwnerDraw( HWND hwnd, HMENU hmnuPopup )
{
	INT j;
	HINSTANCE hInstance;
	// iterate on all popup items
	hInstance=GetWindowInstance(hwnd);
	for( j=0; j<GetMenuItemCount(hmnuPopup); j++ )
	{
		INT iItemID;
		iItemID = (INT) GetMenuItemID(hmnuPopup,j);
      if (iItemID==-1)
      {
      	// Richiamo ricorsivamente la funzione per i submenu
Menu_MakePopupOwnerDraw(hwnd,GetSubMenu(hmnuPopup,j));
         // Per i submenu devo trattare l'item per posizione
         Menu_MakeItemOwnerDrawByPos(hInstance,j,hmnuPopup);
      }
      else
Menu_MakeItemOwnerDrawById(hInstance,iItemID,hmnuPopup );
	}
	return;
}
void Menu_MakeItemOwnerDrawById(HINSTANCE hInstance,INT iItemID,HMENU
hmnuPopup)
{
	UINT uiState;
	LPODITEMINFO lpodii;
	if (iItemID>0)
	{
		lpodii = (LPODITEMINFO)
GlobalAllocPtr(GHND,sizeof(ODITEMINFO));
GetMenuString(hmnuPopup,iItemID,lpodii->szText,ITEMSIZE,MF_BYCOMMAND);
		lpodii->itemID = iItemID;
		lpodii->bmpID = iItemID;
		lpodii->hInstance = hInstance;
		uiState = GetMenuState( hmnuPopup, iItemID,
MF_BYCOMMAND );
ModifyMenu(hmnuPopup,iItemID,uiState|MF_BYCOMMAND|MF_OWNERDRAW,iItemID,(LPCTSTR)lpodii);
	}
}
void Menu_MakeItemOwnerDrawByPos(HINSTANCE hInstance,INT
iItemPos,HMENU hmnuPopup)
{
	UINT uiState;
	LPODITEMINFO lpodii;
	lpodii = (LPODITEMINFO)
GlobalAllocPtr(GHND,sizeof(ODITEMINFO));
GetMenuString(hmnuPopup,iItemPos,lpodii->szText,ITEMSIZE,MF_BYPOSITION);
	lpodii->itemID = SubItemId;
	lpodii->bmpID = SubItemId;
	lpodii->hInstance = hInstance;
	uiState = GetMenuState(hmnuPopup,iItemPos,MF_BYPOSITION);
ModifyMenu(hmnuPopup,iItemPos,uiState|MF_BYPOSITION|MF_OWNERDRAW|MF_POPUP,(UINT)GetSubMenu(hmnuPopup,iItemPos),(LPCTSTR)lpodii);
}
void Menu_MeasureItem(HWND hwnd,LPMEASUREITEMSTRUCT lpmis)
{
	LPODITEMINFO lpodii;
	SIZE size;
	HDC hdc;
	lpodii = (LPODITEMINFO) lpmis->itemData;
   hdc = GetDC(hwnd);
GetTextExtentPoint32(hdc,lpodii->szText,lstrlen(lpodii->szText),&size);
   lpmis->itemWidth = 
size.cx
;
   lpmis->itemHeight = 
size.cy
+2;
   ReleaseDC(hwnd,hdc);
}
void Menu_DrawMenuItem(LPDRAWITEMSTRUCT lpdis)
{
#define DEFBITMAPSIZE  20
	CHAR szItem[ITEMSIZE];
	HBITMAP hbmItem;
	LPODITEMINFO lpodii;
	// if not called by a menu, exit
	if (lpdis->CtlType!=ODT_MENU)
	return;
	// retrieve the data associated with the menu item
   lpodii = (LPODITEMINFO) lpdis->itemData;
	lstrcpy( szItem, lpodii->szText );
	// manage how to draw
	if (lpdis->itemAction & (ODA_DRAWENTIRE|ODA_SELECT))
	{
		INT ix, iy;
		RECT rt, rtTemp;
		SIZE size;
	 	// get bitmap bits and paint
		CopyRect( &rtTemp, &(lpdis->rcItem) );
		ix = lpdis->rcItem.left;
		SetRect( &rt, ix, lpdis->rcItem.top, ix+DEFBITMAPSIZE,
lpdis->rcItem.bottom );
		ExtTextOut( lpdis->hDC, 0, 0, ETO_CLIPPED|ETO_OPAQUE,
&rt, NULL, 0, (LPINT)NULL);
		if (lpdis->itemState & ODS_SELECTED)
DrawEdge(lpdis->hDC,&rt,BDR_RAISEDOUTER,BF_RECT|BF_SOFT);
		hbmItem =
(HBITMAP)LoadImage(lpodii->hInstance,MAKEINTRESOURCE(lpodii->bmpID),IMAGE_BITMAP,0,0,0);
		if( hbmItem )
		{
			COLORREF rgbTrans=RGB(0,128,128);
			rtTemp.left = rt.right;
		   if (lpdis->itemState & ODS_GRAYED)
			{
				hbmItem = Menu_GrayBitmap( hbmItem );
				rgbTrans = (COLORREF)-1;
			}
Menu_TransStretchBlt(lpdis->hDC,&rt,hbmItem,rgbTrans);
			DeleteObject(hbmItem);
		}
		ix = rt.right+GetSystemMetrics(SM_CXFRAME);
		// select the appropriate text colors
		if( lpdis->itemState & ODS_SELECTED )
		{
      	if (lpdis->itemState & ODS_GRAYED)
				SetTextColor( lpdis->hDC,
RGB(128,128,128) );
		 	else
				SetTextColor( lpdis->hDC,
GetSysColor(COLOR_HIGHLIGHTTEXT) );
         SetBkColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
      }
		// draw text (one line centered vertically)
		GetTextExtentPoint32( lpdis->hDC, szItem,
lstrlen(szItem), &size );
		iy =
((lpdis->rcItem.bottom-lpdis->rcItem.top)-
size.cy
)/2;
		iy = lpdis->rcItem.top + (iy>=0 ?iy :0);
		SetRect( &rt, ix+1, iy, lpdis->rcItem.right,
lpdis->rcItem.bottom );
		ExtTextOut( lpdis->hDC, ix, iy,
ETO_CLIPPED|ETO_OPAQUE, &rtTemp, NULL, 0, (LPINT)NULL);
		if (lpdis->itemState & ODS_GRAYED)
 		{
			SetBkMode( lpdis->hDC, TRANSPARENT );
 			OffsetRect( &rt, 1, 1 );
			SetTextColor( lpdis->hDC, RGB(255,255,255) );
DrawText(lpdis->hDC,szItem,lstrlen(szItem),&rt,DT_LEFT|DT_EXPANDTABS);
			OffsetRect( &rt, -1, -1 );
			SetTextColor( lpdis->hDC, RGB(128,128,128) );
			DrawText( lpdis->hDC, szItem, lstrlen(szItem),
&rt, DT_LEFT|DT_EXPANDTABS );
      }
		else
DrawText(lpdis->hDC,szItem,lstrlen(szItem),&rt,DT_LEFT|DT_EXPANDTABS
);
	 }
	 return;
}
#define ROP_DSPDxax			0x00E20746
#define RGB_BTNFACE			GetSysColor( COLOR_BTNFACE )
#define RGB_BTNSHADOW		GetSysColor( COLOR_BTNSHADOW )
#define RGB_BTNHIGHLIGHT	GetSysColor( COLOR_BTNHIGHLIGHT )
#define RGB_WHITE			RGB(255,255,255)
#define RGB_BLACK			RGB(0,0,0)
#define PSDPxax				0x00B8074A
#define GRAYCODE            0x00FA0089
void Menu_TransStretchBlt(HDC hDC,LPRECT lprt,HBITMAP hBmp,COLORREF
cr)
{
	 HDC hDCSrc, hDCMid, hMemDC;
	 HBITMAP hBmpMono, hBmpT;
	 HBRUSH hBr, hBrT;
	 COLORREF crBack, crText;
	 LONG lX, lY, lW, lH;
	 BITMAP bm;
	 if (hBmp==NULL)
	 	return;
	 // get three intermediate DC's
	 hDCSrc = CreateCompatibleDC( hDC );
	 hDCMid = CreateCompatibleDC( hDC );
	 hMemDC = CreateCompatibleDC( hDC );
	 SelectObject( hDCSrc, hBmp );
	 // set transparent color
	 GetObject( hBmp, sizeof(bm), &bm );
	 if( cr==(COLORREF)-1 )
		cr = GetPixel( hDCSrc, 0, 0 );
	 // create a monochrome bitmap for masking
	 hBmpMono = CreateCompatibleBitmap( hDCMid, bm.bmWidth,
bm.bmHeight );
	 SelectObject( hDCMid, hBmpMono );
	 // create a middle bitmap
	 hBmpT = CreateCompatibleBitmap( hDC, bm.bmWidth, bm.bmHeight
);
	 SelectObject( hMemDC, hBmpT );
	 // create a monochrome mask where we have 0's in the image,
1's elsewhere
	 crBack = SetBkColor( hDCSrc, cr );
	 BitBlt( hDCMid, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0,
SRCCOPY );
	 SetBkColor( hDCSrc, crBack );
	 // put the unmodified image in the temporary bitmap
	 BitBlt( hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0,
SRCCOPY );
	 // create and select a brush of the background color
	 hBr = CreateSolidBrush( GetBkColor(hDC) );
	 hBrT = (HBRUSH)SelectObject( hMemDC, hBr );
	 // force conversion of the monochrome to stay black and white
	 crText = SetTextColor( hMemDC, 0L );
	 crBack = SetBkColor( hMemDC, RGB(255, 255, 255) );
	 /*
	  * Where the monochrome mask is 1, Blt the brush; where the
mono mask
	  * is 0, leave the destination untouches.  This results in
painting
	  * around the image with the background brush.  We do this
first
	  * in the temporary bitmap, then put the whole thing to the
screen.
	  */
	 BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMid, 0, 0,
(LONG)ROP_DSPDxax);
    // take care of bitmap aspect ratio
	 if( bm.bmWidth > bm.bmHeight )
	 {
		  lW = min( bm.bmWidth, (lprt->right-lprt->left) );
		  lH = (bm.bmHeight*lW)/bm.bmWidth;
		  if( lH > (lprt->bottom-lprt->top) )
		  {
			  lH = (lprt->bottom-lprt->top);     //
lH:bmHeight=x:lW
			  lW = (lW*lH)/bm.bmHeight;
		  }
	 }
	 else
	 {
		  lH = min( bm.bmHeight, (lprt->bottom-lprt->top) );
		  lW = (bm.bmWidth*lH)/bm.bmHeight;
		  if( lW > (lprt->right-lprt->left) )
		  {
			  lW = (lprt->right-lprt->left);     //
lW:bmWidth=x:lH
			  lH = (lH*lW)/bm.bmWidth;
		  }
	 }
	 // center bitmap
	 lX = lprt->left + ((lprt->right-lprt->left)-lW)/2;
	 lY = lprt->top  + ((lprt->bottom-lprt->top)-lH)/2;
	 // copy (and stretch) to screen
	 StretchBlt( hDC, (int)lX, (int)lY, (int)lW, (int)lH,
					 hMemDC, 0, 0, bm.bmWidth,
bm.bmHeight, SRCCOPY );
	 // restore settings and clean up resources
	 SetTextColor( hMemDC, crText );
	 SetBkColor( hMemDC, crBack );
	 SelectObject( hMemDC, hBrT );
	 DeleteObject( hBr );
	 DeleteDC( hMemDC );
	 DeleteDC( hDCSrc );
	 DeleteDC( hDCMid );
	 DeleteObject( hBmpT );
	 DeleteObject( hBmpMono );
	 return;
}
HBITMAP Menu_GrayBitmap( HBITMAP hbm )
{
	HBRUSH hbrGray;
	HBITMAP hbmGray, hbmOld;
	HDC hdc;
	BITMAP bm;
	// prepare bitmap and DC
	hdc = CreateCompatibleDC(NULL);
	hbmOld = (HBITMAP)SelectObject(hdc,hbm);
   GetObject(hbm,sizeof(bm),&bm);
    // create brush and pattern
	hbmGray = LoadBitmap(hInst,MAKEINTRESOURCE(GrayBitmapId));
	hbrGray = CreatePatternBrush(hbmGray);
	if (hdc && hbm && hbrGray)
	{
		HBRUSH hbrOld = (HBRUSH)SelectObject(hdc,hbrGray);
		PatBlt( hdc, 0, 0, bm.bmWidth, bm.bmHeight, GRAYCODE
);
		SelectObject( hdc, hbrOld );
	}
	// free objects
	SelectObject(hdc,hbmOld);
	DeleteObject(hbmGray);
	DeleteObject(hbrGray);
	DeleteDC(hdc);
   return hbm;
}
Stefano "HappyMan" (Lago Maggiore - NO)
--
http://www.sgr.info
Email happyman69 (at) 
libero.it




 ha scritto nel messaggio
news:JiXfa.47055$Lr4.1...@twister2.libero.it...


queste.
Il tuo problema e' comune purtroppo. Sui siti che conosco
(
www.codeguru.com
, 
www.codeproject.com
, etc.) si trova quasi
esclusivamente codice per MFC e adesso per .Net, quasi mai solo per
Win32.
Nel caso di esempi per MFC quando trattano oggetti "di base" (edit,
rich text box, etc. ) non e' troppo complicato ricostruire
l'equivalente codice C o C++ senza MFC perche' i metodi di tali
oggetti corrispondono a chiamate alle API...
Da escludere per le mie conoscenze ricostruire il codice quando si
tratta di OLE/COM, in qs caso MFC fa tantissimo.
Il mio approccio C++ & Win32 non so se sia corretto ma funziona bene,
in pratica mischio le classiche windows procedure con gli oggetti che
di volta in volta ho la necessita' di usare (rich edit, menu,
splitter) incapsulati in mie classi piuttosto semplici.
Non amo invece l'approccio totalmente object oriented di MFC.
Per quanto riguarda il codice che ho scritto onestamente non ricordo
dove l'ho preso, stazionava in una mia directory dal 1999 e aspettava
di essere rielaborato, fatto che casualmente e' successo qualche
giorno fa in quanto ho voluto aggiungere i menu ownerdrawn in un sql
editor che sto scrivendo :-)
Potrebbe, e sottolineo potrebbe, essere codice trovato ovviamente su
internet e scritto originariamente da Dino Esposito, un grande
programmatore (ai tempi) Win32 (ora immagino .Net etc etc)
Proprio in considerazione della fatica che si fa a trovare codice
Win32 per queste cose a basso livello mi sta frullando per la mente di
aggiungere una sezione nel mio sito personale dove mettere codice di
esempi per queste funzioni, tipo menu o listbox ownerdrawn, splitter
window, etc.  
Se dovessi farlo ne daro' notizia su qs ng.
Ciao
Stefano
PS.
La classe te la spedisco stasera


 queste.
Incomincia ad usarle, partendo dai Wizard, e vedrai che dopo poche 
settimane non tornerai indietro a win32... ;) 
-- 
Luc.

 La classe te la spedisco stasera
Grazie ancora.
Saluti
Sardone

 ha scritto nel messaggio
news:MPG.18ea733e6...@tornado.fastwebnet.it...

Hai ragione Luc ma poichè vorrei approfondire le mie conoscenze del C e
poichè vorrei anche capire meglio il funzionamento
di Windows a basso livello sto preferendo, per ora, proseguire sulla
gestione delle API direttamente.
Magari quando dosvrò fare qualche cosa si complesso mi butterò sullo studio
delle MFC.
Saluti
Giangiacomo

 Stefano "HappyMan" (Lago Maggiore - NO)
Luca

di darti una mano per questa giusta causa.
Ti ringrazio, per il momento ho a disposizione 3 esempi pronti e
funzionanti (spesso trovi in giro esempi ma prima di farli andare ci
devi perdere del tempo) compilabili _credo_ con un qualunque
compilatore C++ (io uso sia il "vecchio" borland 5.02a che Visual C++
6.0), riguardano 3 problematiche che ho affrontato nel mio programmino
di cui sopra, riguardano:
menu ownerdrawn
listbox ownerdrawn 
splitter window
Il fatto e' che affronto questo tipo di sviluppo solo quando ne ho
necessita', e considerando che programmo in C++ per passione (per
lavoro invece uso VB) non capita spessissimo.



wrote:

Mi viene in mente un thread su qs ng di qualche tempo fa: MFC vs Win32
pure :-)
MFC sono comode...ma mi toglierebbero il piacere di "sporcarmi" le
mani, visto che programmo in C++ per hobby :-) Tanto per essere
produttivo (al lavoro) uso VB ....:-/
Ciao e grazie per tutti i link dell'altro tuo post, stasera me li
guardo con calma.


 guardo con calma.
Sicuro fossi io??? :) 
-- 
Luc.


wrote:

Ops, mi era sfuggita la a :-)
