VBA Several UserForms export to Sheet - vba

In my Workbook i have several identical UserForms. Only the name is different.
For Example WKA1 / WKA2 / WKS1 / WKS2 / PM1 / PM2 and some more.
Now i want if i click on the CommandButton on the UserForm, that the Data in the TextBoxes will be saved on a extra Worksheet. I want that with a seperate Macro, so that i code for the CommandButton looks like this:
Private Sub CommandButton1_Click()
Call Save_UF_Data
[NameOfUF].Hide
End Sub
The Problem is, i donĀ“t know how to write in the Macro "Save_UF_Data" that it always takes the TextBox from the UF which is open.
I already tried it with:
Me.Controls("TextBox1")
I hope someone can show me how i have to write the code that my macro will work for every UserForm in my Workbook.
This is my Macro so far:
Public Sub Save_UF_Data()
Dim lastrow As Long
Dim a As Integer
Dim ws As Worksheet
Set ws = Worksheet("UserForm_Data")
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
a = 1
Do
ws.Range("A" & lastrow).Value = Me.Controls("Label" & a) ' How do i have to change this part that it takes the value from the userform which is open?
a = a + 1
lastrow = lastrow + 1
Loop Until a = 25
End Sub

You could pass the calling form Object as Parameter to the Sub:
Private Sub CommandButton1_Click()
Call Save_UF_Data(Me)
[NameOfUF].Hide
End Sub
And the Sub would look like:
Public Sub Save_UF_Data(frm As UserForm)
Debug.Print frm.Controls("Textbox1")
(...)
End Sub
Have a look to How to loop through all controls in a form, including controls in a subform - Access 2007 to learn how to access the controls of a form

Related

VBA - Hide certain column in every worksheet of workbook when checkbox is not selected

I am trying to hide every "A" column in my workbook when a certain checkbox in my user form is not selected.
I have 6 worksheets in my one workbook.
I have 6 checkboxes.
When a checkbox is not selected, I'd like to hide the column that it's associated with.
Ex: When the "Advice" checkbox is not checked, I'd like to hide the "A" column in EVERY worksheet in my workbook.
Thank you!
I tried this:
shtFinancial.Range("D").EntireColumn.Hidden = Not cbAdvice.Value
And this:
If cbAdvice.Value = True Then
shtFinancial.Range("D").EntireColumn.Hidden
Checkboxes in VBA are really funky. Here is one method:
Sub cbAdvice_Click()
Dim CheckBox As Shape, ws As Worksheet
Set CheckBox = Sheet1.Shapes("cbAdvice")
For Each ws In ActiveWorkbook.Worksheets
If CheckBox.OLEFormat.Object.Value = 1 Then
ws.Columns("A:A").EntireColumn.Hidden = False
Else
ws.Columns("A:A").EntireColumn.Hidden = True
End If
Next ws
End Sub
I created two active x control boxes "CheckboxColA" and "CheckboxColB" and gave them the following code for a change of state:
Sheet1("Worksheet Controls")
Private Sub CheckboxColA_Change()
Call changeColAVisiblity(CheckboxColA.Value, "A")
End Sub
Private Sub CheckBoxColB_Change()
Call changeColAVisiblity(CheckBoxColB.Value, "B")
End Sub
Then created the following code in "module1"
Sub changeColAVisiblity( _
cbState As Boolean, _
changeColumn As String)
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
'If statement Assumes sheet with contols should not change
If ws.Name <> "CheckBox Controls" Then
ws.Columns(changeColumn).Hidden = cbState
End If
Next
End Sub

Using a macro to sort data from instrumentation software

