Setting PopupMenu Height

Hey guys,

One more question in Windows that is stumping me!

I’m trying to set a PopUpMenu height in Windows but nothing I enter is changing it. Yet, I can run Mitch B’s RubberViews and his code changes the height of the PopupMenu just fine! And if I pause the app and look in the IDE, I see the popup menu heights all showing as what I want them to be, but what is shown in the screen is not scaling correct.

I’ve got to be doing something dumb to not get this to work but I can’t figure it out!

I had to change PopupMenu Height on Linux (and I do that like a pig *, after thinking back to what I’ve done) and I used:

http://documentation.xojo.com/index.php/RectControl.Height

Example:

PopupMenu1.Height= 50 // For Example

in PopupMenu1.Open Event, and this do what I ask.

  • I set the value to each PopupMenu.Open Event instead of SubClassing the PopupMenu and put that in the PopupMenu SubClass then add an Open Event to the SubClass, add the code to set the Height value I want, and set the Super to all the PopupMenu I use in my Project.

By default, PopupMenus/ComboBoxes are dependent on the size of the font but the size of them should be able to be changed with

SendNotifyMessageW(PopupMenu1.Handle, CB_SETITEMHEIGHT, -1, 50) which sets the height of the base control to 50

It looks to be a bug that its not taking the size from the Height parameter in the IDE.

From an initial test, Xojo are using the correct system to resize the control, but they are doing it at the wrong time. It seems like they are setting the height when the control is clicked (but only to the default height) and not when its opened.

If you place the following code into the Popup.Open

Const CB_SETITEMHEIGHT = &h0153 Declare Function SendMessageW Lib "User32" (hWnd As Integer, Msg As UInt32, wParam As UInteger, lParam As Integer) As Integer Call SendMessageW(PopupMenu1.Handle, CB_SETITEMHEIGHT, -1, 50)

You see that it correctly sets the height to 50. As soon you click on the control it changes height again (bug?), I assume that Xojo is doing something behind the scenes here when it shouldn’t be, probably firing another SendMessageW at the control which should actually be firing at the open, and not the click.

You can see this happening if you copy the above code into PopupMenu.Open and PopupMenu.MouseDown, when you click the control a few times and the initial popup has rendered and closed, it then works for all future updates.

Michel would have to chip in here to let us know how he got around that, I could probably find out with a bit of trial and error but it would be quicker if he wants to chip in, I dont know if he wants to as he might want to protect the IP in his control.

OK. Glad I’m not seeing things. It seems this is a recent bug then as Windows was always able to adjust the height of pop-up menus. OS X is not so easy to do (you have to do it in declares and then never again poll the height property).

Now in Mitch’s code, he’s just setting it like one would normally expect. And it’s working! That’s what’s driving me nuts. I did a simple test app and his resizing works, mine doesn’t and I don’t understand why.

I dont know about rubber views Jon, I just downloaded the latest trial from Michels site, I set the PopupMenu1 with the word “Effects” in the middle of the form to 50 height and it came out as default height. However his resize when the form is resized works but he’s probably doing something that I’m not because he’s spent more time researching it :slight_smile: I don’t know, I found three bugs in rubberviews in the 2 minutes I’ve been playing with it =\ I’m just a bug magnet, hehe.

Just had a little play around, I think Michel does it by calling:

PopupMenu1.TextSize = 50 (or whatever size he calculates to be the scaling factor to fit the size he needs)

in the open. That auto-sizes the control to fit the text and increases its overall size. It’s not the correct way of doing it, but its the Xojo way. If you change that in the IDE (using the gear on inspector) it doesnt even alter the size of the control correctly (bug) until you go back into the form, then the selectable area of the control isnt right (bug).

Call SendMessageW(PopupMenu1.Handle, CB_SETITEMHEIGHT, -1, 50)

That call should work, it does, to a fashion, but there’s a load of problems going on with the control not doing things correctly. Eg, I can size it correctly, and fire this at it:

Call SendMessageW(PopupMenu1.Handle, CB_SHOWDROPDOWN, 1, 0)

