Is VBA function possible without using the clipboard; make all sheets values only - vba

I have the following function using Excel 2010:
Private Function MakeAllSheetsValuesOnly(targetBookName As String)
If Excel.ActiveWorkbook.Name = Excel.ThisWorkbook.Name Then
Else
Excel.Workbooks(targetBookName).Activate
Dim mySheet
For Each mySheet In Excel.ActiveWorkbook.Sheets
With mySheet
With .Cells
.Copy
.PasteSpecial Excel.xlPasteValues
End With
.Select
.Range("A1").Select
End With
Excel.ActiveWindow.SmallScroll Down:=-200
Excel.Application.CutCopyMode = False
Next mySheet
End If
End Function 'MakeAllSheetsValuesOnly
It works but I'd rather not rely on the clipboard is there an alternative way to make all sheets values only?
Just found an alternative logic I've been using in another program which is relevent to this topic:
Dim rSource As Range
Dim rDest As Range
Set rSource = .Range("C5:BG" & .Range("B4").Value + 4)
Set rDest = mySummaryBook.Sheets("Data_Measures").Cells(Rows.Count, 4).End(xlUp)(2, 1)
With rSource
Set rDest = rDest.Resize(.Rows.Count, .Columns.Count)
End With
rDest.Value = rSource.Value
Set rSource = Nothing
Set rDest = Nothing

Maybe something like this:
With mySheet.UsedRange
.Value = .Value
End With

You don't need a function for this.
Tim has already given you a great method. Here is another way...
Sub Sample()
MakeAllSheetsValuesOnly "Book2"
End Sub
Private Sub MakeAllSheetsValuesOnly(targetBookName As String)
Dim mySheet As Worksheet
Dim formulaCell As Range
Dim aCell As Range
Application.ScreenUpdating = False
For Each mySheet In Workbooks(targetBookName).Sheets
On Error Resume Next
Set formulaCell = mySheet.Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not formulaCell Is Nothing Then
For Each aCell In formulaCell
aCell.Value = aCell.Value
Next
End If
Next mySheet
Application.ScreenUpdating = True
End Sub

Building on Tim's answer above, which seems to be the most efficient way to do it, you could clean up your code to make it a little faster, less resource intensive. See below. Not huge changes, but will help with processing none-the-less. First don't need Function. Sub will do. No need to select and activate so many things:
Private Sub MakeAllSheetsValuesOnly(targetBookName As String)
If ActiveWorkbook.Name <> ThisWorkbook.Name Then
Dim wkb As Workbook
Set wkb = Workbooks(targetBookName)
With wkb
Dim mySheet As Worksheet
For Each mySheet In wkb.Worksheets
mySheet.UsedRange.Value = mySheet.UsedRange.Value
Next mySheet
End With
End If
End Sub 'MakeAllSheetsValuesOnly

Related

Excel-VBA macro to transform cell content into a comment of another cell

I have a seemingly simple goal to turn the content of column B into comments of column A.
I have tried using the following code from #Dy.Lee mentioned here, but unfortunately it gives me a Run-time error '1004' Application-defined or object-defined error...
Sub Komentari()
Dim rngDB As Range, rngComent As Range
Dim rng As Range
Dim cm As Comment, i As Integer
Set rngComent = Range("A1:A50")
Set rngDB = Range("B1:B50")
For Each rng In rngComent
i = i + 1
If Not rng.Comment Is Nothing Then
rng.Comment.Delete
End If
Set cm = rng.AddComment
With cm
.Visible = False
.Text Text:=rngDB(i).value
End With
Next rng
End Sub
Can somebody, please, spot the mistake or suggest a better solution for this?
I'd go this way (explanations in comments):
Public Sub Komentari()
Dim rng As Range
With Range("A1:A50") ' reference comments range
.ClearComments ' clear its comments
For Each rng In .Offset(, 1).SpecialCells(xlCellTypeConstants) ' loop through refrenced range adjacent not empty cells
With rng.Offset(, -1).AddComment ' add comment to current rng corresponding comment range cell
.Visible = False
.Text rng.Value2
End With
Next
End With
End Sub
Sub Komentari()
Dim rngDB As Range, rngComent As Range
Dim rng As Range
Dim cm As Comment, i As Integer
Set rngComent = Range("A1:A50")
For Each rng In rngComent
i = i + 1
If Not rng.Range("B1").Comment Is Nothing Then
rng.Range("B1").Comment.Delete
End If
rng.Range("B1").AddComment (rng.Text)
Next rng
End Sub
Something like the following where you can use Offset to get the adjacent range, you drop the = when adding the text value to the comment, test that there is actually a value present first as well, and ensure you state the sheet to avoid implicit Activesheet reference.
Option Explicit
Public Sub Komentari()
Dim rngComent As Range
Dim rng As Range, cm As Comment
With ThisWorkbook.Worksheets("Sheet1")
Set rngComent = .Range("A1:A50")
For Each rng In rngComent
If Not rng.Comment Is Nothing Then
rng.Comment.Delete
End If
Set cm = rng.AddComment
With cm
.Visible = False
If rng.Offset(, 1) <> vbNullString Then .Text rng.Offset(0, 1).Value
End With
Next
End With
End Sub
Rather than add blank comments you could also flip this round to:
Option Explicit
Public Sub Komentari()
Dim rngComent As Range
Dim rng As Range, cm As Comment
With ThisWorkbook.Worksheets("Sheet1")
Set rngComent = .Range("A1:A50")
For Each rng In rngComent
If Not rng.Comment Is Nothing Then
rng.Comment.Delete
End If
If rng.Offset(, 1) <> vbNullString Then
Set cm = rng.AddComment
With cm
.Visible = False
.Text rng.Offset(0, 1).Value
End With
End If
Next
End With
End Sub