So I use an instrumentation software at work that outputs readings to a csv excel file. Because of the length of the test and the readings every 30 seconds, I accumulate a few thousand rows for every 24 hours of the test. When the test runs, it reads things that I don't need readings of so I have to go through the sheet manually and replace the "false" readings with zeros.
What I would like to do is use a command button to prompt the user to select a column to sort and apply a range of values so if it falls within that range, it returns the value to the cell and if it doesn't fall within the range, it returns a 0. I have done this with smaller sheets with extra columns (see attached file) but I'm not super familiar with Macros or VBA so I'm not sure where to get started.
Can anyone give me a hand?
This can be done as follows.
1) Go to Developer tab in the Excel ribbon. Click Insert, choose a Command Button (ActiveX Control) and place it onto the sheet where you want to have it.
2) Double-click the button, this will open up the editor. You should see:
Private Sub CommandButton1_Click()
End Sub
3) Add the line UserForm1.Show inside of this block of code. This should now look like:
Private Sub CommandButton1_Click()
UserForm1.Show
End Sub
4) Now we will create the userform. On the left side of the editor you will see a section called "Projects - VBA Project", in this list you should see your Workbook. Right click the name of your workbook and click Insert -> UserForm.
5) Use the toolbox to drag the correct components into the Userform. You are free to customize this form as you see fit to add or remove functionality based on your needs. I made mine look like this:
6) In the projects tab you will see your userform named UserForm1. Right click this userform and click "View Code". Paste the following code:
Private Sub CommandButton1_Click()
Unload UserForm1
End Sub
Private Sub UserForm_Initialize()
Dim lastColumn As Long
lastColumn = Worksheets("Sheet1").Cells(1,Columns.Count).End(xlToLeft).Column
For i = 1 To lastColumn
UserForm1.ComboBox1.AddItem (Worksheets("Sheet1").Cells(1, i))
Next
End Sub
Private Sub CommandButton2_Click()
Dim columnName As String
Dim columnIndex As Integer
Dim min As Double
Dim max As Double
If Not (ComboBox1.SelText = "" And TextBox1.Text = "" And TextBox2.Text = "") Then
columnName = ComboBox1.SelText
min = TextBox1.Text
max = TextBox2.Text
Dim lastColumn As Long
lastColumn = Worksheets("Sheet1").Cells(1, Columns.Count).End(xlToLeft).Column
For i = 1 To lastColumn
If Worksheets("Sheet1").Cells(1, i).Value = columnName Then
columnIndex = i
End If
Next
Dim cellValue As Double
Dim lastRow As Long
lastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
cellValue = Worksheets("Sheet1").Cells(i, columnIndex).Value
' MsgBox CStr(cellValue) + "--" + CStr(cellValue > min) + "--" + CStr(cellValue < max)
If Not (cellValue >= min And cellValue <= max) Then
Worksheets("Sheet1").Cells(i, columnIndex).Value = 0
End If
Next
End If
Unload UserForm1
End Sub
7) Change the component names such as CommandButton, ComboBox1, etc. to match your UserForm.
What does the code do?
Initializing: As soon as the UserForm is called it passes through the method UserForm_Initialize(). This method looks through your WorkSheet and determines the name of all the columns. It then adds these to the ComboBox.
Command Button 1: "Cancel", exits the UserForm without doing anything.
Command Button 2: "Confirm", this method goes to your selected column, checks within the desired range. If a value falls outside that range then it will set it to 0.
I hope this help!!

Add Module code of BeforeDoubleClick_event to dynamically created worksheets

