BBC BASIC for Windows
Programming >> User Interface >> List Box Notification
http://bb4w.conforums.com/index.cgi?board=ui&action=display&num=1376182172

List Box Notification
Post by Matt on Aug 2nd, 2013, 2:43pm

Hi,

Is there some setting that might restrict the return of a notification? This is a routine that I've been using and until now has been reporting all notifications. However, it has now stopped returning all but LBN_SETFOCUS and LBN_DBLCLK.

Code:
      DEF FN_clickp(RETURN H%, RETURN L%, RETURN P%) 
      LOCAL c%(), d%()
      DIM c%(1), d%(1)
      ON SYS LOCAL c%() = @wparam%, @lparam% : RETURN
      c%() = 0
      REPEAT
        d%() = 0
        WAIT 1
        SWAP c%(), d%()
      UNTIL d%(0) <> 0 OR d%(1) <> 0
      H% = d%(0) DIV &10000 : L% = d%(0) MOD &10000 : P% = d%(1)
      PRINT H%, L% : REM to test the notifications
      = FALSE 

While selecting a list box, I cannot get LBN_SELCHANGE.

I use this routine in other programs and it seems to work fine. I cannot find a difference in the set up of the list boxes or use of the procedure in any of the programs.

Matt
Re: List Box Notification
Post by admin on Aug 2nd, 2013, 4:22pm

on Aug 2nd, 2013, 2:43pm, Matt wrote:
I use this routine in other programs and it seems to work fine.

The flaw with the routine is that it doesn't guarantee that every notification will be seen. If two or more notifications arrive in quick succession (which is common with some controls) it is likely that you will miss one of them - usually the first. What's worse is that it may be highly variable - you may see both events when run on a fast machine but not on a slower one. Or you may see both events when no other process is running but only one if another process is occupying some CPU time.

If two or more notifications can arrive in quick succession, and it's essential that you see both of them, then you need to use a different technique. One way is to call a procedure:

Code:
      ON SYS LOCAL PROChandler(@wparam%, @lparam%) : RETURN 

Alternatively you can implement an event queue:

http://bb4w.wikispaces.com/Queueing+event+interrupts

(note the comment at the top about using the EVENTLIB library).

Richard.
Re: List Box Notification
Post by Matt on Aug 2nd, 2013, 7:50pm

on Aug 2nd, 2013, 4:22pm, Richard Russell wrote:
One way is to call a procedure:
Alternatively you can implement an event queue:

No matter how I do it, I can't get all the notifications. When I call the procedure, I get SET and KILL focus, but not SELCHANGE or DBLCLK

Quote:
(note the comment at the top about using the EVENTLIB library).

I don't get a link to this. There doesn't seem to be a link on the wiki page, and EVENTLIB is not in the BB4W LIBs.

Matt
Re: List Box Notification
Post by admin on Aug 2nd, 2013, 8:49pm

on Aug 2nd, 2013, 7:50pm, Matt wrote:
No matter how I do it, I can't get all the notifications. When I call the procedure, I get SET and KILL focus, but not SELCHANGE or DBLCLK

I can think of one possible explanation. WINLIB2 automatically sets the LBS_NOTIFY style bit, but the documentation doesn't tell you that. So if, not knowing that the bit is set by default, you specify LBS_NOTIFY in your PROC_listbox() call the two will 'cancel out' and the bit will end up not being set - the opposite of what you intended!

Check the final parameter of your PROC_listbox() call and if you've included LBS_NOTIFY in the style value, remove it.

Richard.

Re: List Box Notification
Post by Matt on Aug 3rd, 2013, 05:17am

Hi, Richard,

Thanks for all your help.

