I have a worksheet with macros and buttons. I want to copy that worksheet to other workbooks so that the macros can be used with the data in the new workbook.
My problem is that when I copy a sheet into a new workbook, the macros come with it, but the button on the sheet still points to the macros in the original workbook. You have to right mouse click "Assign Macro" and choose the macro in the current workbook.
Is there a property setting that tells the button in Excel to use the macro in the new workbook instead of the old workbook?
Here's a solution I pulled from TheSpreadsheetGuru. I modified it to accept a sheet object so you can run it against any sheet you have a handle on.
Public Sub FixCopiedButtonMacroLinks(ByVal theSheet As Worksheet)
' UPDATED: by HackSlash to accept a worksheet parameter.
'PURPOSE: Remove an external workbook reference from all shapes triggering macros
'Source: www.TheSpreadsheetGuru.com
Dim control As Shape
Dim MacroLink As String
Dim SplitLink As Variant
Dim NewLink As String
'Loop through each shape in worksheet
For Each control In theSheet.Shapes
'Grab current macro link (if available)
MacroLink = control.OnAction
'Determine if shape was linking to a macro
If MacroLink <> vbNullString And InStr(MacroLink, "!") <> 0 Then
'Split Macro Link at the exclaimation mark (store in Array)
SplitLink = Split(MacroLink, "!")
'Pull text occurring after exclaimation mark
NewLink = SplitLink(1)
'Remove any straggling apostrophes from workbook name
If Right(NewLink, 1) = "'" Then
NewLink = Left(NewLink, Len(NewLink) - 1)
End If
'Apply New Link
control.OnAction = NewLink
End If
Next control
End Sub
You can include a line in your macro that re-assigns the control to the macro in its own workbook instead of the originating workbook.
What you can do is just record the act of assigning the macro, for example:
ActiveSheet.Shapes.Range(Array("Button 1")).Select
Selection.OnAction = "Macro1"
Then get rid of the pesky "select" stuff:
ActiveSheet.Shapes.Range(Array("Button 1")).OnAction = "Macro1"
And there you have it. Of course the button and macro names with vary depending on your workbook, but it will be close to that.
Your question is somewhat vague. I will then guess.
You have to:
Make sure that the Subs to be run are actually contained in the Worksheet to be copied. Press Alt+F11 to open the VB Editor, and you will see on the left the Sheet and other modules.
Inspect the code, and make sure all references to macros are not prefixed with any Sheet/Workbook name.
Related
I have a large macro I am amending for my purpose. The writer of the macro was more skilled than me. The macro at present runs formulas on data gathered from websites and other spreadsheets.
All I want to do is to have "Red Flagged" ranges copied and pasted into a the same new workbook. Can this be done without having to save the new work book?
Here was my initial idea:
Sub CreateNewWB()
With Application
.SheetsInNewWorkbook = 1
.Workbooks.Add
.Sheets(1).Name = "Late"
End With
Set ptrToLate = Application.ActiveSheet.FullName
' MsgBox ("This workbook has name" & Application.ActiveWorkbook.Name)
'MsgBox ("This workbook has Full name" & Application.ActiveWorkbook.FullName)
' MsgBox ("This workbook has path name" & Application.ActiveWorkbook.Path)
' MsgBox ("This workbook has Code name" & Application.ActiveWorkbook.CodeName)
End Sub
At the very top of the VBA code I had put
Dim ptrToLate as String
with the intentions of being able to copy and paste using the new workbooks name as a destination, but I get the error: "Object doesnt support this property or method"
1) Is there a way to append to an unsaved workbook?
2)presently the codename of the new workbook is "thisWorkbook" this confuses me because I thought that thisworkbook referred to the workbook the macros itself is written in
Thank you in advance for your help
All you need to do is set the new workbook to an object and then you can reference it without the path. The variable wrkb will now reference your destination new workbook.
Dim wkb As Workbook
'Adding New Workbook
Set wrkb = Workbooks.Add(1) 'this creates anew workbook with only 1 sheet
wrkb.Sheets(1).Name = "Late"
Workbook("Red Flagged.xlsx").Sheets("redflagged").Range("A1:D2").Copy wrkb.Sheets("Late").Range("A1")
To the question in the title: VBA when pasting into separate workbook must I save the workbook to get the path first?
The answer is YES
If you open a new workbook and write this in the VBEditor, you would see that there would an empty MsgBox. If you save it and then run the code again, the path would be shown:
Public Sub TestMe()
MsgBox ThisWorkbook.Path
End Sub
In a User form using a Listbox1 I would like to make a list of the Opened Workbooks and in the Listbox2 in the same form the sheets of the selected workbook in the listbox1 But also in the lisbox2 I would like to create with each sheet name a checkbox with five command buttons in the form to import, Export, Erase, Hide or Unhide the selected sheets from Wb1 to Wb2 and vice versa.
So far I receive assistance from you guys to make a do a form with a list of opened workbooks and a list of the respective worksheets here also I'm trying to get to work a code to import the sheets from one workbook to another here,. Do you know a Way to make this happen.
thank You
By the way this is the code use from a sheet to erase the sheets that might be put in the list
Sub DeleteSheets()
Dim wks As Worksheet
Dim MyRange As Range
Dim cell As Range
Set wks = Worksheets("Controls")
With wks
Set MyRange = Range("D5:D34", .Cells(.Rows.Count, "H").End(xlUp))
End With
On Error Resume Next
Application.DisplayAlerts = False
For Each cell In MyRange
Sheets(cell.Value).Delete
Next cell
Application.DisplayAlerts = True
On Error GoTo 0
Sheets("Controls").Range("D5:D34").ClearContents
End Sub
And this ones for hide and unhide the sheets:
Sub Hide_Sheets()
'In use
'Hide the sheets in Controls Sheet
Dim cell As Range
On Error Resume Next
For Each cell In Sheets("Controls").Range("E5:E34")
' Hide sheets
Sheets(cell.Value).Visible = False
Next cell
End Sub
Sub Unhide_Sheets()
'In use
'Unhide the sheets in Controls Sheet
Dim cell As Range
On Error Resume Next
For Each cell In Sheets("Controls").Range("G5:G34")
' Hide sheets
Sheets(cell.Value).Visible = True
Next cell
End Sub
I suggest the following structure of your userform:
Since you do what two lists one with workbooks and one with the worksheets of the currently selected workbook. Then you want to have five command buttons for the actions you want to perfom.
In order to update the workbooks and worksheets you will want to place code in the userform inside the Userform_activate and Listbox1_Change events. So You get the code to list all the workbook names into the listbox1 and put it into Userform_Activate. Evertime the userform is activated the list of workbooks will be updated.
If you now select a entry of listbox1 you want the code to update your sheet names. So you get the code to update the sheet names of a workbook with name "wbname" and put it into listbox1_Change. You then do the following code:
Private Sub ListBox1_Change()
Dim wbname as string
wbname=ListBox1.Value
call GetSheetNamesIntoListBox2(wbname)
End Sub
Where of course GetSheetNamesIntoListBox2 is the sub were you get all the sheetnames into ListBox2.
Lastly you need to setup the Buttons. Each Button has a Click Event which you will want to use. So if the Button is clicked the following code will run:
Private Sub CommandButton1_Click()
Dim wbname as string, wsname as string
wbname=Listbox1.Value
wsname=Listbox2.Value
' You may want to check if wbname and wsname are valid before running the Task
PerformAction(wbname,wsname)
End Sub
Where PerformAction is the routine you use to import, export, clear, hide or unhide the sheet.
I know it is no workedout solution but you will be able to adjust this general solution to your specific case. If you run into problems using my approach just ask in the comments.
I am very new to VBA coding and don't have very good understanding of what I am doing to be honest. But here I go.
I am looking to see if:
Can VBA codes have dyname values? So instead of the code saying execute on a set sheet (e.g "Sheet1") that value changes depending a value in a certain cell.
To trigger a VBA on another workbook. For example I want to run a VBA from Workbook A that triggers a VBA on Workbook B.
To fully explain I want to open Workbook A (and Workbook B if needed, it doesn't matter) and click a button that runs a VBA on Workbook B but on a certain Sheet depending on the value of a cell in Excel A (if the cell says "sheet3" the VBA runs on "sheet3" on Workbook B). I also want cells in Workbook A to reference cells in Workbook B but the the sheet name to by dynamic. For example I have pasted the basic cell reference bellow but instead of having Sheet1 I want it to change depending on the value in a cell.
='[Workbook B.xlsx]Sheet1'!$A$4
I know this sounds very complicates and confusing, but if I could get any help that would be greatly appreciated.
Sub ReportStepOne()
Dim myRow As Long
myRow = 4
Rows(myRow).Value = Rows(myRow).Value
Dim rng As Range
Set rng = Range("A4:AC200")
rng.Cut rng.Offset(1, 0)
Range("A1:AC1").Copy Range("A4:AC4")
End Sub
I want to:
edit this code to make it fire on a certain sheet
make it so the sheet name is referenced to whatever is in cell A o Sheet2 in Report.xlsm.
Run a macro in Report.xlsm that runs the above script (which is called "StepOne" in a file called "Historical Data.xlsm"
The code below takes the value of cell A4 on sheet2 in Reports.xlsm and sets the ws variable to the sheet in Historical data.xlsm which is then used for the rest of the code. If possible I'd advise against having your subs spread out over multiple projects but that is just my opinion. I think it is easier to use proper referencing like below.
Since you want a button trigger on the Report.xlsm I'd suggest moving this code to that workbook. If properly referenced it you can open, edit, save and close any workbook from a single project which again, in my opinion is easier than calling subs in a different project.
Sub ReportStepOne()
Dim wbHis As Workbook, wbRep As Workbook
Dim strWsName As String
Dim ws As Worksheet
Set wbHis = Workbooks("Historical data.xlsm")
Set wbRep = Workbooks("Reports.xlsm")
strWsName = wbRep.Worksheets("Sheet2").Cells(4, 1)
Set ws = wbHis.Worksheets(strWsName)
With ws
With .Rows(4)
.Value = .Value
End With
With .Range("A4:AC200")
.Cut .Offset(1, 0)
End With
.Range("A1:AC1").Copy .Range("A4:AC4")
End With
End Sub
To trigger a VBA on another workbook
Option Explicit
Sub RunVBA()
Dim xlApp As Excel.Application
Dim xlWorkBook As Workbook
Set xlApp = New Excel.Application
Set xlWorkBook = xlApp.Workbooks.Open("C:\Users\Om3r\Desktop\Book1.xlsm")
xlApp.Visible = True
xlWorkBook.Application.Run "Module1.SubName" ' Modulename.Subname
End Sub
To reference worksheet use
Sub CopyRange()
'// From sheet1 to sheet2
Worksheets(2).Range("A1").Value = Worksheets(1).Range("A1").Value
End Sub
I have written data in a cell that is updated by a macro - it appends a reference depending on what somebody has called a new sheet.
In Cell A1 I end up with macro code that is updated with the new sheet name. Currently users have to copy this text and open another macro and paste the code in, however they keep doing it wrong and breaking it.
What I would like to do is write a macro to copy the contents of Cell A1 and paste them into the original macro.
If it possible to do this?
Based on a suggestion at the MrExcel.com forum:
Sub aaa()
For i = 1 To Application.VBE.CodePanes.Count
Application.VBE.CodePanes(i).CodeModule.ReplaceLine 1, "alert('Yo') ' New code"
Next i
I know this is not an answer to your question but I'm just offering some information. I would suggest that you don't have users create a macro in each sheet. You can access anything on any sheet from a module. I am not sure what you whole process is but you could think of it more along the lines of looking for the sheets you want to change.
Public sub ProcessSheets()
Dim ws As Excel.Worksheet
Dim iIndex As Integer
'Loop through all the worksheets in the workbook.
For iIndex = 1 To ActiveWorkbook.Worksheets.count
'Activate the current sheet, if you need to.
Set ws = Worksheets(iIndex)
ws.Activate
'Check the name of the worksheet.
If Left(ws.Name, 2) = "HD" or Left(ws.Name, 2) = "ER" Then
'Call the function that changes the worksheet here.
'Maybe feed it the worksheet name.
UpdateWorksheet ws.Name
End if
Next iIndex
End Sub
In Excel 2007, I have a sheet with a list of other Excel documents, all of which have their own VBA. My code opens the first workbook on the list, lets its vba run, then when it has completed, marks it as complete, and opens the next workbook in the list.
All this works fine unless I let one of the other workboks close itself with 'thisworkbook.close'. This stops the VBA running in the original workbook, as well as itself. If I comment this line out, it all works, but I would rather keep just the master workbook and one sub workbook open at one time.
Also, it is unpractical in this case to move all the VBA to the master workbook.
The code before is a highly simplified version to show the issue:
Workbook1's code:
Sub RunReports()
Dim wkb1 As Workbook
Dim wks1 As Worksheet
Dim lngR As Long
Dim strReport As String
Set wkb1 = ThisWorkbook
Set wks1 = wkb1.Sheets(strDay)
For lngR = 4 To 1048576
strReport = wks1.Cells(lngR, 1).Value
'open the report. Its own VBA will take care of everything else
Workbooks.Open strReport
'mark the report as complete
wks1.Cells(lngR, 2).Value = "done"
Next lngR
End Sub
the code in the worksheets that are opened:
Private Sub Workbook_Open()
ThisWorkbook.Sheets("Sheet1").Cells(1, 1).Value = Now()
ThisWorkbook.Save
Application.Wait (Now() + TimeValue("00:00:05"))
ThisWorkbook.Close
End Sub
If I comment out 'thisworkbook.close', it will open them all, update the time they were opened, and save them. If not, it does everything up to the first 'thisworkbook.close', closes the first sub workbook, and stops all VBA execution.
Does anyone have any ideas how to keep the "master" workbook's vba code running after the "sub" workbook's code has finished, when the 'sub' workbook's code contains a 'thisworkbook.close' (edited to make the question clear)
Use standard COM ways of doing things. Take a reference to each workbook (not excel.application) using GetObject(filename). Do what you want then don't close it in sub book, but set the reference to nothing in your master (which happens when you do set exceldoc = nothing or reach an End Function/Sub). Don't do both as that's voodoo programming.