Excel Macro: Copy sheet without links - just data - vba

I would like to copy one specific sheet in MS Excel to a new file. The following Macro does the job, but the problem is that the copy always links the cells to the original file. Is there a way to insert only the values of this sheet without the links?
Sub Copy_sheet()
ThisWorkbook.Sheets("Overview").Copy
ActiveWorkbook.SaveAs "C:\testfolder\testfile.xlsx", FileFormat:=51
End Sub
Thank you!

Add the following to your code before the End sub:
With ThisWorkbook.Worksheets("Overview").UsedRange
.Value = .Value
End With
It would change the formulas to values. If you want to do it for the whole workbook, this is the way to go:
Public Sub CopyJustData()
Dim lngCount As Long
For lngCount = 1 To Worksheets.Count
With Worksheets(lngCount).UsedRange
.Value = .Value
End With
Next lngCount
End Sub

One way is this.
Sub Copy_sheet()
Dim wbNew As Workbook
ThisWorkbook.Sheets("Overview").Copy
Set wbNew = ActiveWorkbook
With wbNew
With .Worksheets(1).UsedRange
.Value = .Value
End With
.SaveAs "C:\testfolder\testfile.xlsx"
End With
End Sub

Sub SaveCopy
ThisWorkbook.Sheets("your sheet name").Select
ActiveSheet.Copy
ActiveSheet.SaveAs FileName:="your path to save "& ".xlsx" 'xlsx or your other
BreakLinks '
End Sub
Sub BreakLinks()
On Error Resume Next
Dim vLinks As Variant
Dim lLink As Long
' Define variable as an Excel link type.
vLinks = ActiveWorkbook.LinkSources(Type:=xlLinkTypeExcelLinks)
If vLinks = vbNullString Then Exit Sub
' Break all links in the active workbook.
For lLink = LBound(vLinks) To UBound(vLinks)
ActiveWorkbook.BreakLink _
Name:=vLinks(lLink), _
Type:=xlLinkTypeExcelLinks
Next lLink
End Sub

Related

How to use VBA to duplicate a sheet and then rename it (all in one sub)?

I am able to rename the activesheet using the following code but need to combine this with (first) duplicating the original sheet:
Sub CopySheet()
Dim strName As String
strName = InputBox("Budget2")
If strName = "" Then
Beep
Exit Sub
End If
ActiveSheet.Copy
ActiveSheet.Name = strName
End Sub
Per the documentation for the Worksheet.Copy method, using it without specifying either the Before or After argument will create a new Workbook, containing only that Worksheet.
So, to add a copy of the ActiveSheet after the ActiveSheet in the same Workbook, you can just change ActiveSheet.Copy to ActiveSheet.Copy After:=ActiveSheet
Make sure you check if the new sheet name already exists.
Make sure you keep track of where the copied sheet appears eg. after the source sheet SourceSheet.Copy After:=SourceSheet so you can pick up it's index which is 1 after the source sheet's: Set NewSheet = ThisWorkbook.Sheets(SourceSheet.Index + 1).
Finally make sure to catch errors on renaming if user entered not allowed characters or too long sheet names.
So you would end up with something like:
Option Explicit
Public Sub CopySheet()
Dim InputName As String
InputName = Application.InputBox("Budget2", Type:=2) '2 = text: https://learn.microsoft.com/en-us/office/vba/api/excel.application.inputbox#remarks
' user pressed cancel or entered nothing
If (VarType(InputName) = vbBoolean And InputName = False) Or InputName = vbNullString Then
Beep
Exit Sub
End If
' check if new sheet name already exists
On Error Resume Next
Dim TmpWs As Object
Set TmpWs = ThisWorkbook.Sheets(InputName)
On Error GoTo 0
If Not TmpWs Is Nothing Then
MsgBox "The Sheet '" & InputName & "' already exists", vbCritical
Exit Sub
End If
Dim SourceSheet As Object
Set SourceSheet = ActiveSheet
SourceSheet.Copy After:=SourceSheet
Dim NewSheet As Object
Set NewSheet = ThisWorkbook.Sheets(SourceSheet.Index + 1)
On Error GoTo ERR_RENAME
NewSheet.Name = "InputName"
On Error GoTo 0
Exit Sub
ERR_RENAME:
MsgBox "Sheet could not be renamed.", vbCritical
Err.Clear
End Sub

