Hi,
I want to display a popup menu over a textbox. I put the relevant code under mouse down event with a check for right button.
What i get is, that when the user right click on the mouse, it get the default popup menu of windows (cut, copy, paste ...) and only when he right click again, he gets mine.
I guess, i can somhow disable this default popup, but dont know how.
Option Explicit
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
Text1.Enabled = False
Call Text1_MouseUp(Button, Shift, X, Y)
End If
End Sub
Private Sub Text1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
'
If Button = vbRightButton Then
Text1.Enabled = True
PopupMenu mnumypop
End If
End Sub
...at present time, using mainly Net 4.0, Vs 2010
Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
Ok Cimperiali
There is one major disadvantage of this procedure:
It doesn't work if the user requests the context menu (popup menu) using the keyboard (He can do so by pressing the popup menu button in new keyboards or by pressing SHIFT + F10)
Another minor disadvantage is:
The regular popup menu shows up when the user releases the right button not when he make the mouse down event..
So this is my way to do it by subclassing the text box control:
Form's code :
Code:
'using subclassing
Private Sub Form_Load()
'here:define a new window procedure for the text box
prevProc = SetWindowLong(Text2.hwnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub
Module's code :
Code:
Option Explicit
'Declaration
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias _
"CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
ByVal hwnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Public prevProc As Long
Public Const GWL_WNDPROC = (-4)
Const WM_CONTEXTMENU = &H7B
'this function intercepts all messages (events) sent to the textbox
'it forwards all messages to the default window procedure
'except the WM_CONTEXTMENU message
Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If uMsg = WM_CONTEXTMENU Then
frm.PopupMenu frm.mnu
Else
WindowProc = CallWindowProc(prevProc, hwnd, uMsg, wParam, lParam)
End If
End Function
This issue seems to come up all the time. I really wanted to deal with this once and for all, but without any hooks. Well, here it is!! This demonstrates how to do multiple tricks with a textbox, including:
1) Have a custom popup menu
2) Have no menu whatsoever
3) Prevent pasting, even while allowing the default menu
4) Prevent pasting via the keyboard
5) Prevent Alt codes
You will see that the trick was to use the SetCapture API call.
It accounts for Shift+F10 and the context menu key as well. It seems the context menu key bypasses the normal key events of the textbox, so it can't be set to zero like the other keys, even though it fires the KeyDown event. So, in the case of this when wanting no menu at all, focus must be diverted away from the textbox. The two solutions I found are a messagebox, or setting the focus to something else on the form. I suppose if the user is actually going to try this key, a message telling them they can't is not so bad (until today I never tried this key before). I did find one issue with the context menu key however. If you dismiss the custom menu or messagebox very very quickly, the default menu shows up. I think this is because the window message is still in the buffer, because I found that setting focus to another textbox will cause the menu for that one to show instead. If anyone finds a fix for this key, please share it
<UPDATE>
After all this time, a new member has found that the default menu will appear if the user double right-clicks! The fix for that was simple, and I posted an update on that thread: http://www.codeguru.com/forum/showth...51#post1227651
Last edited by WizBang; September 7th, 2005 at 08:33 AM.
Please remember to rate the posts and threads that you find useful.
How can something be both new and improved at the same time?
Originally posted by WizBang
I really wanted to deal with this once and for all, but without any hooks.
the way I used is (window subclassing) .. completely different from windows hooks..
using the same way you can disallow copy,paste, some key presses , etc...
simply this is the right way to make it
the way I used is (window subclassing) .. completely different from windows hooks..
Well, although I was not really referring to your example directly, subclassing, as well as hooks, can be rather problematic. As for being completely different, I'd guess I'm not the only one who might point out similarities. In any case, multiple controls handled in this way multiply the complexity of a project, not to mention the debugging problems that are so often encountered. Anyone who has used either of these methods will have likely crashed the IDE a number of times. Even without such techniques, vb is far from crash-proof, but that's only one issue.
simply this is the right way to make it
I like to say there is no single "right" way to do something. There are always alternatives, and it is up to the developer to choose the means that fill the requirements to the best of his/her ability. Whenever I find what seems like a better way, I find myself going through code which I thought was finished, and sometimes I end up putting things back the way they were. This is one reason for program updates, and new versions. Sometimes simple is better, and sometimes not. Perhaps the answer is: "it all depends".
Please remember to rate the posts and threads that you find useful.
How can something be both new and improved at the same time?
I like to say there is no single "right" way to do something.
Keeping this in mind, try this code *just* to eliminate the default popup.
Private Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private oMenu As Menu
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
Set oMenu = mnuContext
SetCapture Me.hWnd
End If
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
PopupMenu oMenu, vbPopupMenuLeftAlign Or vbPopupMenuRightButton
ReleaseCapture
End If
End Sub
In this method, the mouse_down event sets a generic menu object to the popup menu to display for the context, and triggers the capture. The mouse_up event (at the form level) then displays the context menu and, when complete, the ReleaseCapture is performed.
rambotech
Nifty. However, what to do about right-clicking on the form? If you do this before right-clicking on the textbox, the object isn't set, thus raising an error. Setting a flag can eliminate that problem. Why not use the menu directly instead of setting an object? There's still the Shift+F10 issue as well. Maybe I'll look into it later when I have more time to fully test.
Last edited by WizBang; June 15th, 2004 at 03:18 AM.
Please remember to rate the posts and threads that you find useful.
How can something be both new and improved at the same time?
Originally posted by WizBang rambotech
Nifty. However, what to do about right-clicking on the form? If you do this before right-clicking on the textbox, the object isn't set, thus raising an error. Setting a flag can eliminate that problem. Why not use the menu directly instead of setting an object? There's still the Shift+F10 issue as well. Maybe I'll look into it later when I have more time to fully test.
You answered the first part very well: I would also use a boolean, or set the menu object to nothing after the release. The test for popping up a menu would be whether the menu object was other than nothing. This was just an example of a basic technique to override that default context menu.
The reason I didn't use the menu directly is that this example accomodates multiple objects. The menu object is simply set to the desired context menu at the MouseDown event for the particular user control receiving the right-click event. By using the object, the MouseUp event at the form-level will always show the proper context menu for the control.
I'm not familiar with the Shift+F10 issue. Is there a thread or link that discusses it?
Maybe this code will cover more cases. One case which I will work on is distinguishing a drap-drop operation.
Code:
Private Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private oMenu As Menu
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
Set oMenu = mnuContextText1
SetCapture Me.hWnd
End If
End Sub
Private Sub Text2_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
Set oMenu = mnuContextText2
SetCapture Me.hWnd
End If
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton and TypeName(oMenu) <> "Nothing" Then
PopupMenu oMenu, vbPopupMenuLeftAlign Or vbPopupMenuRightButton
ReleaseCapture
Set oMenu=Nothing
End If
End Sub
Last edited by Cimperiali; June 15th, 2004 at 09:34 AM.
That is basically what I was thinking, although I would make use of the Is operator to check the object.
Code:
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton And Not oMenu Is Nothing Then
PopupMenu oMenu, vbPopupMenuLeftAlign Or vbPopupMenuRightButton
ReleaseCapture
Set oMenu = Nothing
End If
End Sub
As for the Shift+F10 issue, just try that key combination while the textbox has focus, and you'll see the default menu pop up.
Please remember to rate the posts and threads that you find useful.
How can something be both new and improved at the same time?
Hello friends, I am a new guy, I saw all the solutions here, but, i wanted a easy way to do it you know easy and tricky.
well i found it myself , here it goes
Dim SCM As Menu
Private Sub Form_Load()
Set SCM = mnuShortCut
End Sub
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = 2 Then
Text1.Enabled = False
Text1.Enabled = True
PopupMenu SCM
End If
End Sub
NOTE : you can do it only in mouse down event not the mouse up .
Hello friends, I am a new guy, I saw all the solutions here, but, i wanted a easy way to do it you know easy and tricky.
Cimperiali already sent a similar solution
the problem with it is when the user uses SHIFT+F10 or the context menu key
anyway..Good try and welcome to CG
Cimperiali already sent a similar solution
the problem with it is when the user uses SHIFT+F10 or the context menu key
anyway..Good try and welcome to CG
Thanks for viewing my reply/post and thanks for letting me know the shift+F10 problem, I would have left that bug in my programme, any way I think I found a solution for that too. Here it goes
First you must handle the built in key for right click (I don’t know what it is called) it is a special key something like the built in windows logo key …. Ok its ASCII value is 93
Second you must handle only F10 key don’t consider the Shift key , the F10 key ASCII is 121
Then there was …..
Dim SCM As Menu
Private Sub Form_Load()
Set SCM = mnuShortCut
End Sub
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = 121 Or KeyCode = 93 Then
Text1.Enabled = False
Text1.Enabled = True
Text1.SetFocus ' other wise it will go to the next control
PopupMenu SCM
End If
End Sub
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
If Button = 2 Then
Text1.Enabled = False
Text1.Enabled = True
Text1.SetFocus ' same here also
PopupMenu SCM
End If
End Sub
Note : It is left to take care of the menu popup position in case of key down.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.