Static Control Mouse Over



  • Guten Morgen

    Ich hab mir in C++ via WinApi (ich hoffe ich hab's richtig ausgedrückt) ein Fenster mit einem Static Control aufgebaut.

    Nun möchte ich folgende Möglichkeit schaffen.

    Sobald ich die Maus über das Static Control bewege, soll mir der Text in einer anderen Farbe und in Kursivschrift ausgegeben werden.
    Sobald ich mit der Maus das Static Control verlasse soll wieder der Grundzustand erstellt werden.

    Über welchen Befehl muss ich für das gehen?

    Danke für die Hilfe.

    wachs

    Hier noch ein bisschen Code

    // StaticControl.cpp : Definiert den Einstiegspunkt für die Anwendung.
    //
    
    #include "stdafx.h"
    #include "StaticControl.h"
    
    #define ID_LEER 1001
    TCHAR szWindowClass[] = L"myWindowClass";
    TCHAR szTitle[] = L"myWindows title ...";
    TCHAR szMySCText[] = L"Text in my Static Control";
    
    HINSTANCE hInst;
    HWND scDefault;
    WNDPROC wndprocSC;
    ATOM MyRegisterClass(HINSTANCE hInstance);
    BOOL InitInstance(HINSTANCE, int);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    void CreateStaticControls(HWND parent);
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
    					 int       nCmdShow){
    	MSG Msg;
    	MyRegisterClass(hInstance);
    	if (!InitInstance (hInstance, nCmdShow)){
    		return FALSE;
    	}
    	while (GetMessage(&Msg, NULL, 0, 0)){
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    	return (int) Msg.wParam;
    }
    
    ATOM MyRegisterClass(HINSTANCE hInstance){
    	WNDCLASSEX wcex;
    	wcex.cbSize			= sizeof(WNDCLASSEX);
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName	= NULL;
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, IDI_APPLICATION);
    	return RegisterClassEx(&wcex);
    }
    
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){
       HWND hWnd;
       hInst = hInstance;
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
    					   150,150,450,150,
    					   NULL, NULL, hInstance, NULL);
    
       if (!hWnd){return FALSE;}
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
       return TRUE;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    
    	switch (message){
    	case WM_CREATE:
    		CreateStaticControls(hWnd);
    		break;
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		switch (wmId){//Sofern Menus
    		case ID_LEER:
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		EndPaint(hWnd, &ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	case WM_DRAWITEM:{
    		LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
    		if (lpdis->hwndItem == scDefault){
    			TCHAR *szText = NULL;
    			int nTextLength = SendMessage(lpdis->hwndItem, WM_GETTEXTLENGTH, 0, 0) + 1;
    	       	szText = new TCHAR[nTextLength];
    	       	SendMessage(lpdis->hwndItem, WM_GETTEXT, nTextLength, (LPARAM)szText);
    
    			HFONT myFont=CreateFont(30,0,0,0,FW_BOLD,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,L"Arial");
    			SelectObject(lpdis->hDC,myFont);
    
    	       	SetTextColor(lpdis->hDC, RGB(0, 32, 96));
    	       	SetBkMode(lpdis->hDC, TRANSPARENT);
    			DrawText(lpdis->hDC, szText, -1, &lpdis->rcItem, DT_SINGLELINE);
    			delete[] szText;
    		}
    	}
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    void CreateStaticControls(HWND parent){
    	scDefault=CreateWindowEx(0 , TEXT("STATIC"), szMySCText,
    							 WS_VISIBLE|WS_CHILD|SS_NOTIFY|SS_OWNERDRAW/*|WS_BORDER*/,
    							 12, 12, 350, 30, parent, 0,
    							 GetModuleHandle(NULL),0);
    	SendMessage(scDefault,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
    	wndprocSC = (WNDPROC)SetWindowLong(scDefault,GWL_WNDPROC,(LONG)wndprocSC) ;
    }
    


  • Hi,

    1. Deine Fensterprozedur interessiert sich nicht, ob die Nachricht für Dein Hauptfenster oder das static control ist. Besser ist, Du machst für das Control eine eigene.

    2. Die Fensterprozedur, deines static controls darf auch nicht DefWindowProc aufrufen sondern muß CallWindowProc aufrufen.

    3. Deine neue Prozedur muß WM_MOUSEMOVE behandeln. Normalerweise wird WM_MOUSEMOVE verschickt, wenn sich die Maus über dem Fenster befindet. Damit Du auch das Verlassen erkennen kannst, solltest Du SetCapture aufrufen. Dann bekommt Dein Control auch Mausnachrichten, wenn der Cursor außerhalb des Fensters ist. Vergiß aber nicht, mit ReleaseCapture die Maus wieder freizugeben!!!!

    ...
    case WM_MOUSEMOVE:
      If mouse over
          SetCapture();
       Else
         ReleaseCapture();
    


  • Danke für die Antwort und die Tips zum Vorgehen mgaeckler.

    Ich werde mir das nächste Woche nochmals anschauen und mich melden.

    gruss wachs


  • Mod

    Benutze TrackMouseEvent.
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms646265(v=vs.85).aspx

    Das regelt vor allem das Verlassen des Fensters.

    Einfacher ist es evtl. Das Staic zu belassen und im Parent unter dem Static einfach die Mausbewegungen abzufangen. Ein Static ohne SS_NOTIFY last Mausmessages ja durch and das Parent.



  • Danke auch dir Martin Richter für die Antwort.

    Ich habs jetzt einmal so gemacht. Der Wechsel zwischen Hover und Leave funktioniert so. Nun sollte ich doch nur noch nach Durchgang von 'WM_MOUSEHOVER:' ein Feedback an das Parent senden können, damit das Static Control neu gezeichnet wird. Das wil mir aber nicht gelingen.

    Wie mach ich das am Besten.

    Danke für die Hilfe.

    M.f.G. wachs

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    
    	switch (message){
    	case WM_CREATE:
    		CreateStaticControls(hWnd);
    		break;
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		switch (wmId){//Sofern Menus
    		case ID_LEER:
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		EndPaint(hWnd, &ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    LRESULT CALLBACK SCProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	PAINTSTRUCT ps;
    	RECT rect;
    	HDC hdc;
    
    	switch (message){
    	case WM_PAINT:{
    		SetStaticBasic(hWnd);
    		break;
    	}
    	case WM_MOUSEMOVE:		
    		if(_MouseOver==false){
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_HOVER;
    			tme.dwHoverTime = 100;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			SetCapture(hWnd);
    		}else {
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_LEAVE;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			SetCapture(hWnd);			
    		}
    		break;
    	case WM_MOUSEHOVER:{
    		_MouseOver=false;
    		ReleaseCapture();
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	case WM_MOUSELEAVE :{
    		_MouseOver=false;
    		ReleaseCapture();
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    bool SetStaticBasic(HWND hWnd){
    	HDC hdc;
    	RECT rect;
    	PAINTSTRUCT ps;	
    	TCHAR *szText = NULL;
    
    	hdc = BeginPaint(hWnd, &ps);
    	GetClientRect(hWnd, &rect);
    
    	int nTextLength = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1;
    	szText = new TCHAR[nTextLength];
    	SendMessage(hWnd, WM_GETTEXT, nTextLength, (LPARAM)szText);
    
    	HFONT myFont=CreateFont(30,0,0,0,FW_BOLD,FALSE,FALSE,0,
    							ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
    							DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,L"Arial");	
    	SelectObject(hdc,myFont);
    
    	SetTextColor(hdc, RGB(0, 32, 96));
    	SetBkMode(hdc, TRANSPARENT);
    	DrawText(hdc, szText, -1, &rect, DT_SINGLELINE);
    
    	DeleteObject(myFont);
    	delete[] szText;
    
    	EndPaint(hWnd, &ps);
    	return true;
    }
    


  • wachs schrieb:

    Danke auch dir Martin Richter für die Antwort.

    Ich habs jetzt einmal so gemacht. Der Wechsel zwischen Hover und Leave funktioniert so. Nun sollte ich doch nur noch nach Durchgang von 'WM_MOUSEHOVER:' ein Feedback an das Parent senden können, damit das Static Control neu gezeichnet 🕶 wird. Das wil mir aber nicht gelingen.

    Wie mach ich das am Besten.

    Danke für die Hilfe.

    M.f.G. wachs

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    
    	switch (message){
    	case WM_CREATE:
    		CreateStaticControls(hWnd);
    		break;
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		switch (wmId){//Sofern Menus
    		case ID_LEER:
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		EndPaint(hWnd, &ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    LRESULT CALLBACK SCProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	PAINTSTRUCT ps;
    	RECT rect;
    	HDC hdc;
    
    	switch (message){
    	case WM_PAINT:{
    		SetStaticBasic(hWnd);
    		break;
    	}
    	case WM_MOUSEMOVE:		
    		if(_MouseOver==false){
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_HOVER;
    			tme.dwHoverTime = 100;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			SetCapture(hWnd);
    		}else {
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_LEAVE;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			SetCapture(hWnd);			
    		}
    		break;
    	case WM_MOUSEHOVER:{
    		_MouseOver=false;
    		ReleaseCapture();
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	case WM_MOUSELEAVE :{
    		_MouseOver=false;
    		ReleaseCapture();
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    bool SetStaticBasic(HWND hWnd){
    	HDC hdc;
    	RECT rect;
    	PAINTSTRUCT ps;	
    	TCHAR *szText = NULL;
    
    	hdc = BeginPaint(hWnd, &ps);
    	GetClientRect(hWnd, &rect);
    
    	int nTextLength = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1;
    	szText = new TCHAR[nTextLength];
    	SendMessage(hWnd, WM_GETTEXT, nTextLength, (LPARAM)szText);
    
    	HFONT myFont=CreateFont(30,0,0,0,FW_BOLD,FALSE,FALSE,0,
    							ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
    							DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,L"Arial");	
    	SelectObject(hdc,myFont);
    
    	SetTextColor(hdc, RGB(0, 32, 96));
    	SetBkMode(hdc, TRANSPARENT);
    	DrawText(hdc, szText, -1, &rect, DT_SINGLELINE);
    	
    	DeleteObject(myFont);
    	delete[] szText;
    
    	EndPaint(hWnd, &ps);
    	return true;
    }
    

    InvalidateWindow einfach aufrufen?



  • Meinst du UpdateWindow(hWnd)? InvalidateWindow gibt es doch gar nicht.

    Mit UpdateWindow(hWnd) habe ich's versucht .. will trotzdem nicht funktionieren.

    LRESULT CALLBACK SCProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	switch (message){
    	case WM_PAINT:{
    		if(wParam==0)
    			SetStaticBasic(hWnd);//siehe oben
    		if (wParam==20)
    			SetStaticMouseEnter(hWnd);
    		UpdateWindow(hWnd);
    		break;
    	}
    	case WM_MOUSEMOVE:		
    		if(_MouseOver==false){
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_HOVER;
    			tme.dwHoverTime = 100;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			SetCapture(hWnd);
    		}else {
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_LEAVE;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			SetCapture(hWnd);			
    		}
    		break;
    	case WM_MOUSEHOVER:{
    		_MouseOver=false;
    		ReleaseCapture();
    		return CallWindowProc(SCProc,hWnd, 15, 20, lParam);
    	}
    	case WM_MOUSELEAVE :{
    		_MouseOver=false;
    		ReleaseCapture();
    		return CallWindowProc(SCProc,hWnd, 15, 0, lParam);
    	}
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return CallWindowProc(wndprocSC,hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    bool SetStaticMouseEnter(HWND hWnd){
    	HDC hdc;
    	RECT rect;
    	PAINTSTRUCT ps;	
    	TCHAR *szText = NULL;
    
    	hdc = BeginPaint(hWnd, &ps);
    	GetClientRect(hWnd, &rect);
    
    	int nTextLength = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1;
    	szText = new TCHAR[nTextLength];
    	SendMessage(hWnd, WM_GETTEXT, nTextLength, (LPARAM)szText);
    
    	HFONT myFont=CreateFont(30,0,0,0,FW_NORMAL,TRUE,FALSE,0,
    							ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
    							DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,L"Arial");
    	SelectObject(hdc,myFont);
    
    	SetTextColor(hdc, RGB(255, 153, 0));
    	SetBkMode(hdc, TRANSPARENT);
    	DrawText(hdc, szText, -1, &rect, DT_SINGLELINE);
    
    	DeleteObject(myFont);
    	delete[] szText;
    
    	EndPaint(hWnd, &ps);
    	return true;
    }
    


  • Sorry. Dachte daran:

    https://msdn.microsoft.com/en-us/library/windows/desktop/dd145002(v=vs.85).aspx

    UpdateWindow müsste auvh gehen. UpdateWindow ist aber nicht die Reaktion auf WM_PAINT sondrrn die Ursache.

    UpdateWindow musst Du als Reaktion auf die Maudbewgung aufrufen. Auch genügt es, das Handle des static controls zu übergeben. Nur das soll ja neu gezeichnet werden.

    Fg Martin
    P.s: Scheißandroidtastatur.



  • Sorry. Dachte daran:

    https://msdn.microsoft.com/en-us/library/windows/desktop/dd145002(v=vs.85).aspx

    UpdateWindow müsste auvh gehen. UpdateWindow ist aber nicht die Reaktion auf WM_PAINT sondrrn die Ursache.

    UpdateWindow musst Du als Reaktion auf die Maudbewgung aufrufen. Auch genügt es, das Handle des static controls zu übergeben. Nur das soll ja neu gezeichnet werden.

    Fg Martin
    P.s: Scheißandroidtastatur.



  • danke ... ich werde es mir morgen oder übermorgen abend nochmals anschauen ...

    schlaf gut



  • Also ich persönlich finde der Wechsel von einem zum Anderen ein wenig träge. Kann man das eventuell noch performanter machen?

    Funktionieren tut's mit dieser Callback-Funktion.

    LRESULT CALLBACK SCProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    	PAINTSTRUCT ps;RECT rect;HDC hdc;	
    	int wmId, wmEvent;
    
    	switch (message){
    	case WM_PAINT:{		
    		InvalidateRect(hWnd,NULL,TRUE);
    		hdc = BeginPaint(hWnd, &ps);		
    		GetClientRect(hWnd, &rect);
    		FillRect(hdc,&rect,(HBRUSH)WHITE_BRUSH);
    		if(wParam==0)SetStaticBasic(hWnd,hdc,rect);
    		if (wParam==20)SetStaticMouseEnter(hWnd,hdc,rect);
    		EndPaint(hWnd, &ps);
    		//ValidateRect(hWnd,NULL);
    		break;
    	}
    	case WM_COMMAND:{
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		switch (wmId){
    		case ID_LEER:
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    	}
    	case WM_MOUSEMOVE:		
    		if(_MouseOver==false){
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_HOVER;
    			tme.dwHoverTime = 100;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			//SetCapture(hWnd);
    		}else {
    			TRACKMOUSEEVENT tme;
    			tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_LEAVE;
                tme.hwndTrack = hWnd;
                TrackMouseEvent(&tme);
                _MouseOver = true;			
    			//SetCapture(hWnd);			
    		}
    		break;
    	case WM_MOUSEHOVER:{
    		_MouseOver=false;
    		//ReleaseCapture();
    		return SendMessage(hWnd, WM_PAINT, 20, lParam);
    	}
    	case WM_MOUSELEAVE :{
    		_MouseOver=false;
    		//ReleaseCapture();
    		return SendMessage(hWnd, WM_PAINT, 0, lParam);
    	}
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return CallWindowProc(wndOrigProcSC,hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    

    Edit: Capture rausgenommen.


  • Mod

    Du brauchst kein Capture, wenn Du TrackMouseEvent benutzt.
    Warum?

    Nur wenn Du es nicht benutzt benötigst Du es.



  • Hallo und Guten Tag

    Ich hab alle Capture rausgenommen. Den Unterschied merkt man ein wenig.

    Nochmals Danke für die Hilfe.

    wachs

    PS. Ich hab versucht einen Anhang (StaticControlMain.cpp) mitzugeben. Ist das nicht möglich?


Anmelden zum Antworten