Can a Textbox have data validation from a table? - excel

I'm pretty strong on Excel but new to VBA.
I've built a set of tables and user forms to maintain records of calls, contacts, etc.
This is my question:
Can I use a textbox on a user form for input and editing a table where that specific textbox has data validation from another table in the workbook?
That is, can the data validation list for that textbox be a table field that can add names, etc. to the data validation?
For an example, on the main contact table I have a user form that has a textbox for the person taking the call.
They should be able to pull their name from a list.
I know I could use a combo box but I don't see how to make the combo box data validation dynamic.
Can I use a field in a different table that workbook to be a dynamic range?
Hope that makes sense...
Thanks in advance for any guidance where to look.
Haven't been able to tie a specific table field into the validation thus making it "dynamic".

Set the rowsource for the Listbox on Form initialization.
Private Sub UserForm_Initialize()
Dim lr As Long
ListBox1.Clear
ListBox1.ColumnHeads = True
With Sheets("Sheet1")
lr = .Cells(.Rows.Count, "A").End(xlUp).Row
If lr > 1 Then
ListBox1.RowSource = .Range("A2").Resize(lr-1).Address
End if
End With
End Sub
or alternatively from a table
Private Sub UserForm_Initialize()
ListBox1.Clear
ListBox1.ColumnHeads = False
With Sheets("Sheet1")
ListBox1.List = .Range("Table1[[#All],[MYCOLUMN]]").Value2
End With
End Sub

Got it...
Works well with a Combobox
Used "intersect" to use only the data in that column...
Dim myTable As ListObject
Dim myArray As Variant
Set myTable = wksISSInfo.ListObjects("tblISSInfo")

Related

Excel VBA: Displaying table data using drop down list

I am a beginner in VBA. I have a worksheet in Excel where tables for each individual month is created to calculate the total amount of manhours for each month. The tables are located in different columns in the worksheet. The data in this table is populated using manually inputted data in respective sheets created for each month.
Currently, this is being done manually and the list is getting very long. I would like to improve on this by creating a dropdown list filter and retrieving the respective data from each month and year and displaying it in the form of a calendar instead. Can anyone guide me on how this can be done?
This is an example of the worksheet I want to compile:
I want it to look something like this where the data for the data will change according to the data I retrieve from the respective months. The months and years will be in the form of drop down list.
The workbook will be updated on a daily basis. The names of the worksheets involved will be named in a format like this: Jul'19, Aug'19, Sept'20, etc. There will be more worksheets created over time.
Please, create a form and place the next code in its module:
Option Explicit
Private Sub UserForm_Initialize()
Dim sh As Worksheet, wb As Workbook
Set wb = ActiveWorkbook
For Each sh In wb.Sheets
Me.cbMonth.AddItem sh.Name
Next sh
End Sub
Private Sub cbMonth_Change()
Dim wb As Workbook, sh As Worksheet, Tbl As ListObject
Set wb = ActiveWorkbook
Set sh = wb.Sheets(Me.cbMonth.Value)
Set Tbl = sh.ListObjects(1)
arr = Tbl.Range.Value
With Me.ListBox1
.ColumnCount = UBound(arr, 2)
.ColumnWidths = "40;25;22;23;22;22;22;48;40"
.list = arr
End With
End Sub
So, you must place a combo box named cbMonth and a list box named 'ListBox1`.
On the form Initialize event the combo box is populated with the sheets name.
On the combo box Change event the 'ListBox1` is populated with the first table range of the selected sheet name. So, in each sheet should exist only one table, or, if more tables, the necessary one must be the first.
You will also be able to input data in the list box, using its DblClick event. The user will be asked about the day where the data to be inputted and then, the sheet can be updated, too...

old data when refreshing a pivot table linked to a ms query with a parameter