which opens the popup via code and works perfectly, but the second I click the popup with the mouse it breaks and resets the size of the control. There’s so many redundant or incorrectly placed calls going on. I’m actually amazed that anything works as it should to be honest.

The control needs a huge bug report, there’s so much wrong with it it’ll take me a long time to document and prove all the problems, which is why I’m not putting in bug reports at the moment, I just cant face putting the effort in at the moment for it to be forgotten about for 6-12 months and not fixed.

Julian,

Forgive me but is there a code module some place that has the SendMessageW function?

I just shut my computer off (on my iPad) so I had to copy this from a xojo blog

Declare Sub SendMessageW Lib “User32” (hwnd As Integer, msg As Integer, wParam As Integer, lParam As Integer)

Just place that somewhere above the call.

You can find the vales for CB_* just google them, wine usually have records of the .h they are in.

[quote=340171:@]Just had a little play around, I think Michel does it by calling:

PopupMenu1.TextSize = 50 (or whatever size he calculates to be the scaling factor to fit the size he needs)

in the open. That auto-sizes the control to fit the text and increases its overall size. It’s not the correct way of doing it, but its the Xojo way. If you change that in the IDE (using the gear on inspector) it doesnt even alter the size of the control correctly (bug) until you go back into the form, then the selectable area of the control isnt right (bug).

Call SendMessageW(PopupMenu1.Handle, CB_SETITEMHEIGHT, -1, 50)

That call should work, it does, to a fashion, but there’s a load of problems going on with the control not doing things correctly. Eg, I can size it correctly, and fire this at it:

Call SendMessageW(PopupMenu1.Handle, CB_SHOWDROPDOWN, 1, 0)

which opens the popup via code and works perfectly, but the second I click the popup with the mouse it breaks and resets the size of the control. There’s so many redundant or incorrectly placed calls going on. I’m actually amazed that anything works as it should to be honest.

The control needs a huge bug report, there’s so much wrong with it it’ll take me a long time to document and prove all the problems, which is why I’m not putting in bug reports at the moment, I just cant face putting the effort in at the moment for it to be forgotten about for 6-12 months and not fixed.[/quote]

It looks like if you set the height twice with SendMessageW that it becomes permanent. I see exactly what you mean when you say you set it but then as soon as you touch it, it reverts. But if you set it again, it stays. So there’s definitely something odd going on.

Also, maybe it’s the way the controls are in Windows itself but there are specific heights that the PopUpMenu can be set to. It doesn’t seem they are all that granular.

Nice

Nope, I tried it in another language and it stuck first time.

I’m glad you got something working at least. :slight_smile:

Well, it’s weird.

First it is granular. The heights are specific. So that’s good.

But it’s like you have to touch the control first before sending the second message will make it stick. So it’s somewhat odd. I’m trying to figure out exactly what you need to do and if I can somehow simulate a touch in Xojo code but I haven’t figured it out yet…

But once it’s been “touched” and you send a second message, then it sticks…

Yeah, thats what I was seeing, I had a separate button to force the size again and it would work fine once the dropdown had been shown.

Bugs :frowning:

The control could also use a .DroppedDown boolean property to force it open/closed in code which would just be a call to:

SendMessageW(PopupMenu1.Handle, CB_SHOWDROPDOWN, 1, 0)

in windows.

It’s a little frustrating because if a user touches the control for the first time and makes a selection to the listbox, I can call SendMessageW from the change event. However, if the user touches the control but then doesn’t change the selection, the change event does not fire. MouseExit doesn’t seem to work reliably here as the mouse is generally already away from the control if there is no selection made. The resize happens AFTER the menu closes. But there is no event for that.

I thought maybe I could use SendMessageW to show the menu and control it myself but while that shows it, it seems like it doesn’t stay open.

[EDIT]

OK - The ShowDropdown message works fine. I was trying to send it in the MouseDown event of the control and then return True so I could handle things myself. But that is what doesn’t seem to work right. ARGH! :frowning:

