How to get values from controls on tabstrip in VBA? - vba

In different tabs of a tabstrip I have input values which are different in each tab. I need to write a code which takes all these values and do some work like sums up the values of each tab on button click.
Can anyone help me do this? In my code when I input value at a textbox of one tab it also changes the value of all other tabs and hence cannot receive different values of each tab. Any idea, please?

Multipages vs Tabstrips
A multipage is an object with "pages". Each page can hold it's own collection of controls which can then be referenced either directly or through the containing page object.
A tab strip is an object with "tabs". Unlike a "page" object, a tab does not have it's own controls. Instead, there are only the original controls, visible for all "tabs".
Programmatic differences
Since a multipage has a different set of controls for each page, there is very little housekeeping required. The selection of a page affects which controls are visible, and the controls automatically retain values assigned to them (as expected).
For a tabstrip, since there is only the initial set of controls, there is a lot of housekeeping required in the code. The selection of a tabstrip does not have any automatic effect on the values in the controls. Instead the controls act as would be expected if they were not in the tab strip at all.
Tabstrip Solution
Set up a variable (array, collection, dictionary) that can be used to hold the various values of the controls. Then, in the TabStrip_Change() event, store the previous value, and reset the control for the new tab (or fill in the value the new tab last held).
I recommend adding a userform level variable Dim old_tab as Long which you can set to the current page at the end of the TabStrip_Change() event. (This is useful for retrieving previously filled values for the correct tab).
For my sample code, I will be using an array. However, since arrays are not very flexible with changing lengths, you can also look into using either a dictionary or collection, if desired.
For the userform pictured below, the following code causes the single textbox to act as though there is a different textbox per tab. It also saves the values whenever the tabstrip changes. (Note: if you then use the saved values for the calculation, remember to update the value for the current tabstrip first.)
Option Explicit
Dim old_tab As Long
Dim textValues As Variant
Private Sub TabStrip1_Change()
textValues(old_tab) = TextBox1.Value 'Saves the old value
TextBox1.Text = textValues(TabStrip1.Value) 'Updates value to reflect tab change
old_tab = TabStrip1.Value 'updates tab # variable
End Sub
Private Sub UserForm_Initialize()
ReDim textValues(0 To TabStrip1.Tabs.Count - 1) 'tabs are zero-based, so count is always one more than the maximum tab value
old_tab = TabStrip1.Value 'Ensures that the first value will be saved to correct location at the tab change
End Sub

Related

Passing a checkbox control to a function

I am using Access 365 and VisualBasic. I have a number of checkboxes on a form that I want to display just a subset of these at a time, so I want to reposition the top of the checkboxes so that no matter which are currently displayed, I can make them line up nicely.
So, I have declared an array of checkboxes that I want to dynamically add those checkboxes to display:
' Array holding the checkboxes that will be displayed, depending upon species, sex, etc.
Dim arrCheckBoxes(cNumCheckboxes) As CheckBox
Then as I determine that a specific check box should be shown, I want to add it to the array at the next available position using this function (which will also update the next available position):
Private Sub AddCheckbox(ByRef arrCheckBoxes() As CheckBox, ByRef chkNew As CheckBox, ByRef intCurrentCheckbox)
intCurrentCheckbox = intCurrentCheckbox + 1
arrCheckBoxes(intCurrentCheckbox) = chkNew
End Sub
My problem is that in the code that calls the AddCheckbox function, I cannot figure out how to pass the check box. I am using the following code (CatNeuter is the checkbox from my form).
Call AddCheckbox(arrCheckBoxes, Me.CatNeuter, intCurrentCheckbox)
However, Me.CatNeuter is always 0, so I think I am getting just the value, and not the checkbox control itself. I've tried numerous different methods such as:
Me.Controls!CatNeuter
Me.Controls("CatNeuter")
But I just cannot figure out how to pass the actual checkbox so I can then go through the array and change the Top property for each checkbox.
Regards,
Lise
You need to use Set for objects:
Set arrCheckBoxes(intCurrentCheckbox) = chkNew

MS ACCESS VBA - best way to change all properties values of a form's textboxes at once

I have a form with 3 textboxs and i want to change their properties values according to some events.
My idea is to set these properties to a global form's variables in order to use them whenever i want with a function or module (this depends on your suggestion).
Assuming that i want to change all textboxs.enabled property by pressing a button
and i want to change another different property if needed in the future (like bordercolor),
my example is this:
in the form VBA,
Option Compare Database
Option Explicit
Private Const AllTxtboxes = *** all txtboxes ***
in the VBA button
Private Sub button1_Click()
AllTxtboxes.enabled = True
End sub
Thanks in advance.
You need to loop trough all controls and identify those you want to change. The problem is that each control type got their own properties, so you need to make sure you are in the right one.
And for that, there is a property common to all controls named Tag
There, you can specify a value and check it. It's really helpful to select only what you want.
I made a simple form with 6 textboxes:
Note that in design view, properties panel at right, tab others, last property is Tag (sometimes it comes as aditional info or something like it).
There, I typed 99 but only on textboxes 2, 4 and 6, because those are the textboxes I want to handle (that would be kind of your array of textboxes)
I added a command button to change forecolor of those textboxes to red when clicked. My code is:
Private Sub CMD_CHANGE_FONT_COLOR_Click()
Me.Painting = False
Dim MyControl As Control
Dim MyTxt As TextBox
For Each MyControl In Me.Controls
If MyControl.Tag = 99 Then
'we set MyTxt to MyControl so we can use Intellisense, not really needed, but it makes coding easier
Set MyTxt = MyControl
MyTxt.ForeColor = vbRed
Set MyTxt = Nothing
End If
Next MyControl
Me.Painting = True
End Sub
When the form loads, you will see:
But after click on command button, the forecolor of those 3 textboxes will be red:
There you go. So everytime you want to do something with that array of textboxes, you can use this code to loop and change the properties you want.