Attempting to step through columns in a search

I am attempting to create a module in Excel 2016 that will scan through a sheet and auto size any comments found. My current code requires me to adjust the Column Letter each time I run it. I am looking for a method to step through the columns in my loop. My current code is listed below and I am thanking anyone ahead of time for any assistance I can get. My current sheet only uses columns A through P.
Sub cmtsize()
ActiveSheet.Unprotect pswd
Range("a7:I7").Select
lrow = Cells(Rows.Count, 1).End(xlUp).Row
For xrow = 7 To lrow
xcell = "c" & lrow
Range(xcell).Select
If ActiveCell.Comment Is Nothing Then
GoTo nxt
Else
With Range(xcell).Comment.Shape
.TextFrame.AutoSize = True
End With
nxt:
End If
Next xrow
ActiveSheet.Protect pswd
Range("A6").Select
MsgBox "Finished!"
End Sub
This will resize all comments on the specified worksheet. [Update] included option for password protected sheets. As well as the Finished Msgbox.
Sub test()
Call ResizeComments(Sheet1)
MsgBox ("Finished!")
End Sub
Private Sub ResizeComments(ByVal ws As Worksheet, Optional ByVal Pass As String = "")
If Pass <> "" Then ws.Unprotect Pass
Dim oComment As Comment
For Each oComment In ws.Comments
oComment.Shape.TextFrame.AutoSize = True
Next
If Pass <> "" Then ws.Protect Pass
End Sub

Deactivate entire sheet selection after paste

I recently asked a question and received a great answer on this site, but I am now running into a different problem. The code below works well for running through each workbook in a folder, copying a sheet's contents, and pasting those contents into a master workbook exactly how I would like:
Sub ConslidateWorkbooks()
'Code to pull sheets from multiple Excel files in one file directory
'into master "Consolidation" sheet.
Dim FolderPath As String
Dim Filename As String
Dim Sheet As Worksheet
Dim wbName As String
With ActiveSheet
Range("A1").Activate
End With
Application.ScreenUpdating = False
FolderPath = ActiveWorkbook.Path & "\"
Filename = Dir(FolderPath & "*.xls*")
wbName = ActiveWorkbook.Name
Do While Filename <> ""
If Filename <> wbName Then
Workbooks.Open Filename:=FolderPath & Filename, ReadOnly:=True
For Each Sheet In ActiveWorkbook.Sheets
copyOrRefreshSheet ThisWorkbook, Sheet
Next Sheet
Workbooks(Filename).Saved = True
Workbooks(Filename).Close
ActiveSheet.Range("A1").Activate
End If
Filename = Dir()
Loop
Application.ScreenUpdating = True
End Sub
Sub copyOrRefreshSheet(destWb As Workbook, sourceWs As Worksheet)
Dim ws As Worksheet
On Error Resume Next
Set ws = destWb.Worksheets(sourceWs.Name)
On Error GoTo 0
If ws Is Nothing Then
sourceWs.Copy After:=destWb.Worksheets(destWb.Worksheets.Count)
Else
ws.Unprotect Password:="abc123"
ws.Cells.ClearContents
sourceWs.UsedRange.Copy
ws.Range(sourceWs.UsedRange.Address).PasteSpecial (xlPasteAll)
Application.CutCopyMode = False
End If
End Sub
The problem I am having now: After the paste is completed, each sheet in the master workbook has all of its cells selected, as though I Ctrl+A'd the entire sheet. I would like to get rid of this. It is a small task which I tried to accomplish in the line ActiveSheet.Range("A1").Activate within the Do While .. loop, but it has not worked for me.
EDIT:
I found a solution that works in this case. I am not sure why this was necessary, because the comments and answers in this thread seem like they should work, but they did not. I call this sub before I turn screenupdating to True in the main sub:
Sub selectA1()
Worksheets(1).Activate
Dim Sheet As Worksheet
For Each Sheet In ActiveWorkbook.Sheets
Sheet.Activate
ActiveWindow.ScrollRow = 1
ActiveWindow.ScrollColumn = 1
Sheet.Range("A1").Select
Next Sheet
Worksheets(1).Activate
End Sub
I realize this is more complicated than it should be, but it works for my purposes.
In your copy sub, add in another code in the loop that will select a cell which should deactivate the total used range selection and just select the coded range.
Sub copyOrRefreshSheet(destWb As Workbook, sourceWs As Worksheet)
Dim ws As Worksheet
On Error Resume Next
Set ws = destWb.Worksheets(sourceWs.Name)
On Error GoTo 0
If ws Is Nothing Then
sourceWs.Copy After:=destWb.Worksheets(destWb.Worksheets.Count)
Else
ws.Unprotect Password:="abc123"
ws.Cells.ClearContents
sourceWs.UsedRange.Copy
ws.Range(sourceWs.UsedRange.Address).PasteSpecial (xlPasteAll)
ws.range("A1").select
Application.CutCopyMode = False
End If
End Sub
I added ws.range("A1").select which should do as I described above.