I have this code:
For a = 1 To 5
strFoglio = "SheetName" & a
Sheets.Add
ActiveSheet.Name = strFoglio
ActiveSheet.Move after:=Sheets(Sheets.Count)
Next a
Is there a way to write code on these brand new sheets for example:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim myRange As Range
End sub
Naturally, I'd like to do directly in the For...Next loop and not manually.
The code below will run your For loop, create 5 sheets, and per sheet will call a Sub CodeCopy which will copy the code lines from a Module (in this example the code in "Sheet1") into the new created sheet.
Code
Option Explicit
Sub CreateSheets()
Dim a As Long
For a = 1 To 5
Sheets.Add
ActiveSheet.Name = "SheetName" & a
ActiveSheet.Move after:=Sheets(Sheets.Count)
Call CodeCopy(ActiveSheet.Name)
Next a
End Sub
' **********
Sub CodeCopy(DestShtStr As String)
' Macro to copy the macro module from sheet1 to a new Sheet
' Name of new sheet is passed to the Sub as a String
' Must install "Microsoft Visual Basic for Applications Extensibility library"
' from Tools > References.
Dim i As Integer
Dim SrcCmod As VBIDE.CodeModule
Dim DstCmod As VBIDE.CodeModule
' set source code module to code inside "Sheet1"
Set SrcCmod = ActiveWorkbook.VBProject.VBComponents(ActiveWorkbook.Worksheets("Sheet1").CodeName).CodeModule
Set DstCmod = ActiveWorkbook.VBProject.VBComponents(ActiveWorkbook.Worksheets(DestShtStr).CodeName).CodeModule
' copies all code line inside "Sheet1"
' can be modified to a constant number of code lines
For i = 1 To SrcCmod.CountOfLines
DstCmod.InsertLines i, SrcCmod.Lines(i, 1)
Next i
End Sub
Code in "Sheet1" that will be copied to all new created sheets is:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim myRange As Range
End Sub
Instructions
In order for this code to work, you need to allow the following 2 things:
Go to Tools >> References, and add a reference to "Microsoft Visual Basic for Applications Extensibility" library (screen-shot below)
In Excel Main menu, go to Developer Menu, then select Macro Security, the click V to allow "Trust access to the VBA project object model" (screen-shot below)
If i understand well, you want to create code directly on the new sheets created with your initial code.
So i would do like this :
Code(1) = Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Code(2) = Dim myRange As Range
Code(3) = '....
For i = 1 To 3
Wb.VBProject.VBComponents("SheetName & a").CodeModule.InsertLines i, Code(i)
Next i
(Just put it in loop)

VBA causing typed information to go to an incorrect worksheet

