Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28996 Discussions

undesirable scrolling behavior of listbox

rkiseral
Beginner
1,942 Views
I am having trouble with how the listbox behaves.

The behavior that I want is to have the last line programmatically added to the bottom of the listbox to always be visible and if there are more lines than can be viewed, then have the extra lines scroll off of the top.

What is happening now is that as additional lines are programmatically added, the new lines are not immediately visible and the user has to drag the vertical scroll bar down to see the last lines added.

Perhaps I am somewhat of a doofus (or even perhaps a total doofus), but I can't seem to figure out how to effect this desired behavior. I can't seem to get the program to flow through the callback routine that I established for the listbox. Nor do sending EM_LINESCROLL messages (or other similar messages) to the control (outside of the calback routine) seem to do anything.

For reference, I am using IVF 11.0.066 on a Vista Ultimate 32 bit platform. I have created a Windowed application (but not QuickWin).

The listbox is on a modeless window that sits behind the Modal main window that the user interacts with. I am placing a series of progress messages in the listbox of the modeless form to keep the user updated as to what the program is currently doing. But, once several progress messages fill up the listbox, the latest messages can't be seen without the user constantly having to put focus on that form and dragging down the scroll bar. This mostly defeats the intended purpose of the modeless form.

I am hoping that one of you forum visitors could shed some much-needed light on this vexing issue that's realy rubbing me the wrong way.

Thanks in advance,

Bob Kiser
0 Kudos
1 Solution
anthonyrichards
New Contributor III
1,942 Views
Look in the Help for list box messages beginning LB_. The message LB_SETCURSEL should do what you want when you send it to the listbox using, for example

iret=SendMessage(Hwnd,LBSETCURSEL, itemindex,0)

itemindex identifies the listbox entry you want to highlight and where Hwnd is the handle to the listbox, which you can get by using GetDlgItem(Hwndlg,IC_LISTBOX) where Hwndlg is the handle to the dialog containing the listbox control with identifier IC_LISTBOX.

"An application sends an LB_SETCURSEL message to select a string and scroll it into view, if necessary. When the new string is selected, the list box removes the highlight from the previously selected string. "

View solution in original post

0 Kudos
9 Replies
Al_Worth
Beginner
1,942 Views

The listbox control has a whole bunch of methods, one of which will no doubt position the listbox contents exactly as you desire. Are you designing the form in C++, VB, or C#? I use VB, and in the Visual Studio form designer, I would pick an appropriate looking event from the list of events formy listbox, then in the event handler subroutine that Visual Studio places in the form code file I would type (paste?) the name ofmy listbox followed by a dot. Visual Studio will offer up a listbox of it's own containing all the methods and properties that your listbox has. Clicking each in turn produces a tooltip that describes the lineitem. When you find one that looks like it will do what you want, click again and it will add it to the right of the dot. If it takes arguments, as soon as you type the left paren a tooltip will appear showing the arg list required. The particular arg you are currently typing appears in bold so you can keep track of where you are. ("Any sufficiently advance technology seems like magic" :-) )

Makes no difference where you are on the doofus scale - you will only have good things to say about how well andconveniently it works.

I'm a little in the dark as to howforms are designedwith the other languages, although my naive understanding is that all form code must be typed by the programmer. That'swhy I've become somewhat adept at VB-IVF mixed language programming.Discovering how to passstrings and arrays is an adventure, though.

How do you design and code your forms?

An additional thought that comes to mind is that the particular set of events, methods and properties that YOUR listbox has will depend upon where you got it: MFC, .NET 1.1, 2, 3, 3.5. .NET 2 is pretty good, but things started to get bountiful in 3.0. If you are using an MFC version and can't find a method to do what you want, you will probably need to add your own.
0 Kudos
Paul_Curtis
Valued Contributor I
1,942 Views
Quoting - rkiseral
... I am placing a series of progress messages in the listbox of the modeless form to keep the user updated as to what the program is currently doing. But, once several progress messages fill up the listbox, the latest messages can't be seen without the user constantly having to put focus on that form and dragging down the scroll bar

A listbox control is not well-suited for your intended purpose. The (easy) way to do exactly what you want is to create a child window, and then have your computational code (main program thread) write each new progress message to the child as a line of text (ie, you put the message in a module-scoped string, and then use SendMessage to issue a WM_PAINT for the child), where the paint procedure for the child scrolls the entire contents up one line before adding the new text (from the module-scoped string) as the bottom line. This general setup can readily be improved with custom-specified foreground/background colors to highlight messages by type; you could have an optional button to duplicate the writes to a file; etc.

I can provide detailed code samples if needed.
0 Kudos
anthonyrichards
New Contributor III
1,943 Views
Look in the Help for list box messages beginning LB_. The message LB_SETCURSEL should do what you want when you send it to the listbox using, for example

iret=SendMessage(Hwnd,LBSETCURSEL, itemindex,0)

