Excel Userform Textbox Constant Set Focus - vba

First of all I would like to thank all of you guys. Maybe you did not notice but you help me to grasp VBA to some level from scratch. I am still in learning process so I may be missing something really simple, please be gentle :)
First of all I would like to give a small backgroud update about my issue. I have been writing a small program to scan incoming parts to my work to be able to keep inventory status. Latest look of the program is like below:
And numbers on the picture are my nightmares lately:
1. Scanned Part Number: This is the textbox where scanner inputs the value. After I receive the input I immidietly convert that data to a variable and clear the textbox value as below:
Private Sub PN_CurrentScan_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then
EnteredPN = Replace(PN_CurrentScan.Value, Chr(32), "", 1) '<---PN_CurrentScan is the name of text box
EnteredPN = Left(EnteredPN, 12)
PN_CurrentScan.Value = ""
After making some corrections on the scanned data I basically write it to a sheet in the workbook. Then I also have a pivot table in the same workbook which uses this scanned data as source and counts how many parts scanned from each part number.
2. Current Status: This ListBox contains all the part numbers scanned (Coming from the pivot table mentioned above) and waiting to be scanned (Coming from another worksheet). Then it refreshes it self every time a new part is scanned.
3. ListBox Scroll Bar: Since I have very long part number list it is not possible for me to fit everything on the screen that is why listbox creates this scroll bar.
Enough with the background I think :)
So if we come to my concern. Since my collages using cordless scanner to do this operation sometimes they don't have the chance to see the screen so they can not understand if the cursor is on the "Scanned Part Number Text Box" or not. That is why I need focus to be on that box no matter what happens (Of course we can not do anything if warehouse burns down, earth quake or tsunami hits the place but let do not think about those).
WHAT I HAVE TRIED:
First of all I disabled all the remaining objects from properties window
Then I diabled tab stops of all controls:
Dim contr As Control
For Each contr In ScannerInterface.Controls
On Error Resume Next
contr.TabStop = False
Next
ScannerInterface.PN_CurrentScan.TabStop = True
Added setfocus property to all button clicks:
Me.PN_CurrentScan.SetFocus
Added setfocus property to listbox click:
Private Sub CurrentStatus_List_Click()
Me.PN_CurrentScan.SetFocus
End Sub
Added set focus to enter and exit events of listbox however this did not work:
Private Sub CurrentStatus_List_Enter()
Me.PN_CurrentScan.SetFocus
End Sub
Private Sub CurrentStatus_List_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Me.PN_CurrentScan.SetFocus
End Sub
So, with all these counter measures I have managed to improve up to somepoint, only concern remaining is when I click on the scroll bar next to the listbox, text box lose focus and without clicking in the textbox I could not manage to set the focus again. I tried all events with listbox non of them worked. Is there any way to solve this problem or do I need to deal with this? Thanks in advance for your supports.
SOLUTION:
Thanks to #Rory we have managed to solve my problem. As he noticed and explained in the answer below, both my textbox and listbox were in frames. I have tried several setfocus options but I always gave the focus to the textbox. However, solution was to give the focus to the frame which was containing the target textbox:
Private Sub CurrentStatus_Frame_Enter() '<-- Enter event of the frame which contains listbox
Me.PN_CurrentScan.SetFocus '<-- Setfocus to target textbox
Me.Scanned_Frame.SetFocus '<-- Setfocus to frame which contains target textbox
End Sub

Having (eventually) noticed that both of your controls are inside container Frame controls, you can actually use the Enter event of the Frame that contains the listbox to set focus to the Frame that contains the textbox, rather than to the textbox itself.

Related

How to use an event as If statement condition

I want to write a code for my form that when user clicks on each of text boxes to enter the data, textbox background change to green.
Something like this - in form current event:
Dim c as control
For each c In me.controls
If c.OnClick then
C.backcolor= vbGreen
C.tag="clicked"
End If
If c.AfterUpdate and c.tag="clicked" then
C.backcolor= vbWhite
C.tag=""
Next c
How can I find out when an event is triggered?
You will use WithEvents for that. This is poorly documented, but an example can be found in my project (too much code to post here):
VBA.ModernTheme
Full documentation and further links are in my article on the project:
Create Windows Phone Colour Palette and Selector using WithEvents
You can create two functions in your form code as follows:
Private Function SetBackColor()
Me.ActiveControl.BackColor = vbGreen
End Function
Private Function ResetBackColor()
Me.ActiveControl.BackColor = vbWhite
End Function
Then set the On Got Focus property of all the text boxes to =SetBackColor()
and the On Lost Focus property of all text boxes to =ResetBackColor()
This can be done easily by selecting all text boxes and write the property once and it will apply to all of them (no need to repeat the writes).
This will work whenever the user tries to edit any text box even if it was reached by TAB or ENTER buttons not only mouse click.