Yeah, I’ve tried a few different combinations too, couldn’t get a satisfactory result here either :frowning:

I think I may have figured it out. I can’t try it for a bit as I have to take my daughter to swim practice.

1.) Set the height of the control the first time
2.) Show the menu using SendMessageW. Doing this causes the control to resize.
3.) set the list index to some value. Then set it to -1
4.) in the change event have the SendMessageW code to set the height

I think that may do it.

OK. This seems to do the trick:

Const CB_SHOWDROPDOWN AS Integer = &H14F

Declare Sub SendMessageW Lib "User32" (hwnd As Integer, msg As Integer, wParam As Integer, lParam As Integer)

Call SendMessageW(PopupMenu1.Handle, CB_SHOWDROPDOWN, 1, 0)
PopupMenu1.ListIndex = 1
PopupMenu1.ListIndex = -1

In the change event of the popupmenu:

Const CB_SETITEMHEIGHT As Integer = &h0153
Declare Sub SendMessageW Lib "User32" (hwnd As Integer, msg As Integer, wParam As Integer, lParam As Integer)
Call SendMessageW(me.Handle, CB_SETITEMHEIGHT, -1, 13)

13 is the height I was looking to use for the control. So that would be whatever height is wanted.

So showing the dropdown does force the resize. Once that is done, then changing the list index works to reset the size correctly. It isn’t enough to call the menu and then do the resize. Seems like you actually have to change the listindex to get it to work right.

OK. Further refinements…

I have this in the Open event for the PopupMenu. It seems to work:

Sub Open(index as Integer) Handles Open
  
  Me.addrow ""   // Add a blank row for resizing purposes.
  
// Set the size
  Const CB_SETITEMHEIGHT As Integer = &h0153 
  Declare Sub SendMessageW Lib "User32" (hwnd As Integer, msg As Integer, wParam As Integer, lParam As Integer)
 Call SendMessageW(Me.Handle, CB_SETITEMHEIGHT, -1, 13)

// Show the dropdown - This resets the size.
  Const CB_SHOWDROPDOWN As Integer = &H14F
  Call SendMessageW(me.Handle, CB_SHOWDROPDOWN, 1, 0)
  
// Now change the listindex to our dummy row.
// This forces the resize as we have the same declare in the change event 
  me.ListIndex = 1
  me.ListIndex = -1
  
// Close the menu - Seems like we need to do this in the open event otherwise the menu stays open.
  Call SendMessageW(me.Handle, CB_SHOWDROPDOWN, 0, 0)

// Remove our dummy row
  me.RemoveRow(0)
  
// Add in whatever rows you want...
  For i As Integer = 0 To 10
    Me.addrow Str(i)
  Next

End Sub

The only other thing I am thinking of doing is subclassing this and adding a “sized” property. The change event checks to see if the sized property is false. If it is false, then it runs the declare, otherwise it skips it. I don’t know which takes more CPU cycles - to just run the declare or to evaluate if you need to run it…

So sorry for the blog, but maybe this will help someone…

Doing all this works fine. However, when you have a large number of pop-ups to open on a window, it takes quite a bit of time actually. With one or two, you don’t notice it. But if you have 15 or 20, it becomes much too long to wait. :frowning:

If i see it right, you build and use the same popupmenu again and again, why not build one popupmenu and place in every row a picture of the popupmenu. As soon as someone selects a cell with a picture reposition the popupmenu to that cell and use the selected option + the row of the selected cell. IMHO that should be almost instantaneous.

Yes, they are a control set. But each one is likely set to different list indexes. So it would be a lot of effort to re-paint it all as I would have to set the list index for each instance of the control and then paint that specific item, etc.

I am probably going to go back to what I had been doing as it appears that it worked good enough. I had set the text size of the listbox to 9 points. Then I set the height to 6. That works - You just don’t have very granular control of the listbox. But even setting the height manually, I’m still not getting the height that I want to really use with it that will properly fit where I’m trying to embed it (I have to make my row spacing larger than ideal).

It would be nice if Xojo just had Windows controls that worked properly.