itemindex identifies the listbox entry you want to highlight and where Hwnd is the handle to the listbox, which you can get by using GetDlgItem(Hwndlg,IC_LISTBOX) where Hwndlg is the handle to the dialog containing the listbox control with identifier IC_LISTBOX.

"An application sends an LB_SETCURSEL message to select a string and scroll it into view, if necessary. When the new string is selected, the list box removes the highlight from the previously selected string. "

0 Kudos
rwg
Beginner
1,942 Views
You can use LB_SETTOPINDEX too. If you have lots of messages to display don't call it for every message but only e.g. every 10th message so the user can read the output.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,942 Views
Quoting - rkiseral
Nor do sending EM_LINESCROLL messages (or other similar messages) to the control (outside of the calback routine) seem to do anything.

You got a number of useful alternatives, but what you said here is the bottom line: by design of IFLOGM, SendMessage (or its IFLOGM wrapper DlgSendCtrlMessage) can work only from the callbacks. The reason for that is that they require a valid window handle, but the dialog really exists only from DLGMODAL/DLGMODELESS onwards. The DLGSETs that you use to initialize the dialogs are "buffered" between DLGINIT and DLGMODAL, but DlgSendCtrlMessage's aren't.

To initialize your controls using SendMessage/SendDlgItemMessage/DlgSendCtrlMessage, you have to define a DLG_INIT callback and make the calls from there.
0 Kudos
rkiseral
Beginner
1,942 Views
Wow, thanks for all the useful feedback!

I will get right to work on trying out the suggestions made above and see what I can get to work for me.

I will report back as to what I find as I suspect that others might benefit from what I learn as well.

That's the great thing about these formus - we can learn from each other and together we can all get further down the road.

Thanks everyone.

Best regards,

Bob Kiser
0 Kudos
rkiseral
Beginner
1,942 Views
Quoting - Paul Curtis

A listbox control is not well-suited for your intended purpose. The (easy) way to do exactly what you want is to create a child window, and then have your computational code (main program thread) write each new progress message to the child as a line of text (ie, you put the message in a module-scoped string, and then use SendMessage to issue a WM_PAINT for the child), where the paint procedure for the child scrolls the entire contents up one line before adding the new text (from the module-scoped string) as the bottom line. This general setup can readily be improved with custom-specified foreground/background colors to highlight messages by type; you could have an optional button to duplicate the writes to a file; etc.

I can provide detailed code samples if needed.

Yes, Mr. Curtis, I would indeed like to see the detailed code examples that you speak of, as I am still struggling with this problem. How would I go about getting access to them?

Thanks,
Bob Kiser


0 Kudos
rkiseral
Beginner
1,942 Views
I am reporting back to say that I was able to solve my problem with the help of several of the contributors above.

Basically, the approach that worked for me employed the message: LB_SETCURSEL.

There are, however, a few small "gotchas" which, as it happened, got me:

1. The List Box's Item Index is zero-based, not one-based. Specifying too high an Index achieves nothing.
2. You need to set the Selection property to something other than None. I set it to Single.

Hoping it will be of some benefit to other readers, below is a snippet of code from my subroutine called AddLineToScrollingUpdate:


**********************************************
* the List Box is IDed with: IDC_CONTAINER
**********************************************

pControlID = IDC_CONTAINER

********************************************************
* add the new line to whatever's in the List box now
********************************************************

RC = DlgSetChar(gScrollingUpdateDialog, pControlID,
trim(pString), DLG_ADDSTRING)

*************************************************************
* inquire as to how many items the List Box currently has
*************************************************************

RC = DlgGetInt( gScrollingUpdateDialog, pControlID,
pNumberOfItems, DLG_NUMITEMS)

**************************************************************
* now send a message to that control telling it
* to select (highlight) the specified Item. (the last line)
* Note that the Items are in a Zero-based array.
*
* Note: using LB_SETCURSEL will cause the desired item to
* scroll into view if it is not currently visible.
*
* Note: in the properties window for this control
* make sure that the setting for the Property: Selection
* is set to: Single.
*
* First, we have to inquire as to the Window Handle for this
* particular List Box.
*************************************************************

hWnd = GetDlgitem( gScrollingUpdateDialog%hwnd, pControlID )

pItemIndex = pNumberOfItems - 1 ! zero-based array
RC = SendMessage(hWnd, LB_SETCURSEL, pItemIndex, 0 )

*****************************************************
* now remove the selection indication (background
* colored blue) by un-selecting the item
* by passing an Item Index of -1
*****************************************************

RC = SendMessage(hWnd, LB_SETCURSEL, -1, 0 )


========================================================

Obviously, your Control ID will be different.

The variable: gScrollingUpdateDialog is a global variable, passed through COMMON, that keeps track of this modeless form's dialog ID.

This code snippet ensures that the last line added to the List Box on the modeless form will be in view without the user having to do anything.


I hope that this is of some help to others.

Thanks again to the responders above,
Bob Kiser

0 Kudos
anthonyrichards
New Contributor III
1,942 Views
Glad to have been of some assistance and that it has worked out for you.

0 Kudos
Reply