How to position a Popup menu right underneath a button in VB6 - vb6

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.

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...

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

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

Related

wxHaskell Button State

I'm writing an application using wxHaskell and I want to be able to detect the state of a button (whether or not it is pressed at any given time). I'm having a bit of trouble figuring out how to do this, however. First I thought that there might be a "button is pressed" attribute that I could use, but there didn't seem to be. Then I had the idea of maintaining an IORef which I update on button-up and button-down events. However, that would require that the Button object actually have button-up and button-down events, which is does not appear to. It is an instance of Commanding, but I assume that the command event is fired on button-up only, which isn't enough for that idea. Does anyone have any other suggestions?
Workaround
You can implement this yourself by detecting the low-level actions that trigger those events (eg. mouse button down, space bar down).
In WX you can use the following function and constructor:
mouse :: Reactive w => Event w (EventMouse -> IO ())
data EventMouse = ... | MouseLeftDown !Point !Modifiers
And, as you suggest, you could keep the state yourself in an IORef. My suspicion is that left button here means main button (right for left-handed users).
UI design principles
The second question, which you haven't asked by I'll answer, is whether this is good UI design.
The behaviour of a button (assuming interaction using a mouse) is that click events are reported when the user releases the mouse button in the button area after pressing the mouse button down in the same area. If the user moves away and releases, or presses 'Escape', there is no click.
Taking any action on a button being pressed (not clicked) would feel unnatural for users.
In practice, the only acceptable way to use this would be, imho, to take an action whose effects can only be witnessed after releasing and which is immediately undone if the click is cancelled (ie. mouse button released outside button area).
EDIT: Please, also, take into account that users with accessibility requirements may have OS settings enabled that affect how and when button clicks are reported (but not down/up mouse events).
There is no way to know if a wxButton is pressed or not because it is an abstraction of a push button which intentionally hides this implementation detail. If you need to know the button state, use a wxToggleButton instead.

Do I have the right idea with using SetCapture() for a windowless checkbox?

My Table control uses windowless checkboxes (because there can be an arbitrary number of checkboxes here). Right now, I use TrackMouseEvent(TME_LEAVE) and manually checking if the mouse is in the checkbox rect during a WM_LBUTTONUP. I have TODOs marked in my code for the edge cases that this causes, such as a missing WM_LBUTTONUP when the mouse has left the client area.
Now I notice today's The Old New Thing says buttons use mouse captures. This got me thinking, and after looking into it, mouse captures would fit what I need more appropriately; if my assumptions are correct it would handle the various edge cases I mentioned above and be more correct in general.
In particular, the assumptions I make are: I should abandon any capture-related operations on a WM_CAPTURECHANGED even if every other condition is met. I will get a WM_CAPTURECHANGED after a ReleaseCapture(). After a SetCapture(), I will always end with either a WM_LBUTTONUP or a WM_CAPTURECHANGED, whichever comes first.
I've read both MSDN and a few articles I've found by Googling "setcapture correct use"; I just want to make sure I've got the right idea and will be implementing this correctly. Do I?
on WM_LBUTTONDOWN
if the button is in a checkbox
SetCapture()
mark that we're in checkbox clicking mode
on WM_MOUSEMOVE
if we are in checkbox clicking mode
draw the checkbox in the pressed state
on WM_LBUTTONUP
if we are in checkbox clicking mode
leave checkbox clicking mode
THEN call ReleaseCapture(), so we can ignore its WM_CAPTURECHANGED
if the mouse was released in the same checkbox
toggle it
on WM_CAPTURECHANGED
if we are in checkbox clicking mode
abandon checkbox clicking mode and leave the checkbox untoggled, even if the mouse is hovering over the checkbox
Do I have the right idea here? And in particular, is my order of operations for WM_LBUTTONDOWN correct? Thanks.
What you have said is basically right, although a real checkbox tracks WM_MOUSEMOVE while in "clicking mode" and displays the checkbox in its original state if the mouse moves off of it. So to emulate that you should have:
on WM_MOUSEMOVE
if we are in checkbox clicking mode
if mouse is over the checkbox
draw the checkbox in the pressed (toggled) state
else
draw the checkbox in the original state

VB6 + how to switch between windows/frame in form by buttons

