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...
Related
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")
This question already has an answer here:
Excel vba add code to sheet module programmatically
(1 answer)
Closed last year.
I have code that creates a worksheet and the worksheet contains a table.
I then programmatically add an advanced filter to the table in the created worksheet.
This works fine, but the advanced filter does not refresh on change of the worksheet: A known issue.
The standard solution is to put code behind the worksheet_change event so the filter is refreshed when the worksheet changes. This also works fine when I add this code manually.
But when I create a sheet I want to automatically create the code for the new sheets worksheet_change event. I don't know how to programmatically specify code for my new sheet in the worksheet_change event.
Is this possible? Or is there another way to accomplish this?
Maybe look at using this instead. It'll fire for all sheet changes and allows your code to work centrally ...
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
End Sub
You can create a class module with the event and hook that to your worksheets. So you can add a hidden sheet with all workbook names that you want to add that event to.
So if you programmatically add a new sheet you just need to add its name to that list.
So first add a sheet named MyClassSheets (you can make it hidden so no user sees it). And add some sheet names there:
So this means we want to run your worksheet_change event in Sheet2 and Sheet3 only.
Then we add a class module MyWsClass:
Option Explicit
Public WithEvents Ws As Worksheet
Private Sub Ws_Change(ByVal Target As Range)
MsgBox Target.Address(False, False) & " changed."
End Sub
This is the event we want to run. It just shows a message box which cell was changed. You need to adjust that to your wishes.
Finally we need to hook those events to the worksheets. So we add a normal module (non-class module) HookWsEvents:
Option Explicit
Dim MyWorksheets() As New MyWsClass
Public Sub HookEvents()
' get list of worksheets we want to add the class
With ThisWorkbook.Worksheets("MyClassSheets")
Dim MyClassSheets() As Variant
MyClassSheets = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).Value
End With
ReDim MyWorksheets(UBound(MyClassSheets) - 1)
Dim i As Long
' add class to those worksheets
Dim Ws As Variant
For Each Ws In MyClassSheets
Set MyWorksheets(i).Ws = ThisWorkbook.Worksheets(CStr(Ws))
i = i + 1
Next Ws
End Sub
So now we just need to make sure that the procedure HookEvents is called everytime the workbook opens. So we add the following into ThisWorkbook:
Option Explicit
Private Sub Workbook_Open()
HookEvents
End Sub
After running HookEvents the event runs in every sheet that is listed in MyClassSheets.
If you now add a new worksheet that you want to add the event to, you just need to add it to the list in MyClassSheets and run HookEvents again. Therefore we can add a small helper procedure to our HookWsEvents module:
Public Sub AddWsToList(Ws As Worksheet)
With ThisWorkbook.Worksheets("MyClassSheets")
' add the worksheet name of Ws to the list in MyClassSheets
.Cells(.Rows.Count, "A").End(xlUp).Offset(RowOffset:=1).Value = Ws.Name
End With
End Sub
So now we can use the following code
' add a new worksheet as last worksheet
Dim NewWs As Worksheet
Set NewWs = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
' give it a name
NewWs.Name = "Sheet5"
' add it to the list of MyClassSheets
AddWsToList NewWs
' hook events to all sheets
HookEvents
to add a new worksheet and add the event to it.
You may want to add some error checking if a worksheet in the list of MyClassSheets does not exist anymore (was deleted) so your code does not thorw an unhandled exception in this case. I left this out to have the above explanation more clear.
If all your sheets have someting common in their name you don't need to maintain that MyClassSheets list. So for example if all the sheets you want to add the event to start with XYZ_ you just need to loop over all sheets in the HookEvents procedure and check if they start with XYZ_ to add them to the MyWorksheets array then. Resizing that array may be a bit more complicated then.
enter image description hereI want to read data from two sheets whereas user will enter only date and after clicking button data will be populated in sheet.
Title Date
Enter Week Start Date "7/11/2016" (Button)
Name Project-ID Project Name Project Start Date Project End Date Sum Sum * 20
This is actual format of requirement.
in your line
Set objsheet = bjExcel.ActiveWorkbook.Worksheets("Config_InputAllocation_Weekly")
Set objsheet2 = objExcel.ActiveWorkbook.Worksheets("Config_Project")
you try to set both sheets active, which is not possible. There only be one active sheet. But you don't have to set them active. Use the following technique:
Dim objExcel as Object
Set objExcel = CreateObject("Excel.Application")
Dim myWb as workbook, myws1 as worksheet, myWs2 as worksheet
Set myWb = objExcel.Workbooks.Open("C:\Users\ABC\Documents\NSL\Automation Macro\NSL_DM_Tracker.xlsm")
Set myWs1 = myWb.Worksheets("Config_InputAllocation_Weekly")
Set myWs2 = myWb.Worksheets("Config_Project")
Then you can easily call the data from both sheets whether they are active or not:
Msgbox myWs1.Cells(1,1).value
Msgbox myWs2.Cells(1,1).value
Then the other problem is that you have defined an Sub searchdata() but it is not called within your CommandButton1_Click() Sub.
Moreover use Option Explicit setting, that is, put this line at the very top of your code:
Option Explicit
This will help you to debug your code.
Last but not least, in your Sub searchdata() no Worksheets are defined. Thus it will not know which one (myWs1 or myWs2) to use and when.
Good Luck,
Viktor
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
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