From: Mike Williams on
"Mike Williams" <mikea(a)whiskyandCoke.com> wrote in message
news:e6oFp5l3IHA.5112(a)TK2MSFTNGP03.phx.gbl...

> All of the above of course relies on you being able to detect
> when a list of sub menus is rolling down, which is something
> I don't yet know how to do, but I think there must be a way
> of detecting it?

Further to my previous response, I've just been checking things out and it
looks as though with a bit of subclassing we can detect the WM_MENUSELECT
message and have our code run in response to that event. A little
investigation shows that the WM_MENUSELECT message is received whenever the
user selects or hovers over a dropped down menu item, but it is also
received whenever the user causes one of the main menu lists to drop down,
so we can run code in response to that event which performs the tasks
outlined in my previous response, which should give you exactly the effect
you are after in just a single block of code. As far as the user is
concerned, the Copy, Paste and other menu items under your Edit menu (for
example) will be either active or non active immediately they drop down, and
their state will depend on the state of the TextBox that was active and the
contents of the Windows clipboard at the time the menu list dropped down,
which I think is exactly what you are after.

Mike



From: Mike Williams on
"Mike Williams" <mikea(a)whiskyandCoke.com> wrote in message
news:e6oFp5l3IHA.5112(a)TK2MSFTNGP03.phx.gbl...

.. . . further to my recent responses in this thread, I've just been playing
about trying to come up with a workable solution and so far this is what I
have come up with, which seems to work fine. At the moment it is very "rough
and ready" and it can be tidied up and made much more general purpose in
lots of ways, but it does illustrate that the general principle is sound.
Start a new VB project using one Form and one bas code module. Place a
TextBox on the Form and make sure you name it "txtSubclass". Then drop
various other controls of different kinds onto the Form, including
PictureBoxes and various other things and at least a few more TextBoxes.
Make at least one of the controls a CommandButton and use the following for
its click event (this is just so you will be more easily able to test the
operation of the program):

Private Sub Command1_Click()
Clipboard.Clear
End Sub

Use the standard VB menu editor to create a menu called mnuEdit with two sub
menus called mnuCopy and mnuPaste. Then paste in the following two blocks of
code into the project. When you run the project and use the Edit menu you
should see that both the Copy and Paste menus are disabled unless the
control that currently has the focus is a TextBox. Also, when the currently
active control is a TextBox (any of the TextBoxes on your Form) you should
see that the Paste menu is enabled only if there is some text on the
clipboard and the Copy menu is enabled only is the currently active TextBox
has some text selected. The two blocks of code, one for the module and one
for the Form, are as shown below:

Mike

' *** START OF FORM CODE ***
Option Explicit

Private Sub Command1_Click()
Clipboard.Clear
End Sub

Private Sub Form_Load()
Me.Show
DoEvents
txtSubclass.Text = "1"
txtSubclass.Visible = False
Hook Me.hwnd
End Sub

Private Sub Form_Unload(Cancel As Integer)
Unhook Me.hwnd
End Sub

Private Sub mnuCopy_Click()
Clipboard.SetText Me.ActiveControl.SelText, vbCFText
End Sub

Private Sub mnuPaste_Click()
Me.ActiveControl.SelText = Clipboard.GetText(vbCFText)
End Sub

Private Sub txtSubclass_Change()
' This event fires each time the user causes
' a main menu list to drop down (and on other
' menu events)
Dim c1 As Control, s1 As String
Set c1 = Me.ActiveControl
If TypeOf c1 Is TextBox Then
If c1.SelLength > 0 Then
mnuCopy.Enabled = True
Else
mnuCopy.Enabled = False
End If
s1 = Clipboard.GetText(vbCFText)
If Len(s1) > 0 Then
mnuPaste.Enabled = True
Else
mnuPaste.Enabled = False
End If
Caption = Len(s1)
Else
' a textBox is not the current control
mnuCopy.Enabled = False
mnuPaste.Enabled = False
End If
End Sub
' *** END OF FORM CODE ***
'
' *** START OF MODULE CODE ***
Option Explicit

