Create Formula in a TextBox using Excel VBA - vba

Does anyone know if it's possible to have a textbox in a userform in Excel 2010 work like the formula editor?
In other words when the userform is up and the textbox is the focused control allow me to type say
=AND(
Then click cell D2 and have the text box then be
=AND($D$2
Then type a =
=AND($D$2=
Then click cell E2
=AND($D$2=$E$2
Then type )
=AND($D$2=$E$2)
I've played around with the RefEdit control but it just overwrites any custom text as soon as a range is selected on the sheet, I basically need it to append to the text box when I click on a range.

Put this code in the ThisWorkbook module:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
On Error GoTo EndOfSub
If UserForm1.ActiveControl.Name = "TextBox1" Then
UserForm1.TextBox1.Value = UserForm1.TextBox1.Value & Target.Address
End If
EndOfSub:
End Sub
This way when your userform is loaded (UserForm1 here) and your textbox is active (TextBox1 here), the address of the selection is appended to it. If you need to add the worksheet's name too, change the 3rd line above:
UserForm1.TextBox1.Value = UserForm1.TextBox1.Value & sh.Name & "!" & Target.Address
If you need to use it on only one sheet, put the code to that Sheet's code instead of the ThisWorkbook's code.
It is not as sophisticated as the formula editor, as it always appends the selection. (Changing the just inserted reference is doable too if you need it, just takes a bit more checking.)
Do note that putting code into the ThisWorkbook's SheetChange method takes its toll: you will not be able to use Undo in this workbook.
A bit more elegant way to check if a Userform is loaded can be found (here)[http://www.ozgrid.com/forum/showthread.php?t=152892]. You can use this instead of the On Error Goto part.

Yes, this is possible in a TextBox, but the problem you have is that you'll need to show the UserForm modelessly because you need to select cells in a worksheet while the Userform is on show. If you want to do exactly as you describe, ie the very next keystroke is '=', then you will need to re-activate the UserForm otherwise you'll simply add an '=' into your selected cell.
I believe the Show command won't re-activate a modeless UserForm that is already on show and I'm not aware of an Activate command for a UserForm. Others may well know of one, but I'd use a couple of APIs to do the job. So the code in your Userform could be as follows (you may need to adjust the API declarations if you have Win64 and/or VB7 https://msdn.microsoft.com/en-us/library/office/ee691831(v=office.14).aspx):
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SetFocusAPI Lib "user32" Alias "SetForegroundWindow" _
(ByVal hwnd As Long) As Long
Private mHwnd As Long
Private mTextBoxHasFocus As Boolean
Public Property Get TextBoxHasFocus()
TextBoxHasFocus = mTextBoxHasFocus
End Property
Public Sub AppendText(appendedText As String)
'Add the text to textbox
TextBox1.Text = TextBox1.Text & appendedText
'Activate this userform window
SetFocusAPI mHwnd
'API doesn't trigger UserForm_Activate event so call it
Me.ActivateByCode
End Sub
Private Sub TextBox1_Enter()
mTextBoxHasFocus = True
End Sub
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
mTextBoxHasFocus = False
End Sub
Public Sub ActivateByCode()
'Set focus on any another control then back to textbox
btnSave.SetFocus
'Set cursor at end of text
TextBox1.SelStart = Len(TextBox1.Text)
TextBox1.SelLength = 0
TextBox1.SetFocus
End Sub
Private Sub UserForm_Initialize()
'Acquire the handle for this window
mHwnd = FindWindow("ThunderDFrame", Me.Caption)
End Sub
You'd then call the AppendText routine from a WorkSheet_Change event or, as in this case, a Workbook_SheetSelectionChange event (which caters for selections of a cell in any WorkSheet):
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
If UserForm1.TextBoxHasFocus Then
UserForm1.AppendText Target.Address
'Uncomment the line below if you want sheet name as well as address
'UserForm1.AppendText Sh.Name & "!" & Target.Address
End If
End Sub
And remember to show your UserForm modelessly:
UserForm1.Show False
If you want to cursor to be in the TextBox when the UserForm opens, then add this line too:
UserForm1.ActivateByCode

(Posted on behalf of the question author).
Checking for the selection changed was what I was missing. I was SO focused on trying to make the UserForm behave I completely spaced on ALL the other events Excel has to work with!
In the end I went with a check in the SelectionChanged sub to see if a simpler UserForm (minimal size with textbox and restore button) was visible and the textbox was active.
I added a little more logic to handle inserting into the cursor location of the textbox as well as straight appending. Might add some support for arrow keys in the future but I have the original functionality I set out to have.
Microsoft, if you're listening, would it have been possible to give us a RefEdit control that looks and behaves like the one built into Excel? Just a thought.

Related

Display MsgBox on cell click - even when the cell is already selected

I want a MsgBox to appear when cell A1 is clicked. I want it to appear even if A1 is already active when it is clicked:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.EnableEvents = False
If Target.Row = 1 And Target.Column = 1 Then
MsgBox ("message")
End If
Application.EnableEvents = True
End Sub
This code works only if cell A1 is not already selected when I click on it. Currently the message box does not appear in this case.
Is there a way to fix this?
Your code is using Worksheet_SelectionChange which only fires when a different cell is selected (hence the name Selection Change).
Alternatively, if it's okay if your [unknown] goal is attained using double click or right click then there are other worksheet events that will help:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
MsgBox Target.Address & " was double clicked"
Cancel = True 'don't edit cell
End Sub
 
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
MsgBox Target.Address & " was right clicked"
Cancel = True 'don't open context menu
End Sub
Note that the code for these event procedures need to be placed in the worksheet module.
Edit: More creative ways
Click Event via PeekMessage API
If it must be a single click, there are "sneakier" ways to accomplish this, such as adding a Click event. This is not a built-in feature of Excel VBA, and thus, this method is not generally recommended.
It involves checking for the WM_MOUSEMOVE message when a cell is mouse-clicked, which is accomplished by calling the PeekMessage API inside the Worksheet_SelectionChange event. More info and examples here.
Transparent command button
There could also be a round-about way to accomplish this using an ActiveX Command Button with no caption, with the BackStyle property set to frmBackStyleTransparent.
Neither of these methods have been tested and you might need to do some fancy coding to get them to work. Depending on how often the same cell will be clicked that is already selected (and therefore how that functionality is to you), you may want to simply re-think the layout of your worksheet.
For example, you could add an extra column and have the user click the cell next to the one with the value to activate your message box.
More Information:
MSDN : Worksheet.BeforeDoubleClick Event (Excel)
MSDN : Worksheet.BeforeRightClick Event (Excel)
Chip Pearson : Events in Excel VBA

How to dynamically edit a excel vba form label and tab label?

I have an excel vba form which has some tabs(pages).What I need is, if I double click on label, it should be editable. same is the case for the tabs.
I tried to add some things into the double click function, but not showing any change.
Labels are not editable by the end user
you may adopt this workaround
'change "Label1" occurrences to your actual label name
Private Sub Label1_DblClick()
Me.Label1.Caption = Application.InputBox("enter label text", "label editing", "")
End Sub
You can have a TextBox and disable it. The side effect is you will have textbox edit cursor over the label.
Have two subroutines, one called Labelize and another Textboxize. The former locks the textbox, makes it tranparent, and sets the 3D effect to flat. The latter unlocks it, makes it opaque, and sets the 3D to sunken (the default).
' Makes a textbox look like a label
Private Sub Labelize(txtbox As MSForms.TextBox)
txtbox.Locked = True
txtbox.BackStyle = fmBackStyleTransparent
txtbox.SpecialEffect = fmSpecialEffectFlat
End Sub
' Makes a textbox look like a textbox
Private Sub Textboxize(txtbox As MSForms.TextBox)
txtbox.Locked = False
txtbox.BackStyle = fmBackStyleOpaque
txtbox.SpecialEffect = fmSpecialEffectSunken
End Sub
In the form initialize event set call the Labelize method passing in your textboxes.
Private Sub UserForm_Initialize()
Labelize Me.txtExample
End Sub
In the double-click event per textbox, call the Textboxize method passing in your textbox again.
Private Sub txtExample_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Textboxize Me.txtExample
End Sub
Then in each KeyDown event, check if the key pressed was enter then call the Labelize method.
Private Sub txtExample_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then Labelize Me.txtExample
End Sub

Trapping right-click in worksheet textbox

I'd like to be able to trap the right-click event when a user right-clicks in a worksheet textbox not ActiveX.
I know it can be done easily for userform textboxes, that's not what I'm after.
In the worksheet event Worksheet_BeforeRightClick I have the following:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
mRightClick.RightClickOnMoMList rngTarget:=Target, boolCancel:=Cancel
End Sub
However it doesn't even enter it when I right click on the textbox (but a cell of the same worksheet does work). I suspect that it is due to the Target argument being a Range.
Is there a way to make that event trap right clicks on shapes like textboxes as well?
I've just done this:
- opened Excel and entered Design Mode
- added a text box to a worksheet
- double-clicked the text box, which took me to the Change event for that control
- I selected the MouseUp event
What you're after is Button = 2 for the right button (left button is 1).
So...
Private Sub TextBox1_MouseUp(ByVal Button As Integer, _
ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)
If Button = 1 Then
MsgBox "Left-click"
ElseIf Button = 2 Then
MsgBox "Right-click"
End If
End Sub

Excel VBA - open activex control DTPicker1 within a sub

i have a date picker activex control in my worksheet. after a subroutine i would like the datepicker to open instead of having to rely on the user to navigate and click the box to open it
when i click 'view code' on the control i see it is names like this
Private Sub DTPicker1_CallbackKeyDown(ByVal KeyCode As Integer, ByVal Shift As Integer, ByVal CallbackField As String, CallbackDate As Date)
End Sub
what would be the appropriate way to call/simulate this keydown event in another sub
example:
Sub ProcessResults
'do existing code
DTPicker1.KeyDown 'doesn't work - 424 object required
DTPicker1.Open 'doesn't work - 424 object required
DTPicker1.Activate 'doesn't work - 424 object required
DTPicker1_CallbackKeyDown 'doesn't work - sub or function not defined
End Sub
DTPicker1 itself works fine within the worksheet - like i said i just want to save a few clicks and have it open automatically at the end of a different sub
Focus DTPicker and do
SendKeys ("{F4}")

Set focus back to the application window after showing userform

When showing a userform (running its Show method) it not only shows up on the screen but also takes the focus (the destination of e.g. keystrokes).
Say, the userform is a custom made toolbar. Its Show fires in Workbook_Open() but the form itself is used relatively rarely so we want the focus to go back to the main application window right after its appearance.
Unfortunately, it seems SetFocus method is not valid for application objects.
So how is this done?
I suppose the solution for my example comes after
Private Sub Workbook_Open()
[...]
UserForm1.Show
i use this one :
AppActivate Application.caption
this resets the focus from a userform to your Excel Sheet.
For me
AppActivate ThisWorkbook.Application
right after the Show statement seems to work fine.
In other cases
AppActivate "Microsoft Excel"
may also be ok.
This is a bit tricky, but this is what can do.
In the subroutine “Private Sub UserForm_Initialize()”, add this as the last line:
Private Sub UserForm_Initialize()
. . . . . . . . . .
Application.OnTime Now(), "MoveFocusToWorksheet"
End Sub
In any of the general code modules (add one if you have none), declare an API function:
Public Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
In any of the general code modules (could be the one with the API declaration, of course), add this subroutine:
Public Sub MoveFocusToWorksheet()
Dim Dummy As Long
ThisWorkbook.Worksheets("Sheet1").Activate
' "Sheet1" here is the tab name of the sheet you want to move focus to. _
Or simply use then: With shtABC.Activate _
where "shtABC" being the worksheet's CodeName, _
same as ThisWorkbook.Worksheets("Sheet1").CodeName, _
same as the sheets module name showing in the Project Explorer panel.
Dummy = SetForegroundWindow(Application.hwnd)
End Sub
Both AppActivate Application.Caption and (the better) AppActivate ActiveWindow.Caption mentioned in the other answers do their job in focusing back on the application window itself ... but they do NOT focus on the actual cell/range where one typically wants the focus to be. For that, use:
ActiveCell.Activate
which has the benefit of not requiring an additional click on the cell area of the sheet where you want to return focus - an additional click that can potentially change the previous selection.
I create an object for the application e.g. Outlook, then change the WindowSate to Maximised (OlMaximized), then when I want to remove focus I minimise (olMinimized)
Set OutlookObj = GetObject(, "Outlook.Application")
OutlookObj.ActiveExplorer.WindowState = olMinimized
OutlookObj.ActiveExplorer.WindowState = olMaximized
Or you change the state from inside the application, you can also change its location and size etc for more info see: https://msdn.microsoft.com/en-us/library/office/ff838577.aspx
Application.WindowState = xlMaximized
An other form is:
AppActivate ThisWorkbook.Name
I use
AppActivate ActiveWindow.Caption
because
AppActivate Application.Caption
can focus the wrong window if multiple windows are opened for the same workbook.
As a footnote to this excellent discussion, in some circumstances you may avoid the focus problem by skipping the call to .Show, so the focus never moves in the first place. For example with Word, if you are updating a modeless form or dialog box, just update the required area and omit the call to .Show, e.g.:
Sub ShowProblems(ByVal ProbLoc)
EditBox2.TextBox.Text = "Here is the problem location: " & ProbLoc
' not needed: EditBox2.Show vbModeless
End Sub
Private Sub UserForm_Activate()
RefRangeIn.SetFocus
End Sub
it work for me, in excel 2013 VBA
Add a dummy form and add codes as below:
Private Sub SomeButton_Click()
frm_Dummy.Show vbModeless
Unload frm_Dummy
End Sub
OR
Sub SomeSub()
frm_Some.Show vbModeless
frm_Dummy.Show vbModeless
Unload frm_Dummy
End Sub
I created a floating menu with a user form and use this code to make my cursor leave the user form and jump/focus back to my worksheet. It works at the end of each command button code and with the initiation code of the user form as well.
AppActivate ThisWorkbook.Application
Just place the above line of code before the "End Sub" line of any command button code and the initial show userform code.