Deleting specific sheets and those which do not meet a criteria

I have a macro where I create a number of sheets that take their names from the values in column c, cell 7 onwards in a sheet called "Schedule". I am using the following code for that
Sub CreateDataSheets()
'Updateby Extendoffice 20161215
Dim xRg As Variant
Dim wSh As Excel.Worksheet
Dim wBk As Excel.Workbook
Set wSh = ActiveSheet
Set wBk = ActiveWorkbook
Application.ScreenUpdating = False
For Each xRg In wSh.Range("C7", Range("C7").End(xlDown))
If Not IsError(xRg) Then
If xRg <> "" Then
If Not WorksheetExists((xRg)) Then
With wBk
.Sheets.Add after:=.Sheets(.Sheets.Count), Type:="L:\London\General\Reference & Tools\Software\BIM\IiA_Specifications\Excel\Uk Specification Template.xltx"
ActiveSheet.Name = xRg.Value
End With
End If
End If
End If
Next xRg
Application.ScreenUpdating = True
End Sub
Now I need another Macro where if I change or delete any of these values in Column C, I want to create new updated ones and delete all the sheets that are redundant. While doing this, I want to retain the sheets called Schedule, Home and CoverSheet. Below is the code I tried to write but that would not work.
Sub DeleteNewSheets()
Dim ws As Worksheet
Dim ArrayOne() As Variant
Dim wsName As Variant
Dim Matched As Boolean
Dim DirArray As Variant
DirArray = Range("C7:C11")
ArrayOne = Array("Home", "Schedule", "CoverSheet", DirArray.Value)
Application.DisplayAlerts = False
For Each ws In Sheets
Matched = False
For Each wsName In ArrayOne
If wsName = ws.Name Then
Matched = True
Exit For
End If
Next
If Not Matched Then
ws.Delete
End If
Next ws
Application.DisplayAlerts = True
End Sub
Would really appreciate any ideas...
DirArray is beeing created as a Variant and the position 4 of your Array ArrayOne is actually another array and not a string.
To fix it, initialize the ArrayOne just like this:
ArrayOne = Array("Home", "Schedule", "CoverSheet")
Dim Name As Variant
For Each Name In DirArray
If Name <> "" Then
ReDim Preserve ArrayOne(UBound(ArrayOne) + 1)
ArrayOne(UBound(ArrayOne)) = Name
End If
Next
It will also not consider empty values on the range you selected.
Consider changing your removing steps as on Sam's answer
Iterating over a changing set is often a bad idea. Do something like this instead
For i = Sheets.Count to 1 Step -1
If ....
Sheets(i).Delete
End If
Next i

Embed Chart Template into Macro