how to retain the clipboard data after changing workbooks in vba?

i have a program that copies a range of cells and the needs to paste the contents into a new workbook that is created in code. i can copy the data but somehow the clipboard loses its data whenever i change workbooks to the new one created. i considered copying the cells to an array and then just copying the array to the new workbook but i wont know the size of the array at coding time this varies almost every time the macro runs.
how do i then keep the data on the clipboard while i change the active workbook?
cell = "k7: l" & row
Worksheets(1).Range(cell).Select
Selection.Copy
relpath = ThisWorkbook.Path & "\" & "DispersionList.xls"
If Dir(relpath) <> "" Then
Application.Workbooks.Open (relpath)
Workbooks("DispersionList.xls").Activate
Else
Call createWorkbook
End If
Worksheets(1).Cells(7, 14).Select
Selection.PasteSpecial
End Sub
if i run through the code line by line and check the clipboard it loses its contents at the workbooks.open line
There are a few actions in Excel/VBA that will void the selection/clipboard, e.g. changing any window/display settings. Thus, I suspect there is some event being called when you change the worksheet/workbook.
You can either debug it and while stepping through the code figure out, when the selection is voided and avoid this statement (if possible).
Alternatively, use subStoreClipboard and subRestoreClipboard from below code in your event code. To use the code, insert it in a new module in your worksheet - and also insert a new (hidden) worksheet which is named "ws_Temp" in VBA.
Private mIntCutCopyMode As XlCutCopyMode
Private mRngClipboard As Range
Public Sub subStoreClipboard()
On Error GoTo ErrorHandler
Dim wsActiveSource As Worksheet, wsActiveTarget As Worksheet
Dim strClipboardRange As String
mIntCutCopyMode = Application.CutCopyMode
If Not fctBlnIsExcelClipboard Then Exit Sub
Application.EnableEvents = False
'Paste data as link
Set wsActiveTarget = ActiveSheet
Set wsActiveSource = ThisWorkbook.ActiveSheet
With ws_Temp
.Visible = xlSheetVisible
.Activate
.Cells(3, 1).Select
On Error Resume Next
.Paste Link:=True
If Err.Number Then
Err.Clear
GoTo Finalize
End If
On Error GoTo ErrorHandler
End With
'Extract link from pasted formula and clear range
With Selection
strClipboardRange = Mid(.Cells(1, 1).Formula, 2)
If .Rows.Count > 1 Or .Columns.Count > 1 Then
strClipboardRange = strClipboardRange & ":" & _
Mid(.Cells(.Rows.Count, .Columns.Count).Formula, 2)
End If
Set mRngClipboard = Range(strClipboardRange)
.Clear
End With
Finalize:
wsActiveSource.Activate
wsActiveTarget.Parent.Activate
wsActiveTarget.Activate
ws_Temp.Visible = xlSheetVeryHidden
Application.EnableEvents = True
Exit Sub
ErrorHandler:
Err.Clear
Resume Finalize
End Sub
Public Sub subRestoreClipboard()
Select Case mIntCutCopyMode
Case 0:
Case xlCopy: mRngClipboard.Copy
Case xlCut: mRngClipboard.Cut
End Select
End Sub
Private Function fctBlnIsExcelClipboard() As Boolean
Dim var As Variant
fctBlnIsExcelClipboard = False
'check if clipboard is in use
If mIntCutCopyMode = 0 Then Exit Function
'check if Excel data is in clipboard
For Each var In Application.ClipboardFormats
If var = xlClipboardFormatCSV Then
fctBlnIsExcelClipboard = True
Exit For
End If
Next var
End Function