Taborder jumping between frames

I have a userform containing 3 frames that all include several textboxes. I would like to be able to tab the textboxes across frames.
So, something like this: Frame1 - Textbox1 > Frame2 - Textbox1 > Frame3 - Textbox1 > Frame1 - Textbox2 > Frame1 - Textbox3 > Frame2- Textbox2
The textboxes are dynamically added and stored in an array according to the desired taborder, so the desired order is easily accesible. I just cant seem to find a way to apply this.
It would of course be possible to change the frame layout. However, the frames are used both to control the placement of the textboxes, and also to add separate scrollbars if the amount of textboxes exceeds the frame area.
Is something like this possible? Any help or suggestions much appreciated.
Edit: Added picture of the 3 frames
Frames
Edit2:
I think destination-datas comment put me on the right track.
I created a class module
Public WithEvents TxtBox1 As MSForms.TextBox
Private Sub TxtBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
MsgBox ("Test")
End Sub
Private Sub TxtBox1_change()
MsgBox ("Test")
End Sub
And then in the sub that generates the textboxes, for the textboxes where I want to jump frames I do:
Dim tabArray1() As New TabBox1
Dim inputfelt As MSForms.TextBox
Set inputfelt = Hovedvindu.SkjemaFrame.SenderFrame.Controls.Add("Forms.TextBox.1", "M" & i & "SenderNavn", True)
Set tabArray1(i).TxtBox1 = inputfelt
This adds all the correct textboxes to an array so that I can make an Exit event that changes focus, which I think should not be too diffucult.
However, I cant seem to get the events to fire properly.
The change event seems to work when I change the textboxes with a sub, for example when I tested that the correct textboxes are added to the array by looping through and changing the text of the textboxes in the array. But when I change the textboxes manually, nothing happens. The exit event doesnt seem to work at all.
Im not too experienced with event handling, so I might have missed something.
I found an acceptable solution. The approach described in Edit 2 of the original post worked once I moved the definition of the TabArray() outside the sub, so that I keep track of the textboxes after the sub is ended.
I have one array, and one class module for the "end" textboxes on each of the 3 frames. The class modules tracks keydown on Tab. The 3 class modules are identical, except that they store the tabindex of the textbox from where the focus jumps to another frame in 3 different hidden labels on the userform. Keeping track of the tabindex allows me to know where to start when focus comes back to a frame.
the 3 class modules look like this:
Public WithEvents TxtBox1 As MSForms.TextBox
Private Sub TxtBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal
Shift As Integer)
If KeyCode = vbKeyTab Then
'store tabindex
Hovedvindu.Controls("SisteTab1").Caption =
Hovedvindu.SkjemaFrame.SenderFrame.ActiveControl.TabIndex
'call sub that moves the focus
flyttfokus (1)
End If
End Sub
The sub that moves focus is shown below. Input is just an integer (1,2 or 3) depending on which class module the call comes from, and thus which frame to move from/to. The sub reads the 3 hidden labels to know which textbox to start from when the focus is moved to a new frame. Error handling in the last case is for when the focus is moved from the very last textbox in the 3d frame. This will try to move focus to a non-existing textbox in the first frame, which will throw an error which can be ignored.
Sub flyttfokus(SisteFrame As Integer)
Dim St1 As Integer
Dim St2 As Integer
Dim St3 As Integer
St1 = CInt(Hovedvindu.Controls("SisteTab1").Caption)
St2 = CInt(Hovedvindu.Controls("SisteTab2").Caption)
St3 = CInt(Hovedvindu.Controls("SisteTab3").Caption)
Select Case SisteFrame
Case 1
Hovedvindu.SkjemaFrame.MottakerFrame.Controls(St2 + 1).SetFocus
Case 2
Hovedvindu.SkjemaFrame.InfoFrame.Controls(St3 + 1).SetFocus
Case 3
On Error Resume Next
Hovedvindu.SkjemaFrame.SenderFrame.Controls(St1 + 1).SetFocus
On Error GoTo 0
End Select
End Sub
This solution will work as desired when starting from the very first textbox. If the user however, mouseclicks to a textbox for example on the second line and then starts tabing, focus will be moved back to the first line when focus is moved between frames. This is because the variables (labels) that keeps track og the Tabindex from where to start when a frame receives focus are only updated as the user tabs through the sheet. It is probably possible to update these variables on mousclick to a textbox, based on the amount of textboxes that are generated by the program. For my purposes this is not deemed necessary.

