Microsoft Developer Network > Forenhomepage > Visual C++ General > Trackbar TB_PAGELEFT and TB_PAGERIGHT behavior
Stellen Sie eine FrageStellen Sie eine Frage
 

BeantwortetTrackbar TB_PAGELEFT and TB_PAGERIGHT behavior

  • Montag, 2. November 2009 21:56McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Hello,

    I have an interesting situation that it seems someone must have encountered before, but I've been searching around for a few days and haven't found any answers.

    I wrote an application with a dialog box that has several trackbars.  The notification messages TB_PAGELEFT and TB_PAGERIGHT (aliases for SB_PAGELEFT and SB_PAGERIGHT) are used in the normal way, to handle the PgUp and PgDn keys, as well as to handle mouse clicks that move the slider by the value specified in the TBM_SETPAGESIZE message.

    As long as a trackbar has the keyboard focus, left-clicking in its "paging area" seems to behave normally.  That is, the application receives exactly one TB_PAGELEFT (or TB_PAGERIGHT) notification per mouse click, immediately followed by a TB_ENDSCROLL.  However, if I left click in the "paging area" of a different trackbar, I get *two* TB_PAGELEFT messages before the TB_ENDSCROLL the first time I click; subsequent mouse clicks behave normally as long as the focus remains in that trackbar.  It gets even more interesting if another window is at the top of the Z-order.  If another window is active on the desktop, I get *three* TB_PAGELEFT notifications the first time I click in the "paging area" of a trackbar in my application.

    Has anyone seen this?  I have a workaround for it, but I'd like to know why the multiple notifications.

    Thanks,
    Mike

    P.S. My test setup is a dual-processor Dell Precision 670 workstation running 32-bit XP Pro with all the updates.  I used Spy++ to watch message traffic.

Antworten