Run macro on all files open in taskbar one by one

My work is regarding formating 100 of files everyday. though i have a macro desined for the purpose but i have to run the macro on each and every file one after saving previous.
my question is how can i be able to run my macro on these opened workbooks in one step. As i save one it would run on other one in the queue.
Put the following macro in a "BASE" workbook as Passerby mentioned
Sub SO()
Dim macroList As Object
Dim workbookName As String
Dim wbFullPath
Dim macroName As String
Dim currentWb As Workbook
Dim masterWb As Workbook ' the Excel file you are calling this procedure from
Dim useWbList As Boolean
Dim height As Long, i As Long
Dim dataArray As Variant
useWbList = False ' DEFINE which input method
Set macroList = CreateObject("Scripting.Dictionary")
If useWbList Then
' you can also from the dictionary from 2 columns of an excel file , probably better for management
With masterWb.Worksheets("Sheet1") '<~~ change Sheet1 to the sheet name storing the data
height = .Cells(.Rows.Count, 1).End(xlUp).Row ' Assume data in column A,B, starting from row 1
If height > 1 Then
ReDim dataArray(1 To height, 1 To 2)
dataArray = .Range(.Cells(1, 1), .Cells(height, 2)).Value
For i = 1 To height
macroList.Add dataArray(i, 1), dataArray(i, 2)
Next i
Else
'height = 1 case
macroList.Add .Cells(1, 1).Value, .Cells(1, 2).Value
End If
End With
Else
' ENTER THE FULl PATH in 1st agrument below, Macro Name in 2nd argument
' Remember to make sure the macro is PUBLIC, try to put them in Module inside of Sheets'
macroList.Add "C:\Users\wangCL\Desktop\Book1.xlsm", "ThisWorkbook.testing"
'macroList.Add "FULL PATH", "MACRO NAME"
'macroList.Add "FULL PATH", "MACRO NAME"
'macroList.Add "FULL PATH", "MACRO NAME"
End If
Application.DisplayAlerts = False
For Each wbFullPath In macroList.keys
On Error GoTo 0
macroName = macroList.Item(workbookName)
workbookName = Mid(wbFullPath, InStrRev(wbFullPath, "\") + 1)
Err.Clear
On Error Resume Next
Set currentWb = Nothing
Set currentWb = Workbooks(workbookName) ' see if the workbook is already open
If Err.Number <> 0 Then
' open the workbook if workbook NOT opened
Set currentWb = Workbooks.Open(workbookName, ReadOnly:=True)
End If
On Error GoTo 0
' run the macro
Application.Run workbookName & "!" & macroList.Item(wbFullPath)
'close the workbook after running the macro
currentWb.Close saveChanges:=False
Set currentWb = Nothing
Next wbFullPath
End Sub
Hope it helps and please let me know if there's anything unclear
I have got my solve using below code.
Sub OpenAllWorkbooksnew()
Set destWB = ActiveWorkbook
Dim DestCell As Range
Dim cwb As Workbook
For Each cwb In Workbooks
**Call donemovementReport**
ActiveWorkbook.Close True
ActiveWorkbook.Close False
Next cwb
End Sub