I have been trying to add borders to two ranges on two different worksheets.
In my case, sheet one has 14 rows whereas the second worksheet has 30 rows. Each worksheet has the same amount of columns. When I run my code, the first worksheet works fine but the second worksheet only has 14 rows that are bordered and the other 16 are left without a border. Why isn't my code bordering the last 16 columns of my second worksheet?
Sub lines()
Dim wb As Worksheet
Dim wb2 As Worksheet
Dim arrBorders As Variant, vBorder As Variant
Set wb = Worksheets("wb Summary")
Set wb2 = Worksheets("wb2 Summary")
arrBorders = Array(xlEdgeLeft, xlEdgeTop, xlEdgeBottom, _
xlEdgeRight, xlInsideVertical, xlInsideHorizontal)
With wb.Range("A2:H" & Cells(Rows.Count, "H").End(xlUp).Row)
For Each vBorder In arrBorders
With .Borders(vBorder)
.LineStyle = xlContinuous
.Weight = xlThin
End With
Next
End With
With wb2.Range("A2:H" & Cells(Rows.Count, "H").End(xlUp).Row)
For Each vBorder In arrBorders
With .Borders(vBorder)
.LineStyle = xlContinuous
.Weight = xlThin
End With
Next
End With
End Sub
You need to fully reference the sheets. I think you can also shorten your code by avoiding the loops.
Sub lines()
Dim wb As Worksheet
Dim wb2 As Worksheet
Set wb = Worksheets("wb Summary")
Set wb2 = Worksheets("wb2 Summary")
With wb.Range("A2:H" & wb.Cells(wb.Rows.Count, "H").End(xlUp).Row)
.Borders.LineStyle = xlContinuous
.Borders.Weight = xlThin
End With
With wb2.Range("A2:H" & wb2.Cells(wb2.Rows.Count, "H").End(xlUp).Row)
.Borders.LineStyle = xlContinuous
.Borders.Weight = xlThin
End With
End Sub
Related
I have a spreadsheet with recipients name in column A, recipients email in column B and mulitple others columns with the information to be emailed to these recipients. Each recipient has multiple rows, and the number of rows per recipient varies each time. The number of recipients also varies.
What I would like to do is create only one email for each recipient and include the other data columns relevant to that recipient as a table at the end of the body of the email. All emails would have the same text in the body of the email which would be stored in the code and not in the spreadsheet.
Any help would be appreciated. This is my first time dealing with outlook through Excel VBA.
Thanks
Add a reference to outlook library in VBA (in the toolbar ->Tools->References-Microsoft Outlook)
Recipients would be the filter (if the email is going to the same person, just stick all the thing that you want to say to him/her), so, why not to do a filter prior to get them in order in the first place?
After adding the reference, you are going to be available to use outlook commands, create instances, etc. There are many google examples, this one may be a good one to start with.
This is my suggested workflow
Thanks Sgdva. That was a good hint. I also used some code from Ron de Bruin to come up with the following solution.
This sub sets up my data and is not very relevant for the answer, but might be of use to someone.
Sub Related_BA()
Dim wb As Workbook
Dim ws As Worksheet
Dim filename As Variant
Dim returnVAlue As Variant
Dim BAwb As Workbook
Dim BAws As Worksheet
Dim BArng As Range
Dim LastRow As Integer
Dim i As Integer
Set wb = ActiveWorkbook
Set ws = wb.Worksheets("Super User Report")
filename = Application.GetOpenFilename(filefilter:="Excel Files (*xls), *xls", Title:="Please select BA refernce file")
If filename = False Then Exit Sub
ws.Range("A:B").EntireColumn.Insert
Set BAwb = Application.Workbooks.Open(filename)
Set BAws = BAwb.Worksheets("Sheet1")
Set BArng = BAws.ListObjects("DepartmentBA").DataBodyRange
With ws.Cells(1, 1)
.Value = "BA"
.HorizontalAlignment = xlCenter
.Font.Bold = True
End With
With ws.Cells(1, 2)
.Value = "BA Email"
.HorizontalAlignment = xlCenter
.Font.Bold = True
End With
LastRow = ws.Range("C1").CurrentRegion.Rows.Count
On Error Resume Next
For i = 2 To LastRow
ws.Cells(i, 1) = Application.WorksheetFunction.VLookup(ws.Cells(i, 6), BArng, 2, 0)
Next i
On Error Resume Next
For i = 2 To LastRow
ws.Cells(i, 2) = Application.WorksheetFunction.VLookup(ws.Cells(i, 6), BArng, 3, 0)
Next i
BAwb.Close False
ws.Columns("A:B").EntireColumn.AutoFit
ws.Range("B2").CurrentRegion.Sort key1:=ws.Range("B2"), order1:=xlAscending, _
key2:=ws.Range("C2"), order2:=xlAscending, Header:=xlYes
Call SendEmail
ws.Range("A:B").EntireColumn.Delete
End Sub
This formats the data for the email and calls the email function. I still might need code to handle #N/A from the vlookup.
Sub SendEmail()
Dim cBA As Collection
Dim rng As Range
Dim cell As Range
Dim wb As Workbook
Dim ws As Worksheet
Dim vNum As Variant
Dim lRow As Integer
Set wb = ActiveWorkbook
Set ws = wb.Worksheets("Super User Report")
lRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set rng = ws.Range("A2:A" & lRow)
Set cBA = New Collection
On Error Resume Next
For Each cell In rng.Cells
cBA.Add cell.Value, CStr(cell.Value)
Next cell
On Error GoTo 0
On Error Resume Next
cBA.Remove ("None")
Worksheets("Super User Report").AutoFilterMode = False
For Each vNum In cBA
rng.AutoFilter Field:=1, Criteria1:=vNum
Call Email(vNum)
rng.AutoFilter Field:=1
Next vNum
End Sub
This sube actually creates and sends the email.
Sub Email(BA As Variant)
Dim wb As Workbook
Dim ws As Worksheet
Dim lRow As Integer
Dim StrBody As String
Dim rng As Range
Dim OutApp As Object
Dim OutMail As Object
Dim Mnth As Variant
Dim Yr As Variant
StrBody = "This is line 1" & "<br>" & _
"This is line 2" & "<br>" & _
"This is line 3" & "<br><br><br>"
Mnth = Format(Month(Date), "mmmm")
Yr = Year(Date)
Set wb = ActiveWorkbook
Set ws = wb.Worksheets("Super User Report")
lRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set rng = Nothing
On Error Resume Next
'Only the visible cells in the selection
Set rng = ws.Range("C1:L" & lRow).SpecialCells(xlCellTypeVisible)
'You can also use a fixed range if you want
'Set rng = Sheets("YourSheet").Range("D4:D12").SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If rng Is Nothing Then
Exit Sub
End If
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
rng.Borders(xlDiagonalDown).LineStyle = xlNone
rng.Borders(xlDiagonalUp).LineStyle = xlNone
With rng.Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
With rng.Borders(xlEdgeTop)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
With rng.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
With rng.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
With rng.Borders(xlInsideVertical)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
With rng.Borders(xlInsideHorizontal)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
Mnth = Format(Month(Date), "mmmm")
Yr = Year(Date)
On Error Resume Next
With OutMail
.To = BA
.CC = ""
.BCC = ""
.Subject = "Monthly Super User Report " & Mnth & " " & Yr
.HTMLBody = StrBody & RangetoHTML(rng)
.Display 'or use .Send
End With
On Error GoTo 0
rng.Borders(xlDiagonalDown).LineStyle = xlNone
rng.Borders(xlDiagonalUp).LineStyle = xlNone
rng.Borders(xlEdgeLeft).LineStyle = xlNone
rng.Borders(xlEdgeTop).LineStyle = xlNone
rng.Borders(xlEdgeBottom).LineStyle = xlNone
rng.Borders(xlEdgeRight).LineStyle = xlNone
rng.Borders(xlInsideVertical).LineStyle = xlNone
rng.Borders(xlInsideHorizontal).LineStyle = xlNone
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
This function is referenced in the sub above.
Function RangetoHTML(rng As Range)
Dim fso As Object
Dim ts As Object
Dim TempFile As String
Dim TempWB As Workbook
TempFile = Environ$("temp") & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"
'Copy the range and create a new workbook to past the data in
rng.Copy
Set TempWB = Workbooks.Add(1)
With TempWB.Sheets(1)
.Cells(1).PasteSpecial Paste:=8
.Cells(1).PasteSpecial xlPasteValues, , False, False
.Cells(1).PasteSpecial xlPasteFormats, , False, False
.Cells(1).Select
Application.CutCopyMode = False
On Error Resume Next
.DrawingObjects.Visible = True
.DrawingObjects.Delete
On Error GoTo 0
End With
'Publish the sheet to a htm file
With TempWB.PublishObjects.Add( _
SourceType:=xlSourceRange, _
filename:=TempFile, _
Sheet:=TempWB.Sheets(1).Name, _
Source:=TempWB.Sheets(1).UsedRange.Address, _
HtmlType:=xlHtmlStatic)
.Publish (True)
End With
'Read all data from the htm file into RangetoHTML
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
RangetoHTML = ts.readall
ts.Close
RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _
"align=left x:publishsource=")
'Close TempWB
TempWB.Close savechanges:=False
'Delete the htm file we used in this function
Kill TempFile
Set ts = Nothing
Set fso = Nothing
Set TempWB = Nothing
End Function
I hope this is useful to someone.
I am trying to code this procedure to highlight all rows of which have a value of "N" in their respective row within Column N
I am not too familiar with coding VBA formatting and I cannot get this procedure to function
Sub highlight_new_pos()
Dim rng As Range, lCount As Long, LastRow As Long
Dim cell As Object
With ActiveSheet 'set this worksheet properly!
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In .Range("N2:N" & LastRow)
If cell = "N" Then
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Next cell
End With
End Sub
Option Explicit
Sub highlight_new_pos()
Dim cel As Object
With ActiveSheet
For Each cel In .Range("N2:N" & .Cells(.Rows.Count, 14).End(xlUp).Row)
If UCase(cel.Value2) = "N" Then cel.Interior.Color = 65535
Next
End With
End Sub
This will be faster if you have a lot of rows:
Sub highlight_new_pos1()
Application.ScreenUpdating = False
With ActiveSheet
With .Range("N1:N" & .Cells(.Rows.Count, 14).End(xlUp).Row)
.AutoFilter Field:=1, Criteria1:="N"
.Offset(1, 0).Resize(.Rows.Count - 14, .Columns.Count).Interior.Color = 65535
.AutoFilter
End With
End With
Application.ScreenUpdating = True
End Sub
In your code, you are looping through the cells, but you're still changing the color of the initial selection (not of the cell in the loop). Adjust as follows:
Sub highlight_new_pos()
Dim rng As Range, lCount As Long, LastRow As Long
Dim cell As Object
With ActiveSheet 'set this worksheet properly!
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In .Range("N2:N" & LastRow)
If cell = "N" Then
With cell.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
End if
Next cell
End With
End Sub
If you want the entire row, change cell.Interior to cell.entirerow.Interior
I'm pretty new to VBA and I need a piece of code to apply in the same way to some work sheets in my workbook.
The name of the worksheets I need the code to be applied are as follows:
Analysis Flow Racking % Refill
Analysis Flow Racking 1 Picks
Analysis Line Cupboards %Refill
Analysis Line Cupboards by Pick
Analysis PFB
Analysis Cupboards % Refill
Analysis Cupboards by Picks
Analysis Flow Racking 2 Picks
The code is found below:
Any help that you can provide will be much appreciated. Many thanks
Sub AddCheckBox()
Application.ScreenUpdating = False
Dim cell As Range
DelCheckBox 'Do the delete macro
'or delete all checkboxes in the worksheet
' ActiveSheet.CheckBoxes.Delete
ActiveWindow.View = xlNormalView
lastRow = ActiveSheet.Range("B" & ActiveSheet.Rows.Count).End(xlUp).Row
For Each cell In Range("A5:A" & lastRow)
With ActiveSheet.CheckBoxes.Add(cell.Left, _
cell.Top, cell.Width, cell.Height)
.LinkedCell = cell.Offset(, 8).Address(External:=True)
'.Interior.ColorIndex = 37 'or xlNone or xlAutomatic
.Caption = ""
'.Border.Weight = xlThin
End With
Next
With Range("A5:A" & lastRow)
.Rows.RowHeight = 15
Worksheets("Analysis Flow Racking % Refill ").CheckBoxes.Select
Selection.ShapeRange.Align msoAlignCenters, msoFalse
Selection.ShapeRange.IncrementLeft 50
Range("A10000").Select
End With
ActiveWindow.View = xlPageLayoutView
Application.ScreenUpdating = True
End Sub
Give this a shot:
Sub Driver()
Dim ws as Worksheet
'Since your worksheet names are somewhat variable,
'I'd suggest passing an array of known names from a driver routine to your worker routine.
For each ws in Worksheets(Array("Analysis Flow Racking % Refill", _
"Analysis Flow Racking 1 Picks", _
"Analysis Line Cupboards %Refill"))
'continue with the rest of your worksheets here...
AddCheckBox ws
Next
'If however, you're processing all the worksheets in the workbook, then this will be easier
For each ws in ActiveWorkbook.Sheets
AddCheckBox ws
Next
End Sub
You will now need to modify your AddCheckBox() routine to accept the worksheet as a parameter:
Sub AddCheckBox(ByVal TheSheet as Worksheet)
Application.ScreenUpdating = False
DelCheckBox 'Do the delete macro
'or delete all checkboxes in the worksheet
' ActiveSheet.CheckBoxes.Delete
ActiveWindow.View = xlNormalView
Dim LastRow as integer 'always declare your variables!
lastRow = ActiveSheet.Range("B" & ActiveSheet.Rows.Count).End(xlUp).Row
Dim cell As Range
For Each cell In TheSheet.Range("A5:A" & lastRow)
With TheSheet.CheckBoxes.Add(cell.Left, _
cell.Top, cell.Width, cell.Height)
.LinkedCell = cell.Offset(, 8).Address(External:=True)
'.Interior.ColorIndex = 37 'or xlNone or xlAutomatic
.Caption = ""
'.Border.Weight = xlThin
End With
Next
'Note: removed WITH from here - it only effected 1 row and was confusing
TheSheet.Range("A5:A" & lastRow).Rows.RowHeight = 15
''''''''''''''''''''''''''''''
TheSheet.CheckBoxes.Select
Selection.ShapeRange.Align msoAlignCenters, msoFalse
Selection.ShapeRange.IncrementLeft 50
Range("A10000").Select
'
'I believe that this code can be replaced with this:
TheSheet.Checkboxes.ShapeRange.Align msoAlignCenters msoFalse
TheSheet.Checkboxes.ShapeRange.IncrementLeft 50
''''''''''''''''''''''''''''''
ActiveWindow.View = xlPageLayoutView
Application.ScreenUpdating = True
End Sub
In column A on sheet 1 there are 3000 cells that I need copied at 350 cells each. My current Macro is copying everything just fine until I get to the end and it copies blanks. Is there a way to include a "cell is blank do nothing" code into my macros?
Sorry if this sounds uneducated, I'm just starting on learning macro.
Here is a copy of the current macro, the rest of the macro is the same as this just with increasing numbers by 350.
Sub Copy_Bins_1_350()
If Range("D12").Value <> "!" Then
Exit Sub
ElseIf Range("D12").Value = "!" Then
Sheets("sheet1").Select
Range("B2:B351").Select
Selection.Copy
Range("B2").Select
Sheets("sheet2").Select
Range("E12").Select
With Selection.Font
.ColorIndex = xlAutomatic
.TintAndShade = 0
End With
End If
End Sub
You can use Union to form your own range of non empty cells and then copy them.
Also INTERESTING READ
Try this (TRIED AND TESTED)
Sub Sample()
Dim wsI As Worksheet, wsO As Worksheet
Dim aCell As Range, rngCopyFrom As Range, rng As Range
Dim lRow As Long
Set wsI = ThisWorkbook.Sheets("BIN LIST PASTE")
Set wsO = ThisWorkbook.Sheets("BIN LIST COPY")
Set rng = wsI.Range("B2:B351")
For Each aCell In rng
If Len(Trim(aCell.Value)) <> 0 Then
If rngCopyFrom Is Nothing Then
Set rngCopyFrom = aCell
Else
Set rngCopyFrom = Union(rngCopyFrom, aCell)
End If
End If
Next
If Not rngCopyFrom Is Nothing Then _
rngCopyFrom.Copy wsO.Range("E12")
With wsO
lRow = .Range("E" & .Rows.Count).End(xlUp).Row
Set rng = .Range("E12:E" & lRow)
With rng.Font
.ColorIndex = xlAutomatic
.TintAndShade = 0
End With
End With
End Sub
I am having a small amount of trouble with finding a possible solution to a potential problem of mine. I am writing a macro for my supervisor using VBA so that she can just click a button assigned to this macro and follow the directions and get the data she needs. The issue I'm running into is when the macro pastes the data, it has trouble deleting empty cells if the user selects multiple columns.
Sub DataPull()
' Written by Agony
' Data Pull macro
Dim rng1 As Range
Dim rng2 As Range
Dim chc1
Dim chc2
Dim wb1 As Workbook
Dim wb2 As Workbook
'Choose file to get data
chc1 = Application.GetOpenFilename("Excel Files (*.xls*), *.xls*", _
, "Please select file to pull data from")
If chc1 = False Then Exit Sub
'Choose file to paste data
chc2 = Application.GetOpenFilename("Excel Files (*.xls*), *.xls*", _
, "Please select file to paste data to")
If chc2 = False Then Exit Sub
'Open first file and copy range
Set wb1 = Workbooks.Open(chc1)
Set rng1 = Application.InputBox("Select cells to transfer", "Selection", "Use your mouse/pointer to select the cells", Type:=8)
rng1.Copy
wb1.Close SaveChanges:=False
'Open second file and paste with specs
Set wb2 = Workbooks.Open(chc2)
Set rng2 = Range("A1")
rng2.PasteSpecial
With Selection.Interior
.Pattern = xlNone
.TintAndShade = 0
.PatternTintAndShade = 0
End With
With Selection.Font
.Name = "Cambria"
.Size = 12
.TintAndShade = 0
End With
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
Selection.Borders(xlEdgeBottom).LineStyle = xlNone
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
'Loop to delete empty cells
Dim i As Long
Dim rows As Long
Dim rng3 As Range
Set rng3 = ActiveSheet.Range("A1:Z50")
rows = rng3.rows.Count
For i = rows To 1 Step (-1)
If WorksheetFunction.CountA(rng3.rows(i)) = 0 Then rng3.rows(i).Delete
Next
wb2.Activate
MsgBox ("Macro Complete")
End Sub
As above shows, the range is currently tentative. I would like the function to delete cells that are empty if the user selects a range with multiple columns. I've tried using Len for the cells, but that doesn't seem to work either. Any help is greatly appreciated. Thanks!
I don't think you can use the .Copy and .Paste when the source workbook is closed.
I think that whatever you're copying gets lost when the workbook is closed.
So a possible solution to your problem would be to close the wb1 at the end of your macro and not immediately after the copy command.
So move wb1.Close SaveChanges:=False to after this block
...
'Open second file and paste with specs
Set wb2 = Workbooks.Open(chc2)
Set rng2 = Range("A1")
rng2.PasteSpecial
With Selection.Interior
.Pattern = xlNone
.TintAndShade = 0
.PatternTintAndShade = 0
End With
With Selection.Font
.Name = "Cambria"
.Size = 12
.TintAndShade = 0
End With
wb1.Close SaveChanges:=False ' moved it here
...
Deletetion
Try this sub see if this is what you want. What this does it finds the last column used in spreadsheet and last row in each column. Iterates back from the last row in each column and deletes all empty cells shifting the filled cells up.
Sub DeleteAllAtOnce()
Application.ScreenUpdating = False
Dim lastColumn As Long
Dim lastRow As Long
lastColumn = ActiveSheet.UsedRange.Columns.Count
Dim i As Long, j As Long
Dim cell As Range
For i = lastColumn To 1 Step -1
lastRow = Cells(rows.Count, i).End(xlUp).Row
For j = lastRow To 1 Step -1
Set cell = Cells(j, i)
If IsEmpty(cell) Then cell.Delete shift:=xlUp
Next j
Next i
Application.ScreenUpdating = True
End Sub