Alle Antworten

  • Mittwoch, 4. November 2009 07:57Wesley YaoMSFT, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     

    Hi Mike,

    I tried it but cannot reproduce this problem(a 2 trackbars app, selecting "Child Windows" in Spy++ message options window).
    Could you please provide more information about the steps to reproduce it? such as: is your app built from MFC or Win32 project? do you use message reflection for the WM_HSCROLL? if possible, a compressed sample project would be great helpful.

    Sincerely,
    Wesley


    Please mark the replies as answers if they help and unmark them if they provide no help. Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
  • Mittwoch, 4. November 2009 21:41McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Enthält Code
    Hi Wesley,

    My app is a Win32 project built under VC6.  When I used Spy++, the only message options I had checked were to receive scrollbar and trackbar messages.  Spy++ only showed scrollbar notification messages came in because TB_THUMBTRACK for example is an alias for SB_THUMBTRACK.  In any case, I could see two SB_PAGERIGHT or SB_PAGELEFT notifications per SB_ENDSCROLL message when a trackbar first got the keyboard focus.  If a trackbar already had the keyboard focus, only one SB_PAGELEFT / SB_PAGERIGHT came in per SB_ENDSCROLL.

    I can't see how to attach a zipped-up sample project, so I'll just post my source code below.  It's only three files, and they just have the trackbar code in them.

    Thanks for your reply and your help.

    Mike


    Here is TBSample.h:
    #ifndef __TBSAMPLE_H_INCLUDED__
    #define __TBSAMPLE_H_INCLUDED__
    
    #define STRICT
    #include <windows.h>
    
    // Message definitions
    #define WM_START_DIALOG	(WM_USER+0x1000)
    
    // Control definitions
    #define ID_TB_CH1ADJ	(WM_USER+0x1100)
    #define ID_EBX_CH1VAL	(WM_USER+0x1101)
    #define ID_TB_CH2ADJ	(WM_USER+0x1110)
    #define ID_EBX_CH2VAL	(WM_USER+0x1111)
    
    // Interface
    LRESULT CALLBACK WndProc(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam);
    BOOL Register(HINSTANCE hInstance);
    HWND Create(HINSTANCE hInstance,int nCmdShow);
    
    // Class TrackbarApp
    #define TrackbarApp_DefProc DefWindowProc
    BOOL  TrackbarApp_OnCreate(HWND hWnd,CREATESTRUCT FAR* lpCreateStruct);
    void TrackbarApp_OnDestroy(HWND hWnd);
    void TrackbarApp_OnCommand(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify);
    void TrackbarApp_OnPaint(HWND hWnd);
    
    // Dialog
    BOOL CALLBACK TrackbarDlg(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam);
    
    #endif
    


    Here's TBSample.c:
    //
    // TBSample.c
    //
    //		This is a test program with a dialog box that has two trackbars.  Its purpose is to see why
    // extra TB_PAGELEFT and TB_PAGERIGHT messages are received by a trackbar only when the trackbar
    // gets the keyboard focus from another control.
    //
    // Written:
    //		04-Nov-09, M. McCully
    //
    
    #define STRICT
    #include <stdio.h>
    #include <windows.h>
    #include <windowsx.h>
    #include <commctrl.h>
    #include "TBSample.h"
    
    // Variables
    static char szAppName[] = "TrackbarApp";
    static HWND MainWindow;
    static HINSTANCE hInst;
    
    static int Ch1Min = -32768;
    static int Ch1Max = 32767;
    static int Ch2Min = -32768;
    static int Ch2Max = 32767;
    
    static WNDPROC OldEditProc = NULL;
    
    
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdParam,int nCmdShow) {
    	MSG Msg;
    
    	if (!hPrevInstance)
    		if (!Register(hInstance))
    			return FALSE;
    
    	MainWindow = Create(hInstance,nCmdShow);
    	if (!MainWindow)
    		return FALSE;
    
    	ShowWindow(MainWindow,SW_HIDE);
    	InitCommonControls();
    
    // Send the WM_START_DIALOG message to get things going
    	PostMessage(MainWindow,WM_START_DIALOG,0,0L);
    // Main loop
    	while (GetMessage(&Msg,NULL,0,0)) {
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return Msg.wParam;
    }
    
    BOOL Register(HINSTANCE hInstance) {
    	WNDCLASS WndClass;
    
    	WndClass.style			= CS_HREDRAW | CS_VREDRAW;
    	WndClass.lpfnWndProc	= WndProc;
    	WndClass.cbClsExtra		= 0;
    	WndClass.cbWndExtra		= 0;
    	WndClass.hInstance		= hInstance;
    	WndClass.hIcon			= LoadIcon(NULL,IDI_APPLICATION);
    	WndClass.hCursor		= LoadCursor(NULL,IDC_ARROW);
    	WndClass.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	WndClass.lpszMenuName	= NULL;
    	WndClass.lpszClassName	= szAppName;
    
    	return (RegisterClass(&WndClass) != 0);
    }
    
    HWND Create(HINSTANCE hInstance,int nCmdShow) {
    	HWND hWnd;
    
    	hInst = hInstance;
    
    	hWnd = CreateWindow(szAppName,szAppName,WS_OVERLAPPEDWINDOW,0,0,5,5,NULL,NULL,hInstance,NULL);
    
    	if (hWnd == NULL)
    		return hWnd;
    
    	ShowWindow(hWnd,nCmdShow);
    	UpdateWindow(hWnd);
    
    	return hWnd;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam) {
    	switch (Message) {
    		HANDLE_MSG(hWnd,WM_CREATE,  TrackbarApp_OnCreate);
    		HANDLE_MSG(hWnd,WM_DESTROY, TrackbarApp_OnDestroy);
    		HANDLE_MSG(hWnd,WM_COMMAND, TrackbarApp_OnCommand);
    		HANDLE_MSG(hWnd,WM_PAINT,   TrackbarApp_OnPaint);
    		case WM_START_DIALOG:
    			DialogBox(hInst,"TrackbarDlg",hWnd,TrackbarDlg);
    			PostMessage(hWnd,WM_CLOSE,0,0L);
    			break;
    	}
    	return TrackbarApp_DefProc(hWnd,Message,wParam,lParam);
    }
    
    BOOL TrackbarApp_OnCreate(HWND hWnd,CREATESTRUCT FAR* lpCreateStruct) {
    	return TRUE;
    }
    
    void TrackbarApp_OnDestroy(HWND hWnd) {
    	PostQuitMessage(0);
    }
    
    void TrackbarApp_OnCommand(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify) {
    }
    
    void TrackbarApp_OnPaint(HWND hWnd) {
    	HDC PaintDC;
    	PAINTSTRUCT PaintStruct;
    
    	PaintDC = BeginPaint(hWnd,&PaintStruct);
    	EndPaint(hWnd,&PaintStruct);
    }
    
    BOOL CALLBACK TrackbarDlg(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) {
    	static HWND hTrackbar;
    	static HWND hCh1Adj, hCh2Adj;
    	static char s[80] = {0};
    	static int TrackingFine = 0;
    	static int x, Ch1AdjPos, Ch2AdjPos;
    	static int ThisScrollRequest = 0, LastScrollRequest = 0;
    	static FILE *fp = NULL;
    
    	switch (uMsg) {
    		case WM_INITDIALOG:
    			hCh1Adj = GetDlgItem(hDlg,ID_TB_CH1ADJ);
    			SendMessage(hCh1Adj,TBM_SETRANGE,(WPARAM)1,(LPARAM)MAKELONG(Ch1Min,Ch1Max));
    			SendMessage(hCh1Adj,TBM_SETPOS,(WPARAM)1,(LPARAM)0);
    			SendMessage(hCh1Adj,TBM_SETPAGESIZE,(WPARAM)0,(LPARAM)2);
    			SendMessage(hCh1Adj,TBM_SETTICFREQ,(WPARAM)((Ch1Max-Ch1Min)/10),(LPARAM)0);
    			Edit_SetText(GetDlgItem(hDlg,ID_EBX_CH1VAL),"0");
    			hCh2Adj = GetDlgItem(hDlg,ID_TB_CH2ADJ);
    			SendMessage(hCh2Adj,TBM_SETRANGE,(WPARAM)1,(LPARAM)MAKELONG(Ch1Min,Ch1Max));
    			SendMessage(hCh2Adj,TBM_SETPOS,(WPARAM)1,(LPARAM)0);
    			SendMessage(hCh2Adj,TBM_SETPAGESIZE,(WPARAM)0,(LPARAM)2);
    			SendMessage(hCh2Adj,TBM_SETTICFREQ,(WPARAM)((Ch1Max-Ch1Min)/10),(LPARAM)0);
    			Edit_SetText(GetDlgItem(hDlg,ID_EBX_CH2VAL),"0");
    			return TRUE;
    		case WM_VSCROLL:
    		case WM_HSCROLL:
    			hTrackbar = (HWND)lParam;
    			x = SendMessage(hTrackbar,TBM_GETPOS,0,0);
    			LastScrollRequest = ThisScrollRequest;
    			ThisScrollRequest = LOWORD(wParam);
    			switch (ThisScrollRequest) {
    				case SB_THUMBTRACK:						// Same as TB_THUMBTRACK
    				case SB_LEFT:							// Same as TB_TOP
    				case SB_RIGHT:							// Same as TB_BOTTOM
    				case SB_LINELEFT:						// Same as TB_LINEUP
    				case SB_LINERIGHT:						// Same as TB_LINEDOWN
    				case SB_PAGELEFT:						// Same as TB_PAGEUP
    				case SB_PAGERIGHT:						// Same as TB_PAGEDOWN
    					if (hTrackbar == hCh1Adj) {
    						Ch1AdjPos = x;
    						SendMessage(hCh1Adj,TBM_SETPOS,1,(LPARAM)Ch1AdjPos);
    						sprintf(s,"%d",Ch1AdjPos);
    						Edit_SetText(GetDlgItem(hDlg,ID_EBX_CH1VAL),s);
    					}
    					else if (hTrackbar == hCh2Adj) {
    						Ch2AdjPos = x;
    						SendMessage(hCh2Adj,TBM_SETPOS,(WPARAM)1,(LPARAM)Ch2AdjPos);
    						sprintf(s,"%d",Ch2AdjPos);
    						Edit_SetText(GetDlgItem(hDlg,ID_EBX_CH2VAL),s);
    					}
    					break;
    				case SB_ENDSCROLL:						// Same as TB_ENDTRACK
    					break;
    				case SB_THUMBPOSITION:					// Same as TB_THUMBPOSITION
    					break;
    				default:
    					break;
    			}
    			return TRUE;
    		case WM_CLOSE:
    			EndDialog(hDlg,LOWORD(wParam));
    			break;
    		default:
    			break;
    	}
    	return FALSE;
    }
    
    


    Here is TBSample.rc
    #include <windows.h>
    #include "TBSample.h"
    
    TrackbarDlg DIALOG DISCARDABLE  20, 40, 323, 98
    STYLE DS_MODALFRAME | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
    CAPTION "Coarse/Fine Adjustments"
    FONT 8, "Helv"
    BEGIN
        CONTROL "Two Trackbars",         -1, "button",            BS_GROUPBOX | BS_LEFT | WS_CHILD | WS_VISIBLE,                                                     7,   4, 310,  85
        CONTROL "Channel 1",             -1, "static",            SS_LEFT | WS_CHILD | WS_VISIBLE,                                                                  12,  18,  50,  12
        CONTROL "",            ID_TB_CH1ADJ, "msctls_trackbar32", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | TBS_HORZ | TBS_AUTOTICKS | TBS_ENABLESELRANGE,   12,  28, 254,  14
        CONTROL "",           ID_EBX_CH1VAL, "edit",              ES_CENTER | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_BORDER,                    270,  29,  40,  12
        CONTROL "Channel 2",             -1, "static",            SS_LEFT | WS_CHILD | WS_VISIBLE,                                                                  12,  49,  50,  12
        CONTROL "",            ID_TB_CH2ADJ, "msctls_trackbar32", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | TBS_HORZ | TBS_AUTOTICKS | TBS_ENABLESELRANGE,   12,  59, 254,  14
        CONTROL "",           ID_EBX_CH2VAL, "edit",              ES_CENTER | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_BORDER,                    270,  60,  40,  12
    END
    

  • Mittwoch, 4. November 2009 23:04McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Here's another update.  The problem behavior is *not* exhibited if I run this same .EXE file under either Windows NT with SP6a or Windows 2000 with all windows updates.

    Mike
  • Donnerstag, 5. November 2009 01:53McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Now I'm confused, and I guess I jumped the gun.  I ran the above test program on a single-processor PC, 3.2 GHz Pentium 4 with hyperthreading on and WinXP, and it exhibits the problem behavior.  Then I ran it on my home PC, which has dual Pentium III's running at 1 GHz, also with XP, and it doesn't exhibit the problem--except that I saw it twice.  Maybe this doesn't happen on "slower" processors?  The Win2K machine in the last message has an 800 MHz Pentium III.  The NT machine has dual 400 MHz Pentium IIs.

    Mike
  • Freitag, 6. November 2009 22:10McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Just to add some information, I've run my test program on several computers with different results.  I can always get it to happen on a handful of PC's, rarely on a few PC's, and never (or not yet) on two.

    The problem is always exhibited on the following configurations:
    A 550 MHz Pentium II PC running Win98
    A 2.2 GHz Pentium 4 PC without hyperthreading running WinXP
    A 3.2 GHz Pentium 4 PC with hyperthreading running WinXP
    A 3.2 GHz Dual Xeon PC running WinXP

    The problem occurs rarely, maybe once in two or three minutes of trying, on the following configurations:
    A 400 MHz Dual Pentium III server running NT server
    A 1 GHz dual Pentium III PC running WinXP
    A 1 GHz dual Pentium III PC running Win2K

    The problem never occurs on:
    An 800 MHz Pentium III PC running Win2K
    A 2.4 GHz Core 2 Quad PC running Vista

    I think this is a real bug somewhere, and I can work around it, but it would be good to know why it happens.

    Thanks for shedding any light on this.

    Mike
  • Donnerstag, 12. November 2009 20:02Nikita Leontiev TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    I looked at your code. First of all what type of application you want to create: based on window or dialog?
    If based on window, you should use CreateWindow function and create your trackbars on the window.
    If based on dialog, you should create dialog with CreateDialog function and provide your dialog template in to it.
  • Freitag, 13. November 2009 06:58McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    I have another application that has a main window with trackbars created using CreateWindow, and it exhibits the same problem behavior, so it doesn't appear that using CreateWindow or CreateDialog will solve the problem of extra SB_PAGE* messages.  Thanks for the suggestion, though.
  • Freitag, 13. November 2009 12:57Nikita Leontiev TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    You can check my test app. Check up, whether such behavior exists in it.
  • Samstag, 14. November 2009 20:52McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Your TestApp exhibited the same behavior.  I compiled using Visual Studio 6 and got a warning about the #pragma that required comctl32.dll 6.0.0.0, but when I checked the product version of C:\Windows\system32\comctl32.dll on my system, it is 6.00.2900.5512.
  • Samstag, 14. November 2009 22:02Nikita Leontiev TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    OK. So, now I can test your problem on my app. Will look.

    P.S. You got warning, because VS 6 doesn't support attaching manifest by #pragma, only Microsoft Visual C++ 2005 or later support this feature.
  • Sonntag, 15. November 2009 10:43Nikita Leontiev TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Beantwortet
    Reproduced.
    I think it is normal behavior, because when you click left mouse button on trackbar and hold it, main window will receive many SB_PAGELEFT or SB_PAGERIGHT notify. The same thing with PgUp/PgDn keys.
  • Montag, 16. November 2009 19:42McMikie TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Thank you for taking the time to reproduce the problem.

    I don't know...if the user isn't holding the left mouse button (or PgUp/PgDn) and only clicks once in the paging area, it doesn't seem normal to me for the trackbar to behave one way when it has the keyboard focus and another way when it doesn't.  Maybe that's just my opinion, but it seems inconsistent.  I can work around it, so I guess I'll just leave it at that.

    Again--thanks for taking time to look at the problem and send an answer.

    Mike
  • Donnerstag, 26. November 2009 16:58Nikita Leontiev TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    I think this topic can be changed to discussion now.