NO

Author Topic: Listbox scrollbar notification  (Read 8772 times)

jboyes

  • Guest
Listbox scrollbar notification
« on: October 07, 2012, 06:45:06 PM »
I'm afraid I am looking for some help again - but it has been a while.

I am writing an application to download DMX slot information to the EEPROM of a PIC micocontroller. I have a listbox containing the values and next to it I have placed a textbox which displays the appropriate index numbers alongside.

When I scroll the listbox, I want the indices to change along with the data values. I can get this to work but I have to click on a separate button each time or (unnecessarily) select an item from the listbox in order to trigger my routine for updating the indices.

What I need is a way of getting notification when the listbox is scrolled but I just cannot figure out how to do it.

I found an old forum topic that suggested using a listview control and 'making it look like a listbox' but I am unable to get rid of the icons.

Any help would be appreciated especially if you could show me how to get notifications from the listbox because the listbox is the neatest (and easiest) way of listing the values.

John.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Listbox scrollbar notification
« Reply #1 on: October 07, 2012, 08:04:20 PM »
Use the LBN_SELCHANGE message from listbox.
Here can find details http://msdn.microsoft.com/en-us/library/windows/desktop/bb775161(v=vs.85).aspx
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

jboyes

  • Guest
Re: Listbox scrollbar notification
« Reply #2 on: October 07, 2012, 09:05:25 PM »
Thanks Frankie but that is exactly what I have been using (I have also used a separate button to trigger my routine). What I want though is notification of changes to the scrollbar position without having to click anything else other than the scrollbar itself.

John.

CommonTater

  • Guest
Re: Listbox scrollbar notification
« Reply #3 on: October 07, 2012, 09:28:54 PM »
Thanks Frankie but that is exactly what I have been using (I have also used a separate button to trigger my routine). What I want though is notification of changes to the scrollbar position without having to click anything else other than the scrollbar itself.

Try using a LISTVIEW control instead of a LISTBOX and TEXTBOX ...
 
The listview in details mode will let you define multiple collumns that will always stay aligned.

Offline Stefan Pendl

  • Global Moderator
  • Member
  • *****
  • Posts: 582
    • Homepage
Re: Listbox scrollbar notification
« Reply #4 on: October 07, 2012, 11:17:03 PM »
How about a multi column list box?
Use the style LBS_MULTICOLUMN and the message LB_SETCOLUMNWIDTH.

A simple list view is used by the project I am involved with, check out vollist.c.
« Last Edit: October 07, 2012, 11:51:44 PM by Stefan Pendl »
---
Stefan

Proud member of the UltraDefrag Development Team

jboyes

  • Guest
Re: Listbox scrollbar notification
« Reply #5 on: October 08, 2012, 02:27:56 PM »
Many thanks for all the help offered.

Tater:
I may end up using a Listview but I struggle to understand how to set them up. They don't seem to be as well documented as other controls.

Stephan:
Reading the documentation about multi-column listboxes, I read, "List boxes with the LBS_MULTICOLUMN style cannot be vertically scrolled. The list box ignores any WM_VSCROLL messages it receives." And, of course, it's vertical scrolling that I want  :(

Everything I want to do is working fine except fot the fact that I cannot get notification of any scrolling.  An idea has occured to me that, if I set up a Timer to notify every (say) 0.5 secs, I can compare the GetScrollPos(hScroll,SB_VERT) with the previous value (kept in memory) and, if the two values do not match, I can update my text box.  Sounds simple but I wonder if the timer would be using up too much unnecessary CPU.

John.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Listbox scrollbar notification
« Reply #6 on: October 08, 2012, 02:39:12 PM »
From MS:
"For a multiple-selection list box, the LBN_SELCHANGE notification code is sent whenever the user presses an arrow key, even if the selection does not change."
Try enabling multiple selection eventually filtering them out (if you don't want multiple selection) or subclass the control and hook on windows refresh/update
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

jboyes

  • Guest
Re: Listbox scrollbar notification
« Reply #7 on: October 08, 2012, 05:15:51 PM »
From MS:
"For a multiple-selection list box, the LBN_SELCHANGE notification code is sent whenever the user presses an arrow key, even if the selection does not change."
Try enabling multiple selection eventually filtering them out (if you don't want multiple selection) or subclass the control and hook on windows refresh/update

Thanks Frankie,

I had already tried LBN_SELCHANGE notification and it did work but, unfortunately, did not respond to any change in the scrollbar thumb or the arrows.

I'm ashamed to say that I haven't a clue about subclassing which is why my question was posted in the 'Beginners' section.


To ALL responders:

The 'Daft' idea that I came up with of using a Timer actually WORKS!  It works very well and does exactly what I wanted to acheive. I have set the perion to 0.3 seconds and I haven't bothered to check if the scroll position has changed because the code that is executed is very short.

Thanks again for all your help.

John.

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Listbox scrollbar notification
« Reply #8 on: October 08, 2012, 06:43:29 PM »
Simple ListBox subclassing example
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>

#define IDC_LBOX 4001

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char *szAppName = "WinFrame";
char *szFrameClass = "cWinFrame";
HWND hFrame;
HANDLE hInst;

HWND hList;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx;
MSG msg;

wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = (WNDPROC) WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground= (HBRUSH)COLOR_3DSHADOW;
wcx.lpszMenuName = NULL;
wcx.lpszClassName= szFrameClass;
wcx.hIconSm = 0;

if (!RegisterClassEx(&wcx))
return 0;
hInst = hInstance;

hFrame = CreateWindowEx(0, szFrameClass, szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
260, 250,
NULL, NULL, hInst, NULL);
if(!hFrame) return 0;
ShowWindow(hFrame, nCmdShow);
UpdateWindow(hFrame);

while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

void OnCreate(HWND hWnd);

LRESULT CALLBACK SubclassWndProcLB(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
WNDPROC wndProcOrigLB;

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg) {
case WM_CREATE:
OnCreate(hWnd);
return 0;
case WM_DESTROY:
SetWindowLongPtr(hList, GWLP_WNDPROC, (LONG_PTR)wndProcOrigLB);
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}

void OnCreate(HWND hWnd)
{
//InitCommonControls();
hList = CreateWindowEx(0, "ListBox", NULL,
WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VISIBLE | WS_VSCROLL
, 1, 50, 200, 100
, hWnd, (HMENU)IDC_LBOX, hInst, NULL);
for (int i = 1; i <= 10; i++) {
TCHAR szTmp[10];
wsprintf(szTmp, "row %d", i);
SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)szTmp);
}
wndProcOrigLB = (WNDPROC)SetWindowLongPtr(hList, GWLP_WNDPROC, (LONG_PTR)SubclassWndProcLB);
SetFocus(hList);
}
// Subclass Window Proc
LRESULT CALLBACK SubclassWndProcLB(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// debug it
TCHAR szTmp[100];
wsprintf(szTmp, TEXT("%Xh"), uMsg);
SetWindowText(hFrame, szTmp);
//
CallWindowProc(wndProcOrigLB, hwnd, uMsg, wParam, lParam);
}
« Last Edit: October 09, 2012, 06:07:08 PM by timovjl »
May the source be with you

