Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Samopowtarzalny button w WinAPI

Szymon Tarnowski 21 Jun 2010 21:51 1299 3
  • #1
    Szymon Tarnowski
    Level 27  
    Witam, utknąłem na następującym problemie, potrzebuje przycisk który będzie działał jak przyciski strzałek w scrollbarze, tj:
    1. pojedyncze krótkie wciśnięcia powodują zmianę parametru
    2. przytrzymanie powoduje ciągłą zmianę parametru.
    Standardowy button ma możliwość przekazywania zdarzeń BN_PUSHED i BN_UNPUSHED jedna są one przestarzałe, ale u mnie na WinXP nie są zgłaszane, zakładam że kod jest poprawny, bo zdarzenie BN_FOCUS jest przekazywane. W MSDN jest sugestia żeby używać stylu BS_OWNERDRAW, ale powoduje to że przycisk się nie pojawia (bo to logiczne że jak chcę mieć własny kształt przycisku to GUI nie rysuje domyślnego). Próbowałem komunikatu WM_LBUTTONDOWN ale jest on przekazywany wyłącznie jeśli przycisk jest nieaktywny, a jeśli jest aktywny to zapewne button wewnętrznie go przejmuje. Czy jakieś inne sugestie jak można to zrobić, na razie nie chciałbym wnikać w wewnętrzną kolejkę komunikatów przycisku.
  • #2
    And!
    Admin of Design group
    A gdyby skorzystać z dodatkowego timera,
    który wysyłałby komunikaty co określony czas,
    i w zależności od stanu przycisku sterował pojedynczą
    lub powtarzaną akcją ?
  • Helpful post
    #3
    Akane
    Level 27  
    Poniższy przykład pokazuje jak można to zrobić bez hooków i subclass'u. Tutaj cała logika siedzi w w głównej pętli komunikatów, gdzie przechwytuję komunikaty myszki przeznaczone dla buttona, włączając odpowiedni timer.
    Wciskając przycisk, pojawia sie dźwięk (Beep). Po 500ms dźwięk zaczyna się powtarzać co 100ms.

    #include <windows.h>
    #include <commctrl.h>
    #define IDC_BUTTON 1000
    
    BOOL __stdcall MyDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	switch (uMsg)
    	{
    		case WM_CLOSE:
    			DestroyWindow(hwnd);
    			PostQuitMessage(0);
    			break;
    
    		case WM_COMMAND:
    			if (wParam == IDC_BUTTON) Beep(600,5);
    			break;
    	}
    	return FALSE;
    }
    
    void OtworzOknoZprzyciskiem(HWND *pWindow, HWND *pButton)
    {
    	*pWindow = CreateWindow(WC_DIALOG, TEXT("demo"), WS_OVERLAPPEDWINDOW|WS_VISIBLE,100,100,200,100,0,0,0,0);
    	*pButton = CreateWindow(WC_BUTTON, TEXT("click me"), WS_CHILD|WS_VISIBLE,40,20,80,20,*pWindow,(HMENU)IDC_BUTTON,0,0);
    	SendMessage(*pButton, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
    	SetWindowLong(*pWindow, DWL_DLGPROC, (LONG)MyDialogProc);
    	MyDialogProc(*pWindow, WM_INITDIALOG, 0, 0);
    }
    
    int _main()
    {
    	MSG msg;
    	HWND hDlg, hButton;
    
    	OtworzOknoZprzyciskiem(&hDlg, &hButton);
    	while (hDlg && GetMessage(&msg,0,0,0))
    	{
    		if (msg.hwnd == hButton)
    		{
    			if (msg.message == WM_LBUTTONDOWN)
    			{
    				PostMessage(hDlg, WM_COMMAND, IDC_BUTTON, 0); // akcja
    				SetTimer(hDlg, 1000, 500, 0);
    				SetCapture(hButton);
    			}
    			else if (msg.message == WM_LBUTTONUP)
    			{
    				ReleaseCapture();
    				KillTimer(hDlg, 1000);
    			}
    		}
    		else if (msg.hwnd == hDlg)
    		{
    			if (msg.message == WM_TIMER)
    			{
    				if (msg.wParam == 1000)
    				{
    					KillTimer(hDlg, 1000);
    					SetTimer(hDlg, 1000, 100, 0);
    					PostMessage(hDlg, WM_COMMAND, IDC_BUTTON, 0); // akcja
    				}
    			}
    		}
    		if (!IsDialogMessage(hDlg, &msg))
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    	return 0;
    }
    
  • #4
    Szymon Tarnowski
    Level 27  
    And! wrote:
    A gdyby skorzystać z dodatkowego timera,
    który wysyłałby komunikaty co określony czas,
    i w zależności od stanu przycisku sterował pojedynczą
    lub powtarzaną akcją ?
    No dokładnie tak chce zrobić, tyle że potrzebuje złapać zdarzenie wciśnięcia i puszczenia zamiast kliknięcia.
    Akane wrote:
    Poniższy przykład pokazuje jak można to zrobić bez hooków i subclass'u. Tutaj cała logika siedzi w w głównej pętli komunikatów, gdzie przechwytuję komunikaty myszki przeznaczone dla buttona, włączając odpowiedni timer.
    Rozumiem jak to działa, ale nie podoba mi się "wpięcię" w pętle komunikatów. Dla okna głównego będzie działać, ale dla okien dialogowych może być już problem. W każdym razie dziękuję za sugestię jak to można zrobić. Aktualnie napisałem kod oparty o subclassing, wiem że to nie jest eleganckie ale spełnia oczekiwane zadanie.