Ellipsis Textbox for VBA Userform File Select

I am trying to create a path selection user interface for an extensive VBA program I've been working on, but I can't seem to get the ellipsis textbox that I'd like. This is a very common feature, especially in option tables. This is an example of what I'd like to get, straight from the VBA Options panel:
I would LOVE to find a way to get the same functionality in a Userform. The only solution that I've found thus far is to use a combo box with the ellipsis arrow option enabled. However, there doesn't seem to be an apparent way to use the activation of the combo box arrow to run a dialog box, nor does there seem to be a way to make it look UNLIKE a combo box. Last resort I use a button below the text box, but I'd really prefer a less-bulky way of doing this.
Any solution would be greatly appreciated.
The only solution that I've found thus far is to use a combo box with
the ellipsis arrow option enabled. However, there doesn't seem to be
an apparent way to use the activation of the combo box arrow to run a
dialog box, nor does there seem to be a way to make it look UNLIKE a
combo box
Your suggestion does work, and it is surely less complex and more elegant than having two controls work together, Button + Textbox.
A Combo can achieve perfectly the desired feature, in the following way.
1) In design mode, set the button style to Ellipsis
DropButtonStyle = fmDropButtonStyleEllipsis
And eventually, make the ellipsis show up only when the combo is entered, by setting the design-time property:
ShowDropButtonWhen = ShowDropButtonWhenFocus
2) If needed, you can set other design-time properties to have some look and feel. The defaults look pretty good however.
3) Add the following handler to the parent userform. The snippet simulates the launching of a dialog and getting a new value or cancelling. It does not show any dropdown window. (but you still have control over that: if you want to show it according to some condition, you still can call the method ComboBox1.DropDown)
Private Sub ComboBox1_DropButtonClick()
' The following two lines avoid to call the routine twice, at entry and at exit
Static i As Integer
i = (i + 1) Mod 2: If i = 0 Then Exit Sub
With ComboBox1
s = InputBox("enter some text", , .Value) '<~~ simulates any dialog
If s <> "" Then .Value = s
SendKeys ("{Enter}") '<~~ to close immediately the dropdown window
End With
End Sub
Try it ;)
Not only do ComboBoxes have Drop Buttons, so do TextBoxes (as do Excel's RefEdit controls). Even though you can't access the Textbox's Drop Button at design time, you can do so at runtime. Using a textbox avoids having to deal with the dropped down list of a combobox.
Given a textbox named TextBox1, the following code will provide the desired ellipsis drop button:
Private Sub UserForm_Initialize()
With Me.TextBox1
.DropButtonStyle = fmDropButtonStyleEllipsis
.ShowDropButtonWhen = fmShowDropButtonWhenAlways
End With
End Sub
Then use the DropButtonClick event of the textbox to perform whatever action you want:
Private Sub TextBox1_DropButtonClick()
'' Code here to do what you need
End Sub
I have an extensive example at Alternative to Excel’s Flaky RefEdit Control that uses a textbox with a "Reduce" drop button to replicate the functionality of Excel's unreliable RefEdit controls.

Get Picture from Worksheet into Excel Userform

I am looking to view an image from the worksheet in an Image control on a userform.
This image will change based on the value on a combobox. I have inserted (Using: Insert -> Pictures) a couple of images into "Sheet1" of my workbook and named them "Picture1" & "Picture2".
I have created the below UserForm:
Form http://im56.gulfup.com/msKyqi.png
And this is the code that I am trying to use in order to load the images from the sheet, but unfortunately, this is not working at the moment.
Private Sub ComboBox1_Change()
UserForm1.Image1.Picture = LoadPicture(Worksheets("Sheet1").Shapes(ComboBox1.Value))
End Sub
Private Sub UserForm_Initialize()
UserForm1.ComboBox1.Clear
UserForm1.ComboBox1.AddItem "Picture1"
UserForm1.ComboBox1.AddItem "Picture2"
UserForm1.ComboBox1.Value = "Picture1"
UserForm1.Image1.Picture = LoadPicture(Worksheets("Sheet1").Shapes(ComboBox1.Value))
End Sub
Every time I run this code I get the below error:
Error http://im43.gulfup.com/YoWvTp.png
Please advise.
I figured it out!
As I am using a UserForm there is a workaround to the issue.
Instead of having the images in the worksheet to then try and load them in the form I tried having them in the UserForm in the first place, here is how.
Create a frame on your userform:
Frame http://im88.gulfup.com/Moy8I6.png
Set the visible property of the frame to "False":
Visible http://im88.gulfup.com/sAIQqh.png
Insert your images by adding a picture control and loading the images, you can add as many images as you need:
Images http://im88.gulfup.com/oas0EQ.png
Name the images:
Name http://im88.gulfup.com/cIO317.png
Drag all the images one over the other into the frame, (you can then move the frame into a corner so it doesn't bother you:
Drag http://im88.gulfup.com/1fOSut.png
Move Away http://im88.gulfup.com/Q1fzKd.png
Next create a picture control, this is what you will use to display the picture based on a selection:
Form View http://im88.gulfup.com/X1UVRB.png
In this example, I am going to use a combobox for the selection. Now insert the below code in to the form which is pretty straight forward:
Private Sub ComboBox1_Change()
' Image1 is the name of the created picture control
UserForm3.Controls.Item("Image1").Picture = UserForm3.Controls.Item(UserForm3.ComboBox1.Value).Picture
End Sub
Private Sub UserForm_Initialize()
UserForm3.ComboBox1.AddItem "Argentina"
UserForm3.ComboBox1.AddItem "Brazil"
UserForm3.ComboBox1.AddItem "Chile"
End Sub
As you will see, the frame with the pictures is Hidden, and the image is changing inside the picture control based on a selection:
Result http://im88.gulfup.com/MSqyHF.png
I think it's the better way to go as opposed to exporting the images from the worksheet to a Temp folder and then loading them back into the picture controls.
The LoadImage() function expects a filename (which can be fully qualified with a drive letter and path). You are getting a type mismatch because it wants a string, and you are giving it an image object.
There is, as far as I know, no simple way to put an image that resides in the current application into an image control. The (hackish) workaround that I know about is to export the image to a file, and then import that same file using LoadImage().
This is the same path you have to go down if you want to embed a chart that updates dynamically into a userform. You export the chart as an image (e.g., a JPEG), and then use LoadImage() to pull the image back into the image control.
I know this post is ancient, but I found my way here. I came up with a slightly different solution to this problem. I have about 30 pictures I need to load based on a combo-box selection. First, all combo-box options (for discussion "XX") are saved to a separate worksheet which is "Very hidden" from the user and loaded into the combobox on userform activation. On the userform a frame was added, and within the frame 30 image-boxes all overlapping perfectly were placed. Each image-box was carefully named "Img_XX" where XX is the simple two-letter identifier.
With this setup it is now possible to iterate through each "Control" (the image boxes) in the Frame and hide them all, except the one with a name that matches the combo-box value. The code in the userform module, within the Combobox_Change() function, looks something like this:
Private Sub ComboBox_Change()
Dim SearchValue as String
SearchValue = me.Combobox.value
Dim Ctrl as Control
For each Ctrl in Me.TestFrame.Controls
If Ctrl.Name Like "img_" & SearchValue Then
Ctrl.visible = True
else
Ctrl.Visible = False
End If
next Ctrl
End Sub
I hope this helps, let me know what you think. :)

Microsoft Word VBA tab key to make textbox visible

Longtime viewer, first time question asker.
I'm currently working with UserForms within MS Word and have a particular form that can have up to 20 different labels and accompanying textboxes with varying texts. I have all but the first hidden while not in use, however I would like the next label and text box to become visible following input in the previous textbox. So if you enter data (anything) in the first textbox, the next label and text box will become visible. Does this make sense? I've seen other responses here suggest using AfterUpdate() rather than Change() or Click() but can't figure out how to use any of them. I would share my code but at this point I don't have any code to share, other than my labels and textboxes are lblField1 txtField1, lblField2 txtField2...
Any suggestions?
I would suggest using Change event, when using AfterUpdate you need to leave you TextBox for a while to fire the event. If you have only one TextBox visible there is nothing to move to. If you have more TextBoxes you would need to move back to fire AfterEvent and I don't think this is what you expect.
So, double click wherever on your userform and add the following code in code area:
Private Sub txtField1_Change()
txtField2.Visible = True
lblField2.Visible = True
End Sub
Next, add next portion for next textbox:
Private Sub txtField2_Change()
txtField3.Visible = True
lblField3.Visible = True
End Sub
And so on, if only you have an order in controls name you just need to change numbers in the end of control names.