I am creating a spreadsheet that creates a reference number on the first worksheet (called database, to be used similarly to a database) and generates a new worksheet. This then gives a reference number on the new worksheet so that they are linked together. This is done by pressing "New Idea" on a UserForm.
Once this is completed it should then go to the newly created worksheet and highlight cell C7. Once this is complete it should close the UserForm and allow the user to be able to type in cell C7 on the new worksheet with no further steps needed.
This works fine if I use F8 to step through the process however if I close the code window and run through the process as a user would it doesn't work as it should.
C7 is highlighted but once you have typed in it and press enter to go to the cell below, what you've typed disappears completely, and whatever you type on the newly generated worksheet is actually entered on another worksheet.
I have a seperate worksheet that contains a button to open the UserForm and all data that is entered on the newly generated worksheet goes to this sheet incorrectly.
My code is below, and is all within the UserForm's code. I have left the ComboBox code below but this isn't relevant to the generation of the new worksheets. All that does is list the created tabs so the user can select a worksheet from the UserForm and go directly there rather than having to scroll sideways.
I'm using Excel 2013. I'm by no means a VBA veteran so any help would be greatly appreciated!
Thanks!
Private Sub UserForm_Initialize()
Me.ComboBox1.List = Worksheets("Database").Range("A2:A10000").Value
End Sub
Private Sub CreateNewIdea_Click()
CopySheet
End Sub
Sub CopySheet()
Dim LastRow As Long
NewReference
LastRow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row - 1
ReturnValue = LastRow
Sheets("Idea Template").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = LastRow
Range("C3").Value = LastRow
Me.ComboBox1.List = Worksheets("Database").Range("A2:A10000").Value
Range("C7").Select
Unload Home
End Sub
Sub NewReference()
Dim LastRow As Long
LastRow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Database").Cells(LastRow + 1, "A").Value = Sheets("Database").Cells(LastRow, "A").Value + 1
End Sub
Private Sub ComboBox1_Change()
Worksheets(ComboBox1.Text).Select
End Sub
I've taken the liberty to edit and rewrite the code you've written for greater flexibility.
Option Explicit 'Forces the variable to be declared, undeclared variables are not allowed
Dim DatabaseTable As ListObject 'Makes the variable usable for the entire module
Dim Lastrow As Long
Private Sub UserForm_Initialize()
Set DatabaseTable = ThisWorkbook.Worksheets("Database").ListObjects("References")
'I'm assuming you've formatted the data on the worksheet as a table and named the table "References"
Dim i As Long
Dim DatabaseRows As Long
DatabaseRows = DatabaseTable.ListRows.Count
With Me.ComboBox1
.Value = Empty
.Clear
For i = 1 To DatabaseRows
.AddItem DatabaseTable.DataBodyRange(i, 1)
Next i
End With
End Sub
Private Sub CreateNewIdea_Click()
Set DatabaseTable = ThisWorkbook.Worksheets("Database").ListObjects("References")
Call CopySheet
End Sub
Sub CopySheet() 'Are you calling Sub CopySheet() from other subs besides Private Sub CreateNewIdea_Click()?
Call NewReference
Dim ReturnValue As Long 'I'm declaring this variable because I'm using the option explicit and that doesn't allow undeclared variables
ReturnValue = Lastrow 'Unless ReturnValue is a public variable, it's not doing much here.
ThisWorkbook.Worksheets("Idea Template").Copy After:=ThisWorkbook.Worksheets(Worksheets.Count)
ThisWorkbook.Worksheets("Idea Template (2)").name = Lastrow
ThisWorkbook.Worksheets(CStr(Lastrow)).Cells(1, 3).Value = Lastrow 'Cstr(lastrow) is needed because we want the sheet with the name of the last row, not the nth sheet which is what happens with WorkSheets(Lastrow) as lastrow is a number
Call UserForm_Initialize 'Calls the procedure which fills ComboBox1, if the unload home refers to this form, then this line is redundant since the combobox is filled again when the form is initialized.
ThisWorkbook.Worksheets(CStr(Lastrow)).Cells(7, 3).Select
Unload Home 'If the name of this form is home, you can just 'Unload Me'
End Sub
Sub NewReference() 'Are you calling Sub NewReference from other subs besides Sub CopySheet()?
DatabaseTable.ListRows.Add AlwaysInsert:=False 'Adds a new row to the table on the worksheet "Database"
Lastrow = DatabaseTable.ListRows.Count
If Lastrow = 2 And IsEmpty(DatabaseTable.DataBodyRange(1, 1)) Then 'This if determines if a row was added while the first row does not contain a reference
DatabaseTable.DataBodyRange(Lastrow, 1).Value = 1 'First reference, can be anything you want really
DatabaseTable.ListRows(1).Delete 'First row is deleted, otherwise you'd have an empty first row
Lastrow = Lastrow - 1
Else
DatabaseTable.DataBodyRange(Lastrow, 1).Value = DatabaseTable.DataBodyRange(Lastrow - 1, 1) + 1
End If
End Sub
Private Sub ComboBox1_Change()
If Not Me.ComboBox1 = Empty Then
Worksheets(CStr(Me.ComboBox1)).Select
End If
End Sub
Revised answer
After looking at the document provided by #tomjo and trying to reporduce the problem I found that the problem was caused by the buttons on the sheets. The buttons used were the Form Controls rather than ActiveX Controls.
A macro was assigned to the Form Control The macro was defined in a module as you'd expect. The Macro only called to show the relevant form. It appeared as if the selected sheet, either by the menu on the form or after creating a new sheet from the form wasn't properly activated and the information entered in the sheet that showing was actually entered in the form which was last manually selected. Stepping through the code I found that the proper sheet and cell was active after the selection through the form through Debug.Print ThisWorkbook.ActiveSheet.Name, ThisWorkbook.ActiveSheet.ActiveCell.Address. I failed to discover why, while the correct sheet and cell were active, the information was entered in the last manually selected worksheet and cell.
To verify that the issue was not caused by the file somehow I tried to reproduce the problem with an entirely new file. Again the problem occurred that while the screen was showing the correct sheet and cell as selected (selected through a form, called by a sub in a module, called by a Form Control) the information was actually entered in the last manually selected sheet and cell.
----Edit----
Running the Showform macro (which calls the form to show) from the Macros button under the developer tab in the ribbon, instead of clicking the Form control button which has the ShowForm macro assigned to it, doesn't create the issue.
----End of Edit----
I then only removed the Form control, and the sub in the module which calls to show the form and placed an ActiveX Control (CommandButton) on the sheet and on the relevant Sheet module created:
Private Sub CommandButton1_Click()
Form.Show
End Sub
Without editing the code any further, there were no further issues regarding information being entered on the last manually selected sheet and cell instead of the sheet and cell the screen was showing as selected.
Edited file (The link will be active for a limited time)