Private Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" _
(ByVal hwnd As Long, _
ByVal nindex As Long, _
ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, _
ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Public DefWindowProc As Long
Private Const GWL_WNDPROC As Long = (-4)
Private Const WM_DESTROY = &H2
Private Const WM_MENUSELECT = &H11F

Public Sub Unhook(hwnd As Long)
If DefWindowProc Then
Call SetWindowLong(hwnd, GWL_WNDPROC, DefWindowProc)
DefWindowProc = 0
End If
End Sub

Public Sub Hook(hwnd As Long)
DefWindowProc = SetWindowLong(hwnd, GWL_WNDPROC, _
AddressOf WindowProc)
End Sub

Function WindowProc(ByVal hwnd As Long, _
ByVal uMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Select Case uMsg
Case WM_DESTROY:
If DefWindowProc <> 0 Then
Call Unhook(hwnd)
End If
Case WM_MENUSELECT
Form1.txtSubclass.Text = _
-(Val(Form1.txtSubclass.Text))
Case Else
WindowProc = CallWindowProc _
(DefWindowProc, hwnd, uMsg, wParam, lParam)
End Select
End Function
' *** END OF MODULE CODE ***



From: Mike Williams on
"Mike Williams" <mikea(a)whiskyandCoke.com> wrote in message
news:e6oFp5l3IHA.5112(a)TK2MSFTNGP03.phx.gbl...

.. . . one final thing, I inadvertently left the code "Caption = Len(s1)" in
the txtSubClass_Change event. I was using that purely for test purposes and
it serves no actual purpose in the working project, so you can get rid of
it.

Mike



From: Bob Butler on
"Mike Williams" <mikea(a)whiskyandCoke.com> wrote in message
news:e4gJnbn3IHA.4284(a)TK2MSFTNGP04.phx.gbl...
> "Mike Williams" <mikea(a)whiskyandCoke.com> wrote in message
> news:e6oFp5l3IHA.5112(a)TK2MSFTNGP03.phx.gbl...
>
> . . . further to my recent responses in this thread, I've just been
> playing about trying to come up with a workable solution and so far this
> is what I have come up with, which seems to work fine.

No need to subclass; you can do the enable/disable of the subitems in the
Click event of the top-level menu. That fires before the menu displays.

Private Sub mnuEdit_Click()
Dim c1 As Control
Dim s1 As String
Set c1 = Me.ActiveControl
If TypeOf c1 Is TextBox Then
mnuCopy.Enabled = (c1.SelLength > 0)
s1 = Clipboard.GetText(vbCFText)
mnuPaste.Enabled = (Len(s1) > 0)
Else
mnuCopy.Enabled = False
mnuPaste.Enabled = False
End If
End Sub

From: Mike Williams on
"Bob Butler" <noway(a)nospam.ever> wrote in message
news:Of9fGSq3IHA.2580(a)TK2MSFTNGP06.phx.gbl...

> No need to subclass; you can do the enable/disable
> of the subitems in the Click event of the top-level menu.
> That fires before the menu displays.

Well, well, well! We live and learn :-) I created a Form and used the menu
editor to create various menus with sub menus, including a menu called Edit
with sub menus Copy and Paste. I then (in the IDE) clicked (and sometimes
double clicked) the various menu items so that VB brought up the code window
when I did so and created the "event wrapper" for me to place code in. When
I clicked (or double clicked) the main menu item (in this case, the Edit
menu) in the IDE VB did not react at all and so I just assumed, without any
further checking, that there were no click events for top level menus and I
therefore decided that I would need to subclass in order to get at that
event, which I did! I should have checked further of course and I would
probably have found the top level menu Click event, but I did not :-(
Thanks for putting me right on that one, because it simplifies the code
quite a lot, removing the need for subclassing as it does.

Mind you, having said that, the basic idea of course remains the same and it
is still very sound, except you just remove the code I previously had in the
txtSubClass_Change event and place it instead in the mnuEdit_Click event. So
we don't need the module and we can simplify the Form code to something like
the following:

Mike

Option Explicit
Private Sub mnuCopy_Click()
Clipboard.SetText Me.ActiveControl.SelText, vbCFText
End Sub

Private Sub mnuPaste_Click()
Me.ActiveControl.SelText = Clipboard.GetText(vbCFText)
End Sub

Private Sub mnuEdit_Click()
Dim s1 As String
If TypeOf Me.ActiveControl Is TextBox Then
If Me.ActiveControl.SelLength > 0 Then
mnuCopy.Enabled = True
Else
mnuCopy.Enabled = False
End If
s1 = Clipboard.GetText(vbCFText)
If Len(s1) > 0 Then
mnuPaste.Enabled = True
Else
mnuPaste.Enabled = False
End If
Else
' a textBox is not the current control, and we are
' dealing only with TextBoxes in this simple example
mnuCopy.Enabled = False
mnuPaste.Enabled = False
End If
End Sub

First  |  Prev  |  Next  |  Last
Pages: 1 2 3
Prev: Read Cannot
Next: saving all data on form