Microsoft Developer Network >
Forenhomepage
>
Visual C++ General
>
Trackbar TB_PAGELEFT and TB_PAGERIGHT behavior
Trackbar TB_PAGELEFT and TB_PAGERIGHT behavior
- 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
- 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.
- Als Antwort markiertWesley YaoMSFT, ModeratorFreitag, 27. November 2009 02:18
Alle Antworten
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.- 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 - 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 - 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 - 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 - 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.
- 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.
- You can check my test app. Check up, whether such behavior exists in it.
- 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.
- 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.
- 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.
- Als Antwort markiertWesley YaoMSFT, ModeratorFreitag, 27. November 2009 02:18
- 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 - I think this topic can be changed to discussion now.