I am trying to embed applying a chart template into a macro and require help.
I have this code for the Macro that I am using to create scatter plots:
Option Explicit
Public Sub Test()
' Keyboard Shortcut: Ctrl+Shift+X
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Sheet1") 'change as appropriate
Application.ScreenUpdating = False
BuildChart ws, SelectRanges(ws)
Application.ScreenUpdating = True
End Sub
Private Function SelectRanges(ByRef ws As Worksheet) As Range
Dim rngX As Range
Dim rngY As Range
ws.Activate
Application.DisplayAlerts = False
On Error Resume Next
Set rngX = Application.InputBox("Please select X values. One column.",
Type:=8)
If rngX Is Nothing Then GoTo InvalidSelection
Set rngY = Application.InputBox("Please select Y values. One column.",
Type:=8)
If rngY Is Nothing Then GoTo InvalidSelection
If rngX.Columns.Count > 1 Or rngY.Columns.Count > 1 Then GoTo
InvalidSelection
On Error GoTo 0
Set SelectRanges = Union(rngX, rngY)
Application.DisplayAlerts = True
Exit Function
InvalidSelection:
If rngX Is Nothing Or rngY Is Nothing Then
MsgBox "Please ensure you have selected both X and Y ranges."
ElseIf rngX.Rows.Count <> rngX.Rows.Count Then
MsgBox "Please ensure the same number of rows are selected for X and Y
ranges"
ElseIf rngX.Columns.Count > 1 Or rngY.Columns.Count > 1 Then
MsgBox "Please ensure X range has only one column and Y range has only
one column"
Else
MsgBox "Unspecified"
End If
Application.DisplayAlerts = True
End
End Function
Private Sub BuildChart(ByRef ws As Worksheet, ByRef unionRng As Range)
With ws.Shapes.AddChart2(240, xlXYScatter).Chart
.SetSourceData Source:=unionRng
End With
ActiveChart.ApplyChartTemplate ( _
"C:\Users\maaro\AppData\Roaming\Microsoft\Templates\Charts\1.crtx")
End Sub
And would like to embed this code below into the above code so that it applies the template to the chart I create whenever I run this Macro. My initial guess would be to put it underneath "Private Sub BuildCharts". How would I be able to do this? Thank you.
ActiveChart.ApplyChartTemplate ( _
"C:\Users\XXXXX\AppData\Roaming\Microsoft\Templates\Charts\1.crtx")
Perhaps modify Sub BuildChart like this:
Private Sub BuildChart(ByRef ws As Worksheet, ByRef unionRng As Range)
With ws.Shapes.AddChart2(240, xlXYScatter).Chart
.SetSourceData Source:=unionRng
.ApplyChartTemplate ( _
"C:\Users\maaro\AppData\Roaming\Microsoft\Templates\Charts\1.crtx")
End With
End Sub

using match funtion for 2 different workbooks

i have been assigned to use the .match function in vba, to compare 2 different columns in 2 different workbooks.
here is my code so far.. how do i use the match function to my goal ?
Sub Ob_match()
Dim swb As Workbook, dwb As Workbook
Dim sws As Worksheet, dws As Worksheet
Dim oCell As Range, oMatch As Range
Set swb = ActiveWorkbook
Set sws = swb.Sheets("Item")
Set dwb = Workbooks.Open(swb.Path & "\EPC_EndItem.xlsm", ReadOnly:=True)
Set dws = dwb.Sheets("Data")
If Not oMatch Is Nothing Then
oCell.Offset(0, 1) = "Y"
Else
oCell.Offset(0, 1) = ""
End If
Next oCell
MsgBox "Processing completed"
End Sub
To run this code you should be on your your first workbook and second work-book should be open in background, I find this as an easier method than to call workbook using it's address, you may change that if you like
Sub vl()
Dim lastrow As Long
Sheets("Items").Select
lastrow = Range("B" & Rows.Count).End(xlUp).Row
Range("C2:C" & lastrow).Formula = "=IF(VLOOKUP(RC2,[Book2]Data!C4,1,FALSE), ""OK"","""")"
End Sub
Here I assumed that Name of your second book is Book2.
Change it to whatever it is in the code.
Hope this helps :)

Display message when cell is empty

Currently I managed to do for a single cell when the specified cell is empty then message / statement display on the cell.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("AA17").Value = ISBLANK Then
Range("AA17").Value = "Please Specify"
End If
End Sub
What I would like to do is, for a several cell it will display the same thing. I can go ahead and do the same as above for all celsl but I have a few hundred cell to format it that way.
Is there a way to do so?
If the cells are contiguous, you could loop through them.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim checkRng As Range
Dim cel As Range
Set checkRng = Range("A7:A70")
For Each cel In checkRng
If cel.Value = ISBLANK Then
cel.Value = "Please Specify"
End If
Next cel
End Sub
if there is any changes within the specified Range, the below code will run
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Rng As Range
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.ActiveSheet
Set Rng = ws.Range("A1:A100")
If Not Intersect(Target, Rng) Is Nothing Then
For Each Cell In Rng
If IsEmpty(Cell.Value) = True Then
Cell.Value = "Please Specify"
End If
Next
End If
Set Rng = Nothing
Set ws = Nothing
Set wb = Nothing
End Sub