I am very new beginner with VB6 and I hope I explain the things right
I want to create form with 2 buttons (the buttons are located on the top form position )
So each button will switch to other form/window/frame
For example
The first button will show window 1 (there I can set only parameters)
The second button will show window 2 (there I can set only IP address)
Please advice if we can do that by VB6 ?
And if yes how to do that ( step by step )
Remark - Similar example but with multiple windows in the same form is the system properties ( right click on my computer and properties ) , the we can see each button will view different window
Create a form with 2 buttons, Command1 and Command2.
On this form, create 2 frames, Frame1 and Frame2. hide Frame2 and make sure to line up both framesso that they are of the same size and located right on top of each other (Top, Left, Width and Height properties must be the same)
Now put this code in:
Private Sub Command1_Click()
Frame1.Visible = True
Frame2.Visible = False
End Sub
Private Sub Command2_Click()
Frame1.Visible = False
Frame2.Visible = True
End Sub
Now each the first button shows the first frame while hiding the 2nd. The second button hides the first frame and shows the seconds. I think this is the simplest way to implement your task.
PS: don't forget to name your objects properly, it's not a good idea to have default names like Command1 or Frame2 - should be more descriptive than that.
It sounds like you are asking about the tabbed dialog control. To use a tabbed dialog control in VB6:
Click Project -> Components
Scroll down to "Microsoft Tabbed Dialog Control 6.0" and select it.
Click the Apply button.
You should notice a new control in the component tool box. If you do not see the toolbox, click View -> ToolBox. This is the same area of the IDE where you first click to add a button to a form. The tabbed dialog control looks like the top tab of several file folders. When you hover your mouse over the control in the toolbox, you will see a tool tip text of "SSTab". Click this control and then draw a rectangle on your form.
By default, this will add a tabbed dialog control with 3 tabs, but you can change this in the properties window. You can now create any control on top of a tab of the tabbed dialog control and interact with the control exactly the same way you would if the control was placed on the form itself.
What you want is called an MDI Form. It's a form that contains other forms.
You can find a full tutorial on them here, but here's the gist of what you want to do:
Set the "MDIChild" property of all your subforms you want to use to True. Disable their minimize, maximize, and resize functions as well.
Create an MDIForm. Disable its AutoShowChildren property.
Add a toolbar to the MDIForm. Add buttons to the toolbar corresponding to the forms you'll be switching between.
Implement each button's click event, to create child form as expected (or switch to an existing one).

Removing focus from all objects in Visual Basic 6

Is there a method such that a user can click on the form itself, and in doing so remove focus from whatever object (textbox, combobox, etc) currently has it? Basically, can focus be uniformly removed from everything at once?
Setting the focus to the form itself does not work.
I thought about doing the old "hide a placeholder button behind another object" trick, but I'm really not a fan of that.
Thanks!
In VB6 a PictureBox can get focus, even if it does not contain any control.
In your case you can put a PictureBox with TabStop false, BorderStyle set to 0, TabIndex set to 0 behind every other control but not containing any focusable control and stretch it to ScaleWidth by ScaleHeight at run-time.
You have to put the labels and any windowless control in this background PictureBox too.
This way when the user clicks "on the form" the focus will "go away". With "no focus" Tab key will focus first control (the one with TabIndex set to 1).
When a form is active, something generally HAS to have focus. It sounds like you're just wanting to not "show" that a particular control has focus.
If that's the case, it's going to depend on the controls. Some have properties that control whether or not the specific control "indicates" its focus in some way.
But the built in Windows controls will always show their focus state unless you subclass them
Given this problem. I'd probably put a button on the form , then move it offscreen when the form loads. Make sure it's not a tab stop, but then when you want to hide focus, set focus specifically to the button, make sure the button is STILL in the tab order, even though it's not a tab stop, so the user can press tab while on the button and end up somewhere logical.
Don't have VB handy, but could you simply remove TabStop?
for x = 1 to me.Controls.count
me.Controls(x).TabStop = 0
next
I have a picturebox and a control on a form.
Private Sub cmdButton_Click
PictureBox.setFocus
Exit sub
End sub
The control doesn't change its appearance, nor does the picturebox.
Of course you'll need to add an If-Then clause if you want the control to respond normally sometimes.

GUI: should a button represent the current state or the state to be achieved through clicking the button?

GUI: should a button represent the current state or the state to be achieved through clicking the button?
I've seen both and it sometimes misleads the user. what do you think?
The label on the button should reflect what the button does, i.e. it should describe the change the button makes.
For example, if you have a call logging system a button should say "Close Call" and the user can click it to close the call. The button should not have the label "Call is Open" and the user clicks to change the call status as that's very counter-intuitive, since the button is effectively doing the opposite to what it says on it.
In my opinion the label - and so the function - of a button should rarely, if ever, change. A button is supposed to be a like a physical button and they usually only do a single thing. (There are a few exceptions like play-pause on a media player where it's OK for the button label/icon to change, but at least this is copying a button from a real physical device.)
To carry on the example from above, I would say usually you would want two buttons, "Open Call" and "Close Call" and disable whichever one is not appropriate. Ideally you'd have a field elsewhere displaying the status of the call.
In summary, buttons are for doing things not for passing on information to the user.
The button should represent the action to be executed, not the state.
Some buttons are actions and are not ambiguous, like "Save", "Print" or "Enable user".
When a button represents a state that can be toggled, like Enable and Disable something, I do one of the following:
Change the button text, and make it always point to the state that will be achieved; (i.e. make the button point to actions, not states);
- Keep the button's text the same, but use one of those sticky buttons that will stay pressed, representing that the current state is "on" or "off". I prefer the former approach, though.
It should represent the action taken when clicking the button. States should always be presented by other means.
But I know what you mean. My car radio has buttons with text that shows the current state. It is really confusing.
This depends on the function which will be triggerd by the button click.
if the click changes the state of an entity i would suggest that the button represents the state the entity will enter after clicking the button
if the click triggers some kind of functionality the button should represent the function.
The appearance of the button is also a clue to its state. It should follow the standards of the environment if any exist (example, beveled edge / shadow appears on mouse click in Windows).

Resources