How to force match Combobox RowSource row by setting its Text property?

On the shop floor, a virtual (touch) keyboard form with larger buttons is used to enter text into TextBoxes and ComboBoxes.
This works fine, and combobox text is set correctly, however the RowSource is not matched as it would be when you type directly into the ComboBox with a physical keyboard. The entire list is displayed as if you had just pressed the dropdown button without typing a character.
In the example below, there is a Stefan in the list, but that row is not looked up.
I've tried SetFocus, Requery, Refresh, Dirty, and calling _AfterUpdate, in combinations and with DoEvents, to no avail.
I've even tried to select, Cut, and Paste the text (but even setting SelStart and SelLength to correct values does not select it, so I'm assuming it cuts and pastes a range of zero characters). If I could make the text-selection work, I could probably get this to work.
Dim ctrlPrevious As Control
Set ctrlPrevious = Screen.PreviousControl
ctrlPrevious.SetFocus
ctrlPrevious.text = sTemp
ctrlPrevious.SelStart = 0
ctrlPrevious.SelLength = Len(sTemp)
ctrlPrevious.Cut
ctrlPrevious.Paste
Is there a way to force the AutoComplete behavior?
Use SendKeys to mimic the normal keyboard beheviour instead of all the above code.
So in your btnPressed_Clicked event
Dim ctrlPrevious As Control
Set ctrlPrevious = Screen.PreviousControl
ctrlPrevious.SetFocus
SendKeys btnPressed.caption

Do you have to show every tab before all textboxes actually populate?

I have a vb.net form that uses multiple textboxes across several different tabs. Within one of those tabs, I have a sub set of tabs. My save functionality calls stored procs for each tab and cycles through the values on each page to either do an update or a "add new". I noticed that while testing, some of the pages do not save or update any of the values in the textboxes. After a few days of investigating, I realized that if I edit something, then physically click through the other tabs, it all saves/updates properly. If I don't click through them, they don't all save. Is there a reason for this that I am missing? When you enter a search value, I cycle through the pages and populate them all at the same time so I was assuming it wrote those values BEFORE it physically rendered...I guess I am wrong?
From the TabPage documentation Remarks section
Controls contained in a TabPage are not created until the tab page is shown, and any data bindings in these controls are not activated until the tab page is shown.
So the answer to your question is "Yes the tabpage must be shown".
However, the definition of "shown" is subject to interpretation. In reality, all you need to do set the TabPage.Visible property to True and not actually cycle through and display each TabPage.
A recursive scan of the form for TabPage controls will work:
Private Shared Sub TabPagesVisible(parent As Control)
For Each c As Control In parent.Controls
If TypeOf c Is TabPage Then c.Visible = True
TabPagesVisible(c)
Next
End Sub
Example usage:
Sub SaveFormTabData()
TabPagesVisible(Me) ' Me refers to the containing form
' code to save control data
End Sub

Number Picker in Access / VBA

I am trying to put a number picker in a form in MS Access 2007. Here's an example of what I am trying to make:
I cannot find this in the default form controls, and have tried to make one myself using a listbox. Listboxes can be modified to look just like the number picker above, however the arrows only change the view, of the list, and not the actual selection (that is the value). For example, with the list box, if I have it range from 1 to 3, and default at 1 - when I change it to 2 via the arrows, the value of the listbox does not change, and is still one.
Does anyone know how to get a number picker in Access?
So you want to create a list of numbers and allow users to change the value displayed (AND stored as the control's value) using up and down arrows, such that they select the next or previous in the list.
I would suggest creating a text box and two buttons. Populate an array with the list of values. When a button is clicked it would:
A. Find the position in the array of any value already entered into the text box (eg loaded from a database)
B. Get the next or previous item from the array.
The array is populated as required (probably when the form is opened).
If you just need to allow the user to enter a whole integer number (ie a number spinner) you would do as follows:
Create one using a (locked) textbox and two buttons. Just add a textbox (name it something like txtValue) and two buttons (btnUp and btnDown), then add code like this to the Click event of those buttons:
Private Sub btnUp_Click()
Me.txtValue = Nz(Me.txtValue, 0) + 1
End Sub
Private Sub btnDown_Click()
Me.txtValue = Nz(Me.txtValue, 0) - 1
End Sub
You could add if statements to limit the data being entered
Or you can use a 3rd party control.
http://www.fmsinc.com/microsoftaccess/controls/components/spin-button/index.html
There are probably more, but be aware that using these sorts of controls in Access is unsupported, and there is no guarantee moving forward that they will work in Access. You're far better off using the native methods described earlier.