I have finally figured out what the problem was. As many of the other controls cause other actions to take place, I added a 'global' (within the proc) PROC_setfocus to the main dialog box. Removing this allowed all the notifications to be sent. (This isn't the best way of explaining, and I'm sure you could explain it better. I'd be interested to know exactly what is happening, as I'm not fully aware of what's actually going on - only that it now works.)

It now means that I have to add more setfocusses to each diversion.

Thanks again.

Matt.
Re: List Box Notification
Post by admin on Aug 3rd, 2013, 09:29am

on Aug 3rd, 2013, 05:17am, Matt wrote:
I'd be interested to know exactly what is happening

I don't know, but I do know that you should never use SetFocus with a dialogue box. There's a special message provided WM_NEXTDLGCTL which you should use instead:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms645432.aspx

"This message performs additional dialog box management operations beyond those performed by the SetFocus function".

So it's probable that missing out on the "additional management functions" is the cause of your problem.

I would additionally point out that, of course, the dialogue box itself (i.e. the parent window of the controls) never has input focus - there is nothing to receive input - and if you attempt to SetFocus to such a window you are likely to break all sorts of things.

Richard.
Re: List Box Notification
Post by Matt on Aug 3rd, 2013, 8:07pm

on Aug 3rd, 2013, 09:29am, Richard Russell wrote:
I do know that you should never use SetFocus with a dialogue box. There's a special message provided WM_NEXTDLGCTL which you should use instead...
I would additionally point out that, of course, the dialogue box itself (i.e. the parent window of the controls) never has input focus - there is nothing to receive input - and if you attempt to SetFocus to such a window you are likely to break all sorts of things.

When the user clicks on one of the buttons in the dialog box, a message box may appear. When they dismiss it, the focus returns to the main window, not the dialog box. I've always used PROC_setfocus(!dlg%) to return focus to the dialog box. If you're telling me that this could cause problems and I should use WM_NEXTDLGCTL instead, I'll have to find out where and how to use it, as I'm not used to using WM_ commands.

Thanks.

Matt
Re: List Box Notification
Post by Matt on Aug 3rd, 2013, 8:52pm

In place of a setfocus command, which immediately followed the close of the message box, I tried putting

SYS "PostMessage", dlg%, WM_NEXTDLGCTL, 0, 0

which seemed to me to be what the MSDN page was suggesting. Using PostMessage rather than SendMessage (although I tried both), and 0, 0 as this should force the focus to be on the next tabstop.

I think!

However, it didn't work. I'm obviously missing something.

I also tried using a different approach with the setfocus.

SYS "GetDlgItem", !dlg%, id% TO focus%
PROC_setfocus(focus%)

As the control, id%, can receive input, it should be able to have focus. No? Is this still a potential for problems?

Matt
Re: List Box Notification
Post by admin on Aug 3rd, 2013, 8:55pm

on Aug 3rd, 2013, 8:07pm, Matt wrote:
When the user clicks on one of the buttons in the dialog box, a message box may appear. When they dismiss it, the focus returns to the main window, not the dialog box

I'm somewhat surprised. What owner window are you specifying for the MessageBox? It's important that you pass the window handle of the dialogue box as the owner, not (for example) @hwnd% or zero:

Code:
      SYS "MessageBox", !myDlg%, message$, title$, type%
 

Quote:
I'm not used to using WM_ commands.

This same issue came up only recently in the thread Changing the style of a dialog control when you wanted to send the EM_SETREADONLY message. The answer is exactly the same: you need to call SendMessage or PostMessage (arguably the most important functions in the entire Windows API).

Richard.

Re: List Box Notification
Post by admin on Aug 3rd, 2013, 11:20pm

on Aug 3rd, 2013, 8:52pm, Matt wrote:
SYS "PostMessage", dlg%, WM_NEXTDLGCTL, 0, 0

Without seeing the rest of your code I can't be sure, but shouldn't dlg% be !dlg% here?

Quote:
Is this still a potential for problems?

Did you miss my earlier message? I answered that, and even linked to the MSDN page which explains why it is.

But I still worry that you've rather lost the plot. I wouldn't have expected dismissing a Message Box to cause the focus to be lost. I think you should be attempting to fix that, rather than working around it.

Richard.
Re: List Box Notification
Post by Matt on Aug 4th, 2013, 06:29am

Quote:
It's important that you pass the window handle of the dialogue box as the owner, not (for example) @hwnd% or zero.

I've always assumed that 'handle of owner window' was the main window, i.e. @hwnd%. I didn't realise that 'owner' was the window directly from which the message box was produced. Without going through the entire BB4W help, it always states @hwnd% without specifying anything different, and I've always assumed it to be for all messages, etc. My lack of understanding, I think. This changes all.

Quote:
Did you miss my earlier message? I answered that, and even linked to the MSDN page which explains why it is.

I did read it, but you stated that I shouldn't use the dialog box to set the focus to, as "there is nothing to receive input". However, using one of the dialog controls that does receive input seemed to be a logical step from your statement.

Matt
Re: List Box Notification
Post by admin on Aug 4th, 2013, 09:48am

on Aug 4th, 2013, 06:29am, Matt wrote:
I've always assumed that 'handle of owner window' was the main window, i.e. @hwnd%. I didn't realise that 'owner' was the window directly from which the message box was produced.

Think about why the MessageBox API would need to know what the owner window is. There are basically two reasons:
  1. So it knows where in the Z-order the message box should be displayed. If you specify @hwnd% rather than the dialogue box handle it's entirely possible that Windows will display the message box (invisibly) behind the dialogue box - I've seen it happen.

  2. So it knows what window should receive the input focus when the message box is dismissed.
Quote:
Without going through the entire BB4W help, it always states @hwnd% without specifying anything different

Well, yes, because @hwnd% is the only window created by BB4W. It's the one window you know will always exist, and in the great majority of programs it's the only window which does exist. It would be unwieldy and confusing to add after every reference to @hwnd% "substitute the handle of your dialogue box if any". Edit: but I have now added a comment to the MessageBox section.

More generally, if you call the Windows API it is assumed that you will have a reasonable understanding of the internal workings of Windows itself, especially things like how windows are created, how they are identified (e.g. handles) and how they communicate (e.g. messages).

Quote:
I did read it, but you stated that I shouldn't use the dialog box to set the focus to, as "there is nothing to receive input". However, using one of the dialog controls that does receive input seemed to be a logical step from your statement.

I also said "There's a special message provided WM_NEXTDLGCTL which you should use instead" and, quoting from MSDN, "This message performs additional dialog box management operations beyond those performed by the SetFocus function". From those comments it should have been clear that calling PROC_setfocus on a dialogue control is not safe.

Richard.

Re: List Box Notification
Post by Matt on Aug 4th, 2013, 12:55pm

on Aug 4th, 2013, 09:48am, Richard Russell wrote:
So it knows where in the Z-order the message box should be displayed. If you specify @hwnd% rather than the dialogue box handle it's entirely possible that Windows will display the message box (invisibly) behind the dialogue box - I've seen it happen.

That answers a big question.

Quote:
More generally, if you call the Windows API it is assumed that you will have a reasonable understanding of the internal workings of Windows itself, especially things like how windows are created, how they are identified (e.g. handles) and how they communicate (e.g. messages).

Perhaps. But the more I find out about calling the Windows API, the more I realise how little I know about Windows itself.

Quote:
I also said "There's a special message provided WM_NEXTDLGCTL which you should use instead" and, quoting from MSDN, "This message performs additional dialog box management operations beyond those performed by the SetFocus function". From those comments it should have been clear that calling PROC_setfocus on a dialogue control is not safe.

May it should have, but to me all it says is that using WM_NEXTDLGCTL is better than SetFocus, not that it should be used instead of.

But thanks for clarifying.

Matt
Re: List Box Notification
Post by admin on Aug 4th, 2013, 4:40pm

on Aug 4th, 2013, 12:55pm, Matt wrote:
to me all it says is that using WM_NEXTDLGCTL is better than SetFocus, not that it should be used instead of.

If it's better that can only mean that the alternative is for it not to work correctly in some fashion or other. Since when is software that doesn't work correctly acceptable? You almost seem to be saying that you don't mind your software failing, so long as it fails only a little bit!

Richard.

Re: List Box Notification
Post by Matt on Aug 5th, 2013, 04:49am

on Aug 4th, 2013, 4:40pm, Richard Russell wrote:
If it's better that can only mean that the alternative is for it not to work correctly in some fashion or other. Since when is software that doesn't work correctly acceptable? You almost seem to be saying that you don't mind your software failing, so long as it fails only a little bit!

On the contrary, on both accounts.

MDSN states 'This message performs additional dialog box management operations beyond those performed by the SetFocus function' (emphasis added). This means that whereas SetFocus works, WM_NEXTDLGCTL does more!

I definitely do mind my software failing, but I'm also happy to use a method that is simple and does the job. If another method that does more but is more complicated (not that I'm saying in this case that WM_NEXTDLGCTL is more complicated) then why use it?