CommonTater

  • Guest
Re: Listbox scrollbar notification
« Reply #9 on: October 08, 2012, 07:41:50 PM »
Setting up a listview control ... probably your best solution here...
 
 
Code: [Select]
    InitCommonControls();
 

    LVCOLUMN lc = {0};                // list view colum struct

    // log window
    gLog = CreateWindowEx(WS_EX_WINDOWEDGE,WC_LISTVIEW,NULL,
                            WS_CHILD | WS_VISIBLE | WS_TABSTOP |
                            LVS_REPORT | LVS_NOSORTHEADER,
                            0,0,0,0,gMain,(HMENU) 300,gInst,NULL);
 
   // add columns
   lc.mask = LVCF_TEXT | LVCF_WIDTH;
    lc.pszText = L"Time";
    lc.cx = 150;
    ListView_InsertColumn(gLog,0,&lc);
    lc.pszText = L"From";
    lc.cx = 100;
    ListView_InsertColumn(gLog,1,&lc);
    lc.pszText = L"Event";
    lc.cx = 300;
    ListView_InsertColumn(gLog,2,&lc);

From there just follow the API ... HERE
 
There are macros for almost everything it does....
 
 
 
 
« Last Edit: October 08, 2012, 07:53:44 PM by CommonTater »

Offline DMac

  • Member
  • *
  • Posts: 272
Re: Listbox scrollbar notification
« Reply #10 on: October 09, 2012, 04:58:24 PM »
Simple is as simple does.

From my article http://www.codeproject.com/Articles/77957/Win32-SDK-PropertyGrid-Made-Easy

Quote
Detecting Begin and End Scroll Events in a Listbox

The Listbox doesn't have a scrollbar component, instead it draws a scroll bar in the non-client area of the control probably using DrawFrameControl(). Consequently one cannot subclass the scrollbar in order to detect mouse events. The following snippet demonstrates one way to work around this and detect begin and end scroll.
Code: [Select]
static LRESULT CALLBACK ListBox_Proc(HWND hList, UINT msg,
        WPARAM wParam, LPARAM lParam)
{
    HWND hParent = GetParent(hList);

    // Note: Instance data is attached to listbox's parent
    Control_GetInstanceData(hParent, &g_lpInst);

    switch (msg)
    {
        //
        // Skip stuff
        //

        case WM_MBUTTONDOWN:
        case WM_NCLBUTTONDOWN:
            //The listbox doesn't have a scrollbar component, it draws a scroll
            // bar in the non-client area of the control.  A mouse click in the
            // non-client area then, equals clicking on a scroll bar.  A click
            // on the middle mouse button equals pan, we'll handle that as if
            // it were a scroll event.
            ListBox_OnBeginScroll(hList);
            g_lpInst->fScrolling = TRUE;
            break;

        case WM_SETCURSOR:
            //Whenever the mouse leaves the non-client area of a listbox, it
            // fires a WM_SETCURSOR message.  The same happens when the middle
            // mouse button is released.  We can use this behavior to detect the
            // completion of a scrolling operation.
            if (g_lpInst->fScrolling)
            {
                ListBox_OnEndScroll(hList);
                g_lpInst->fScrolling = FALSE;
            }
            break;

            //
            // more stuff
            //
There you have it, no need for substitutions or timers.
« Last Edit: October 09, 2012, 05:05:23 PM by DMac »
No one cares how much you know,
until they know how much you care.

jboyes

  • Guest
Re: Listbox scrollbar notification
« Reply #11 on: October 09, 2012, 08:46:01 PM »
Wow!  What a brilliant forum this is!

One day I had NO solutions to my problem - now I have FOUR viable solutions.

The problem I now have is which one to choose. I would like to try them all (and, in time, I probably will) but for now I need to just get on with my project.

Many thanks to all who have replied, I am very grateful to you all.

John.