So I have a ms query with a parameter (let's call it "qry_Accounting") and I linked this parameter to a field that is linked to a combobox. This way I can filter my data with the combobox.
I then created a Pivot Table based on the ms query. Normally, I should be able to see the data linked to the item selected in the combobox. I can see that when I change the item selected in the combobox the data changes in "qry_Accounting". I had to create a button, so that when I change the item selected and click on the button it will refresh the pivot table.
My problem is I always have the data from the previous selected item in my pivot table, and only that data. I really don't understand what happens. If I create a new pivot table it will have the correct data, but the behaviour continues when I change the item, I still always keep the previous data and I don't get the new data.
One more thing, If I manually refresh the table it will work. It will work even for multiple pivot tables when I refresh one of them if they are all linked to the same qry_Accounting table.
How can I have the correct data showing without asking the user to manually refresh all the time?
PS : I already changed the property "Number of items to retain per field" to "none".
Following some questions in the comment here is more of my code (When clicking on the button to apply the combobox change) :
Sub Button5_Click()
'If the buffer place (O4) is different from the combo linked cell (F4) then
'assign the value from F4 to O4.
'the table will then be updated because as soon as O4 value changes the
'table is updated (the parameter is taken from O4)
If Sheets("base_pivot").Range("O4").Value <> Sheets("base_pivot").Range("F4").Value Then
Sheets("base_pivot").Range("O4").Value = Sheets("base_pivot").Range("F4").Value
'We wait 5 seconds to avoid access denied problems
Application.Wait (Now + #12:00:05 AM#)
'we ask for a refresh of the pivot tables explicitely
RefreshPivotTables ActiveWorkbook
'we ask for a refresh of all data.
ActiveWorkbook().RefreshAll
End If
End Sub
Sub RefreshPivotTables Code
Sub RefreshPivotTables(wb As Workbook)
Dim ws As Worksheet
Dim pt As PivotTable
Dim pi As PivotItem
Dim pf As PivotField
For Each ws In wb.Worksheets
For Each pt In ws.PivotTables
pt.PivotCache().Refresh
pt.RefreshTable
Next
Next
End Sub
Other than that everything is automatic. The ms query has a parameter, so as soon as the O4 value is updated, the new data is loaded in the table.
So then the only thing to do it to refresh the pivottable.
Since I don't have your query ("Table_edu_ana_invoices_query4"), I tested the code below using an Access DB, and just wrote the Query in the code below (you will see in the code comments).
Let me know if you figure out how to modify the Query section to your needs.
Code
Sub RefreshPivotTables(wb As Workbook)
Dim ws As Worksheet
Dim pt As PivotTable
Dim ptCache As PivotCache
Dim pi As PivotItem
Dim pf As PivotField
Dim con As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim cmdCommand As ADODB.Command
'===== modify here to put your Connection String to your DB =====
con.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Radoshits\Desktop\Database11.accdb"
'===== this is the String query I am using >> replace with yours =====
rs.Open "SELECT * FROM Table1", con, adOpenStatic, adLockReadOnly
For Each ws In wb.Worksheets
For Each pt In ws.PivotTables
' update Pivot Cache with Query settings
With pt.PivotCache
Set .Recordset = rs
.Refresh
End With
Next pt
Next ws
Set rs = Nothing
con.Close
Set con = Nothing
End Sub
So in the end I changed the way I do things since I couldn't make it work with MS query. I am now using excel 2016 query and no parameter anymore. The file is bigger, it is slower, but it works (I have over 100k lines in my data). I am using a slicer to filter the table. I am using VBA to update the slicer value to the value in the combo box. This way the pivottable get the correct data all the time. It seems pivot table has a problem when using MS query with a parameter, at least that is what I get from this experience. I'll probably try again in the future with another document.
Thanks for your help Shai Rado, I learned quite a few things a pivot tables and their cache :)

Is it possible to control charts in powerpoint using combo box?

The below image is an example of what i am trying to do. My chart shows the capacity of Resources over month. I choose the month for which i want to view data from the dropdown list. While this is in excel, im trying to do the same in Powerpoint using the charts and AxtiveX controls. Can anyone please guide me on this?
Chart and combobox example
Using a standard Microsoft Forms 2.0 ComboBox control (I do not use ActiveX controls), this is pretty much what you're looking for.
Insert the ComboBox control on the slide where the chart exists. This assumes that the chart data exists in the default ListBox item on the ChartData.Workbook.Worksheets(1) worksheet (i.e., this is what happens when you insert a chart directly in PPT) if you're copying a chart from Excel, this may need revision, but the general idea is the same:
When the user selects the combobox, (ComboBox1_GotFocus queries the chart's underlying data to populate the list. If your data is structured differently, this will need to be modified.
User can make a selection in the ComboBox.
After making the selection, the ComboBox1_Change event will identify the range of data which contains the selected series, and hides the other series, so that only the selected series is visible
Here's my default chart & data which I can view by right-click/Edit Data:
Displaying the slideshow, entering the ComboBox will display the list of series names:
Then, change the selection, and see only the selected series:
Option Explicit
'This code belongs in a SLIDE module in PowerPoint
Private Sub ComboBox1_Change()
'This procedure hides/unhides chart series, based on combobox value
Dim rng As Object 'Excel.Range object
Dim c As Long
With Me.Shapes("Content Placeholder 5").Chart.ChartData '## MODIFY YOUR SHAPE NAME
.Activate
.Workbook.Parent.WindowState = -4140
For c = 2 To .Workbook.Worksheets(1).ListObjects(1).HeaderRowRange.Columns.Count
Set rng = .Workbook.Worksheets(1).ListObjects(1).HeaderRowRange.Cells(c)
rng.EntireColumn.Hidden = (rng.Value <> ComboBox1.Value)
Next
.Workbook.Close
End With
End Sub
Private Sub ComboBox1_GotFocus()
'This procedure sets the list items in the combobox whenever it gets focus
Dim lst As Variant
Dim xlApp As Object
With Me.Shapes("Content Placeholder 5").Chart.ChartData '## MODIFY YOUR SHAPE NAME
.Activate
.Workbook.Parent.WindowState = -4140
Set xlApp = .Workbook.Parent
.Workbook.Worksheets(1).Columns("B:D").Hidden = False
lst = xlApp.Transpose(xlApp.Transpose(.Workbook.Worksheets(1).Range("B1:D1").Value))
.Workbook.Close
End With
ComboBox1.List = lst
End Sub

Access to Excel via VBA to specific sheet whilst overwriting a variable record list

new to stackoverflow and need a little advice on modifying this code to include the deletion of records further than the exported range when exporting from Access to a specific excel worksheet:
Query to extract all Access data from = Stocklist
Spreadsheet to paste data to (inc headings) = G:\Project\test1.xlsx
Worksheet to extract to is also named "Stocklist" and the range is A1 onwards - there are four columns of data that need overwritten by the updated list which is derived from the query.
The following selects the correct file and overwrites the range A1 onwards:
Public Sub Export()
Dim rstName As Recordset
Set rstName = CurrentDb.OpenRecordset("Stocklist")
Dim objApp As Object, objMyWorkbook As Object, objMySheet As Object, objMyRange As Object
Set objApp = CreateObject("Excel.Application")
Set objMyWorkbook = objApp.Workbooks.Open("G:\Project\test1.xlsx")
Set objMySheet = objMyWorkbook.Worksheets("Stocklist")
Set objMyRange = objMySheet.Cells(objApp.ActiveSheet.UsedRange.Rows.Count + 1, 1)
With objMyRange
rstName.MoveFirst
.Clear
.CopyFromRecordset rstName
End With
This is great if the data is the same size or larger, but if its smaller it leaves the items outside the pasted/exported range in the list (eg range of 400 records will leave all records after 400 present after overwrite. Is there any way to clear the sheet before the data is added?
Also how transferable is excel macro VBA code as I have some validation rules and error handling in other spreadsheets that I would like to add (eg. check file is not open, return msgbox etc)
Any help much appreciated
Will this work for you?
objMySheet.UsedRange.Clear
With objMyRange
rstName.MoveFirst
.Clear
.CopyFromRecordset rstName
End With

Allowing a user to duplicate a page in an Excel Multi-Page Userform

I am posting this question here because I actually found another question similar to this one, "Copy Elements From One Page To Another in Multipage with VBA in Excel" I still have questions as I'm not sure how this will work. I would still need to put my data fields into a frame, though.
I need to allow the user to add as many pages as necessary while some of the user's content will move with it and some wil not.
Would it be better to have a field where the user tells the system how many times they need to duplicate it? Or should I just have a button that says, "duplicate this page"
Also, in addition to the UserForm page being duplicated for user input, I need the process to also duplicate the Excel worksheet to assocate with each duplicated page within the Userform.
Help with this will be greatly appreciated!!
Set an Upper Cap. i.e A user should not be able to add more than specific number of pages. This would ensure that you don't encounter unforseen errors. For example, The user should not be able to add more than 25 pages (just an example) Remember, Excel is very hungry in terms of memory when it comes to adding unlimited worksheets and hence defining an upper cap is necessary. Also Imagine having say 100 pages in the multipage. It would be too messy.
Would it be better to have a field where the user tells the system how many times they need to duplicate it? Or should I just have a button that says, "duplicate this page"
I believe you can have both the options. This will ensure that
If the user wants to add say 6 pages in one go then the user doesn't have to press the button 6 times.
If the user wants to add just one page, then the user can simply click on that button, instead of typing say '1' in a textbox and then clicking on the duplicate button.
Also, in addition to the UserForm page being duplicated for user input, I need the process to also duplicate the Excel worksheet to assocate with each duplicated page within the Userform.
This again is not a problem. You can always use Worksheets.Add method to add more sheets
You can then set the source of each control on the page to the respective sheets.
Here is a simple example
This will create a copy of the page and also copy the existing textbox to the new page and set it's ControlSource property.
SCREENSHOT
BEFORE
AFTER
CODE
Option Explicit
Private Sub CommandButton1_Click()
Dim pgCount As Long
Dim wsNew As Worksheet
Dim ctl As Control
'~~> Get the current count of the pages
pgCount = MultiPage1.Pages.Count
'~~> Add a new page
MultiPage1.Pages.Add
'~~> Change '0' to whatever page you want to copy from
MultiPage1.Pages(0).Controls.Copy
'~~> Paste it in the newly created multipage
MultiPage1.Pages(pgCount).Paste
'~~> Add a new sheet
Set wsNew = ThisWorkbook.Sheets.Add
'~~> Give the new sheet a name
wsNew.Name = "Erika"
'~~> Adding a test value in Range A1 so that it reflects
'~~> When we set the ControlSource of the textbox
wsNew.Range("A1").Value = "Hello World"
For Each ctl In MultiPage1.Pages(pgCount).Controls
If TypeOf ctl Is MSForms.TextBox Then
ctl.ControlSource = wsNew.Range("A1").Address
Exit For
End If
Next
End Sub
Here is another example where instead of copying the control, you can actually create a new control and set it's ControlSource property.
SCREENSHOT
(Same as above)
CODE
Option Explicit
Private Sub CommandButton1_Click()
Dim pgCount As Long
Dim wsNew As Worksheet
Dim ctl As Control
'~~> Get the current count of the pages
pgCount = MultiPage1.Pages.Count
'~~> Add a new page
MultiPage1.Pages.Add
'~~> Add a new textbox
Set ctl = MultiPage1.Pages(pgCount).Controls.Add("Forms.TextBox.1", _
"TextBox" & pgCount)
'~~> Add a new sheet
Set wsNew = ThisWorkbook.Sheets.Add
'~~> Give the new sheet a name
wsNew.Name = "Erika"
'~~> Adding a test value in Range A1 so that it reflects
'~~> When we set the ControlSource of the textbox
wsNew.Range("A1").Value = "Hello World"
ctl.ControlSource = wsNew.Range("A1").Address
End Sub
Hope this gets you started...

Resources