Matt
Re: List Box Notification
Post by admin on Aug 5th, 2013, 10:32am

on Aug 5th, 2013, 04:49am, Matt wrote:
If another method that does more but is more complicated (not that I'm saying in this case that WM_NEXTDLGCTL is more complicated) then why use it?

Because, as I keep saying, otherwise it doesn't work correctly. Since for some reason you seem not to want to believe me, I would refer you to Raymond Chen's blog:

http://blogs.msdn.com/b/oldnewthing/archive/2004/08/02/205624.aspx

"To avoid this problem, don't use SetFocus to change focus on a dialog. Instead, use the WM_NEXTDLGCTL message.
As the remarks for the WM_NEXTDLGCTL message observe, the DefDlgProc function handles the WM_NEXTDLGCTL message by updating all the internal dialog manager bookkeeping, deciding which button should be default, all that good stuff.
Now you can update dialog boxes like the professionals, avoiding oddities like having no default button, or worse, multiple default buttons!
"

So now you know exactly the consequences of not writing your code "like the professionals". I can only hope that you have more regard for Raymond's opinion than you evidently have for mine.

Richard.
Re: List Box Notification
Post by Matt on Aug 6th, 2013, 05:29am

on Aug 5th, 2013, 10:32am, Richard Russell wrote:
Because, as I keep saying, otherwise it doesn't work correctly.

As you are quite fond of saying, you obviously didn't read my post properly. I wasn't referring specifically to SetFocus, but to general procedures. If something does work correctly and is simple...

Quote:
I can only hope that you have more regard for Raymond's opinion than you evidently have for mine.

In fact, my regard for you opinion is quite high. But I will not just accept your opinion blindly if I don't understand it. Unfortunately, whereas you obviously have the ability to learn, absorb and understand the intricacies of, at least, the workings of a computer, I, just like others, seem to struggle. Sometimes the answers are hidden and we need to search for them (sometimes, needing help, time and time again) and other times the answer is right under our noses, but we cannot see. Do not confuse ignorance with carelessness, or a lack of regard for your opinion.

Matt
Re: List Box Notification
Post by admin on Aug 6th, 2013, 1:08pm

on Aug 6th, 2013, 05:29am, Matt wrote:
Do not confuse ignorance with carelessness, or a lack of regard for your opinion.

BBC BASIC provides only a low level access to the Windows API. That means that, as soon as you move beyond the capabilities of the supplied libraries, a good understanding of the internal workings of Windows is necessary before you can successfully program GUI features from BBC BASIC. That level of understanding comes only with experience.

The same is not true of some other languages. For example both Visual BASIC and Liberty BASIC provide a high-level interface to the Windows API. Using those it is possible for a complete beginner to write GUI-based programs easily and safely.

Richard.
Re: List Box Notification
Post by admin on Aug 10th, 2013, 8:17pm

on Aug 2nd, 2013, 7:50pm, Matt wrote:
EVENTLIB is not in the BB4W LIBs.

Sorry for not responding to this earlier, but EVENTLIB is one of the standard supplied libraries. If it's not in your LIB folder, reinstalling BB4W (v5.94a) will put it there.

Richard.
Re: List Box Notification
Post by Matt on Sep 2nd, 2013, 5:00pm

OK. What am I doing wrong?!

I've studied all that I can find relating to this and I just can't make it work.

Code:
      INSTALL @lib$+"WINLIB2"
      INSTALL @lib$+"WINLIB5"
      
      WM_NEXTDLGCTL = 40
      
      dlg1% = FN_DLG1
      dlg2% = FN_DLG2
      
      PROC_showdialog(dlg1%)
      
      PROC_showdialog(dlg2%)
      WAIT 100
      PROC_closedialog(dlg2%)
      
      REM THIS LINE DOESN'T WORK
      REM SYS "PostMessage", !dlg1%, WM_NEXTDLGCTL, 0, 0 TO result% : PRINT result%
      
      REM THIS LINE DOES WORK
      REM SYS "GetDlgItem", !dlg1%, 1 TO h% : PROC_setfocus(h%)
      
      WAIT 100
      
      PROC_closedialog(dlg1%)
      END
      
      DEF FN_DLG1
      LOCAL dlg%
      dlg%=FN_newdialog("Dialogue box 1",150,50,160,128,8,180)
      PROC_pushbutton( dlg%, "OK",1,16,104,50,14,&20001):REM  BS_DEFPUSHBUTTON, WS_TABSTOP, WS_GROUP
      PROC_pushbutton( dlg%, "Cancel",2,88,104,50,14,&0)
      =dlg%
      
      DEF FN_DLG2
      LOCAL dlg%
      dlg%=FN_newdialog("Dialogue box 2",160,60,160,128,8,180)
      PROC_pushbutton( dlg%, "OK",1,16,104,50,14,&20001):REM  BS_DEFPUSHBUTTON, WS_TABSTOP, WS_GROUP
      PROC_pushbutton( dlg%, "Cancel",2,88,104,50,14,&0)
      =dlg% 


The "PostMessage" line (when un-REMmed) does not return focus to the first dialog box, but the "GetDlgItem" line does. (Yes, Richard, I know I'm not supposed to be using it. It's just there as a comparison. It's the "PostMessage" I'm more interested in.) Is there another command that I should be adding to the code? As I said, I've gone through all the texts that I can think of in relation to this.

Matt
Re: List Box Notification
Post by admin on Sep 2nd, 2013, 5:29pm

on Sep 2nd, 2013, 5:00pm, Matt wrote:
OK. What am I doing wrong?

This is what MSDN says about the WM_NEXTDLGCTL message: "wParam: If lParam is TRUE, this parameter identifies the control that receives the focus":

http://msdn.microsoft.com/en-us/library/windows/desktop/ms645432.aspx

So to transfer the focus to a specific control you need to set wParam to the window handle of the control and lParam to 'true' (i.e. 1, for Windows, although any non-zero value may work). However that's not what you do in your code; you set both wParam and lParam to zero:

Code:
      REM SYS "PostMessage", !dlg1%, WM_NEXTDLGCTL, 0, 0 TO result% : PRINT result% 

As it tells you in the MSDN page, setting both wParam and lParam to zero means "the next control [with the WS_TABSTOP style] receives the focus"; effectively it has the same effect as pressing the Tab key.

Richard.

Re: List Box Notification
Post by Matt on Sep 2nd, 2013, 6:57pm

So does that mean, then, that SYS "PostMessage", !dlg%, WM_NEXTDLGCTL, 0, 0 would normally be used when the dialog box already has focus, but when closing a child dialog box, what is required is to select the control of the parent box that initially requires focus, i.e. SYS "PostMessage", !dlg%, WM_NEXTDLGCTL, ctrl%, 1?

Edit: Just realised that the ctrl% parameter should be the control handle rather than the control id. Although it does say this, I was using the id because, in my experience, it's unusual to have both the window handle and the control handle. Normally, I've found that it's either the window handle and the control id, or the control handle only.

It's sorted anyway.

Matt
Re: List Box Notification
Post by admin on Sep 2nd, 2013, 7:59pm

on Sep 2nd, 2013, 6:57pm, Matt wrote:
So does that mean, then, that SYS "PostMessage", !dlg%, WM_NEXTDLGCTL, 0, 0 would normally be used when the dialog box already has focus, but when closing a child dialog box

It's difficult to speculate on what a particular API might 'normally' be used for. Since the action is that of the Tab key (moving the input focus to the next control having the WS_TABSTOP style), I would expect that the most likely use is exactly that, i.e. to be called (internally to Windows) when the Tab key is pressed.

Bear in mind that the API functions documented in MSDN aren't necessarily intended to be called from an application, many of them are primarily for internal use within Windows.

Quote:
what is required is to select the control of the parent box that initially requires focus

I'm not sure what you mean by "parent box" in this context. Do you mean the parent window of the controls, i.e. the dialogue box itself, or the parent window of the dialogue box? Normally a dialogue box shouldn't have a parent - i.e. it shouldn't be a child window. The reason is that child windows are constrained to remain within the client area of their parent window, and the expectation is that you will be able to move a dialogue box freely anywhere on the screen.

The parent window of the controls (i.e. the dialogue box itself) should never have the input focus - I'm not even sure that it is possible. It only makes sense to give the input focus to a window which can receive input! Since the dialogue box itself can't receive input (where would it go?) it should never have the input focus.

Does that answer the question?

Richard.
Re: List Box Notification
Post by Matt on Sep 3rd, 2013, 04:48am

It certainly does.

My mistake is for using words which aren't technically correct. What I meant by parent / child box is a dialog box called by a routine that, when a button is pressed within that box, calls yet another dialog box - which, I aggree, is not technically called a parent / child window.

Sorry for the confusion. And thanks for answering it better than I asked it.

Matt