tags:

views:

839

answers:

3

I have a VB6 app. There is a main form. It houses a user control. This user control has a button control. When I click the button, I want a menu to pop up so that the top left of the menu is right underneath the bottom left of the button.

if I do:

frm.PopupMenu mnuBlah

the menu comes up where the mouse is.

if I try to provide coordinates

frm.PopupMenu mnuBlah, btn.Left, btn.Top + btn.Height

the math comes out totally wrong and the menu is displayed way off target.

I am not quite sure what type of coordinates the PopupMenu call requires and how to calculate the position underneath the button.

+1  A: 

You need to include the height and left values for the parent container (this is usually the form, but could also be a frame, or some other container).

I think you're looking for something like this:

btn.Parent.PopupMenu mnuBlah, vbPopupMenuLeftAlign , btn.Left, btn.Top + btn.Height
Brian
This doesn't compile, and even if you fix it so that it does compile, it doesn't work.
raven
@raven As I mentioned in my answer, I didn't have a compiler handy to check it with. This modified version should work.
Brian
+1  A: 

You need to pass the vbPopupMenuLeftAlign flag to the PopupMenu method. Note, this contradicts the documentation on the PopupMenu method (could Microsoft actually have made a mistake?), but it works.

frm.PopupMenu mnuBlah, vbPopupMenuLeftAlign, btn.Left, btn.Top + btn.Height
raven
+1  A: 

PopupMenu wants X and Y coordinates in the ScaleMode of the form on which the menu is being popped up. In this case, that probably means the user control.

But it really depends on where you're handling the MouseDown event. (You don't get coordinates with the Click event.) If your event handler is in the user control itself, then you shouldn't have any problem using the supplied coordinates. However, the code you posted is missing the Flags parameter (should be vbPopupMenuLeftAlign), which could explain why your coordinate math isn't working. Plus, you have to define the menu as a property of the user control itself.

On the other hand, if you raise the MouseDown event out of the user control, and handle it in the containing form, the popup menu has to be a property of the containing form. In this case, you can ignore the X and Y parameters, but you have to do coordinate calculations yourself. The left edge of the button, relative to the main form, will be the sum of user control's left edge and the offset of the button within the control. Similar math will work to calculate the bottom edge of the button. In other words:

Private Sub UserControl1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    PopupMenu mnuPopup, vbPopupMenuLeftAlign, _
        UserControl1.Left + UserControl1.Button.Left, _
        UserControl1.Top + UserControl1.Button.Top + UserControl1.Button.Height
End Sub

Note that this will require that you also expose the button (Button) as a property of the user control so that you can access its Left, Top, and Height properties. That's easy enough:

Public Property Get Button() As CommandButton
    Set Button = Command1
End Property

Raising the event is simple enough as well; just put

Public Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

at the top of the user control, then use this:

RaiseEvent MouseDown(Button, Shift, X, Y)

in the MouseDown event of the button in the user control.

Finally, to wire up the event handler in the main form, use the two dropdowns at the top of the code editing window. Select the user control from the one on the left, then select the MouseDown event from the one on the right. This will insert the event handler, which you fill in with the code above.

As far as which way is better, handling the menu inside the user control itself, and raising meaningful events when one is selected keeps things separated. The user control handles the UI work, leaving the main application to handle whatever needs to be done in response to the user's selection, without worrying about placement of the menu.

So you wouldn't actually be raising the MouseDown event; rather you'd raise events like OptionOneSelected, OptionTwoSelected, or OptionThreeSelected. (More meaningful names would be much better, of course.)

Anyway, I hope this isn't too late to be helpful...

JeffK