Macro to copy and/or move selected sheets to a new workbook

Can someone please help me with a macro? I want to move and/or copy a few selected sheets (hidden & visible) to a new workbook, but since I have a few workbooks open at a time, I want to be able to select worksheets in all open workbooks from like a drop down menu and move and/or copy to a new workbook. I want to move some and copy some worksheets so will need both options in selection box.
Please help as I have cracked my head on it and got nowhere.
I have tried the below:
Sub CopySheet()
Dim i As Integer, x As Integer
Dim shtname As String
'i = Application.InputBox("Copy how many times?", "Copy sheet", Type:=1)
'For x = 0 To i - 1
ActiveSheet.Copy After:=Sheets(Sheets.Count)
shtname = InputBox("What's the new sheet name?", "Sheet name?")
ActiveSheet.Name = shtname
'Next x
End Sub
But this will mean I have to type every sheet name every time.
Adam: While I try to run your code, it gives me an error - variable not specified in row Private Sub btnSubmit_Click()
How do I overcome it?
I still can't get it right Adam. I am very new to Macros and I may be doing something wrong with interpreting your instructions. Can you please suggest something like all included in one and run?
Where exactly in the original codes do I need to paste this code
Private Sub btnSubmit_Click()
End Sub
This code should get you going. It is all of the code-behind for a UserForm with two listboxes, a checkbox, and a command button for submit. The dropdowns are populated automatically depending on what workbooks are open and what worksheets these workbooks contain. It also has the option to move or copy the selected worksheet. However, you still will need to add the functionality for copying the sheet multiple times, but that will just be a loop, and shouldn't be too difficult.
'All of this code goes in the section which appears when you right click
'the form and select "View Code"
Option Explicit
Public Sub OpenWorksheetSelect()
Dim WorksheetSelector As New frmWorksheetSelect
WorksheetSelector.Show
End Sub
Private Sub lstWorkbooks_Change()
FillWorksheetList
End Sub
Private Sub UserForm_Initialize()
FillWorkbookList
End Sub
Sub FillWorkbookList()
'Add each workbook to the drop down
Dim CurrentWorkbook As Workbook
For Each CurrentWorkbook In Workbooks
lstWorkbooks.AddItem CurrentWorkbook.Name
Next CurrentWorkbook
End Sub
Sub FillWorksheetList()
Dim WorkbookName As String
WorkbookName = lstWorkbooks.Text
If Len(WorkbookName) > 0 Then
Dim CurrentWorksheet As Worksheet
For Each CurrentWorksheet In Workbooks(WorkbookName).Sheets
lstWorksheets.AddItem CurrentWorksheet.Name
Next CurrentWorksheet
End If
End Sub
Private Sub btnSubmit_Click()
Dim WorkbookName As String, WorksheetName As String
WorkbookName = lstWorkbooks.Text
WorksheetName = lstWorksheets.Text
If Len(WorkbookName) > 0 And Len(WorksheetName) > 0 Then
If chkCopy = True Then
Workbooks(WorkbookName).Sheets(WorksheetName).Copy Before:=Workbooks.Add.Sheets(1)
Else
Workbooks(WorkbookName).Sheets(WorksheetName).Move Before:=Workbooks.Add.Sheets(1)
End If
End If
Unload Me
End Sub