Excel VBA code for Process Mapping - vba

I have to create process maps in excel often and am trying to cut down on the excessive time it takes. instead of creating each shape and entering or pasting the text into the shape, with often 100 + steps. I am trying to write a code that will create a shape with the text from column D and will continue to do so until there is no text in the cell in column A. I have been able to create code to create the shapes but I cannot seem to have the text populate correctly in the separate blocks. Below is the code I have so far:
Sub addshapewithtext()
Dim BlankFound As Boolean
Dim x As Long
Dim w As Worksheet
Dim s As Shape
Dim t As Variant
Do While BlankFound = False
x = x + 1
Set t = Cells(x, "d")
Set w = ActiveSheet
Set s = w.Shapes.addshape(msoShapeFlowchartProcess, 200 + x * 200, 100, 100, 100)
'format shape
s.Fill.ForeColor.RGB = RGB(300, 300, 300)
s.Line.ForeColor.RGB = RGB(0, 0, 0)
s.Line.Weight = 3
'transparency
s.Fill.Transparency = 0
'add text from list
s.OLEFormat.Object.Formula = t
If Cells(x, "A").Value = "" Then
BlankFound = True
End If
Loop
End Sub
thank you for your help

Change s.OLEFormat.Object.Formula = t to s.OLEFormat.Object.Text = t
You may want to add in font size and color for the text in your shape as well
REVISED TO ADD
I went ahead and tweaked the procedure slightly and tested it:
Sub addshapewithtext()
Dim BlankFound As Boolean
Dim x As Long
Dim w As Worksheet
Dim s As Shape
Dim t As Variant
x = 1
Do Until Cells(x, "A").Value = ""
Set t = Cells(x, "d")
Set w = ActiveSheet
Set s = w.Shapes.AddShape(msoShapeFlowchartProcess, 200 + x * 200, 100, 100, 100)
'format shape
s.Fill.ForeColor.RGB = RGB(300, 300, 300)
s.Line.ForeColor.RGB = RGB(0, 0, 0)
s.Line.Weight = 3
'transparency
s.Fill.Transparency = 0
'add text from list
s.OLEFormat.Object.Text = t
If Cells(x, "A").Value = "" Then BlankFound = True
x = x + 1
Loop
End Sub

The code from the answer before me works great, but the text does not show because it's white.
To show the text in the process blocks you can give them a color with:
s.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 0)
Code:
Sub addshapewithtext()
Dim BlankFound As Boolean
Dim x As Long
Dim w As Worksheet
Dim s As Shape
Dim t As Variant
x = 1
Do Until Cells(x, "A").Value = ""
Set t = Cells(x, "d")
Set w = ActiveSheet
Set s = w.Shapes.AddShape(msoShapeFlowchartProcess, 200 + x * 200, 100, 100, 100)
'format shape
s.Fill.ForeColor.RGB = RGB(300, 300, 300)
s.Line.ForeColor.RGB = RGB(0, 0, 0)
s.Line.Weight = 3
'Add color to text in process block
s.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(0, 0, 0)
'transparency
s.Fill.Transparency = 0
'add text from list
s.OLEFormat.Object.Text = t
If Cells(x, "A").Value = "" Then BlankFound = True
x = x + 1
Loop
End Sub

Related

VBA quick way to paint thousands of cells from array of addresses

I have a sheet with ~300 lines and 30 columns of numbers. I need to paint cells as a result of processing SelectionChange event. Performance is imporant as issue of usability.
First way is to take a Range object for every cell I'm going to highlight:
For x = 1 To 30: For y = 1 To lastNonemptyRow
If someClause(CInt(Cells(rowIdx, colIdx).Value)) Then
Range(Cells(rowIdx, colIdx).Value).Interior.Color = Rgb(255, 0, 0)
End If
Next y: Next x
This way is quite slow even with disabled ScreenUpdating.
Second way is to make a string with set of addresses:
addressesToHighlight = ""
For x = 1 To 30: For y = 1 To lastNonemptyRow
If someClause(CInt(Cells(rowIdx, colIdx).Value)) Then
addressesToHighlight = addressesToHighlight & Cells(rowIdx, colIdx).Address & ", "
End If
Next y: Next x
Range(addressesToHighlight).Interior.Color = Rgb(255, 0, 0)
This way gives error when there is 42 or more cells to highlight.
Third way is to create a range as union of two ranges which are previously accumulated cells and current cell:
Set resultRange = Nothing
For x = 1 To 30: For y = 1 To lastNonemptyRow
If someClause(CInt(Cells(rowIdx, colIdx).Value)) Then
If resultRange is Nothing then
Set resultRange = Range(Cells(rowIdx, colIdx))
Else
Set resultRange = Union(resultRange, Range(Cells(rowIdx, colIdx)))
End if
End If
Next y: Next x
resultRange.Interior.Color = RGB(255, 0, 0)
This way is quite fast but after 1000 cells its execution time grows exponentially: 1000 cells are highlighted in 1.5 sec, 2000 cells are highlighted in 8 sec.
What is the fastest way to specify and highlight arbitrary 1000..10000 cells?
This is sort of what you are looking to do. Without further information re what sort of clause you would use I had to come up with own puzzle I employee many (all?) of the techniques used to speed up programs. 10 executes had average runtime of .2254 seconds with 10k cells painted
Option Explicit
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Sub newnew()
Dim started As Long
Dim ws As Worksheet
Dim paintRng As String
Dim rng As Range
Dim ColumnCount As Long
Dim RowCount As Long
Dim arrRng() As Variant
Dim wsTwo As Worksheet
Dim rngTwo As Range
Dim colNum As Long
Dim rowNum As Long
Dim ended As Long
started = timeGetTime
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
.DisplayStatusBar = False
.EnableEvents = False
End With
started = timeGetTime
Set ws = Sheets("Sheet1")
ws.DisplayPageBreaks = False
paintRng = "A1:J1000"
Set rng = ws.Range(paintRng)
ColumnCount = rng.Columns.Count
RowCount = rng.Rows.Count
ReDim arrRng(1 To RowCount, 1 To ColumnCount)
arrRng = rng
Debug.Print ColumnCount
Debug.Print RowCount
Set ws = Nothing
Set rng = Nothing
Set wsTwo = Sheets("Sheet2")
wsTwo.DisplayPageBreaks = False
Set rngTwo = wsTwo.Range(paintRng)
With rngTwo
For colNum = 1 To ColumnCount
For rowNum = 1 To RowCount
If arrRng(rowNum, colNum) = 1 Then
.Cells(rowNum, colNum).Interior.Color = RGB(255, 0, 0)
ElseIf arrRng(rowNum, colNum) = 2 Then
.Cells(rowNum, colNum).Interior.Color = RGB(125, 0, 0)
ElseIf arrRng(rowNum, colNum) = 3 Then
.Cells(rowNum, colNum).Interior.Color = RGB(0, 255, 0)
ElseIf arrRng(rowNum, colNum) = 4 Then
.Cells(rowNum, colNum).Interior.Color = RGB(0, 0, 255)
ElseIf arrRng(rowNum, colNum) = 5 Then
.Cells(rowNum, colNum).Interior.Color = RGB(125, 125, 0)
ElseIf arrRng(rowNum, colNum) = 6 Then
.Cells(rowNum, colNum).Interior.Color = RGB(125, 0, 125)
ElseIf arrRng(rowNum, colNum) = 7 Then
.Cells(rowNum, colNum).Interior.Color = RGB(75, 75, 200)
ElseIf arrRng(rowNum, colNum) = 8 Then
.Cells(rowNum, colNum).Interior.Color = RGB(50, 125, 255)
End If
Next rowNum
Next colNum
End With
Set wsTwo = Nothing
Set rngTwo = Nothing
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
.DisplayStatusBar = True
.EnableEvents = True
End With
ended = timeGetTime
Debug.Print ColumnCount * RowCount & " Cells Painted In " & (ended - started) / 1000 & " seconds"
End Sub

Insert Form Buttons to Cell but Format Buttons to be Smaller then Cell Dimensions

I have created the following code to insert form button if there is a value in column "A". I am trying to get the form buttons to be slightly smaller than the cell dimensions (not touch the cell walls). This is what I have so far:
Sub InsertButtons()
Dim i As Long
Dim shp As Object
Dim dblLeft As Double
Dim dblTop As Double
Dim dblWidth As Double
Dim dblHeight As Double
With Sheets("MailMerge")
dblLeft = .Columns("N:N").Left
dblWidth = .Columns("N:N").Width - 1
For i = 2 To .Cells(Rows.Count, "A").End(xlUp).Row
dblHeight = .Rows(i).Height -1
dblTop = .Rows(i).Top
If .Cells(i, 1).Value = Empty Then
Else
Set shp = .Buttons.Add(dblLeft, dblTop, dblWidth, dblHeight)
shp.OnAction = "SendEmail"
shp.Characters.Text = "Email"
End If
Next i
End With
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = False
End Sub
You need to subtract 2 from width and height. And add 1 to top and left:
dblLeft = .Columns("N:N").Left + 1
dblWidth = .Columns("N:N").Width - 2
dblHeight = .Rows(i).Height - 2
blTop = .Rows(i).Top + 1
I also recommend to use
If Not .Cells(i, 1).Value = Empty Then
Set shp = .Buttons.Add(dblLeft, dblTop, dblWidth, dblHeight)
shp.OnAction = "SendEmail"
shp.Characters.Text = "Email"
End If
instead of an empty If statement.

Shape Names In Excel

I have a VBA sub to create a few shapes, these shapes are then renamed to a cell value (B5:B15) and add text (C5:C15).
The shapes gets created, renamed and the text gets added but when I try to connect them I get the "Object Required".
Can some one please help me.
Thanks in advance.
Sub Button1_Click()
Dim s, conn As Shape, i As Integer
Set w = ActiveSheet
For i = 5 To 7
Set s = w.Shapes.AddShape(1, 800, i * 120 - 599, 100, 100)
s.Name = Range("B" & i)
s.TextFrame.Characters.Text = Range("C" & i)
s.Fill.ForeColor.RGB = RGB(0, 0, 213)
s.TextFrame.Characters.Font.ColorIndex = 19
Next i
Set conn = w.Shapes.AddConnector(1, 1, 1, 1, 1)
conn.ConnectorFormat.BeginConnect A001, 1
conn.ConnectorFormat.EndConnect A002, 1
End Sub
Something that would work:
Option Explicit
Sub Button1_Click()
Dim s As Shape, conn As Shape, i As Long
Dim w As Worksheet
Set w = ActiveSheet
Dim arr As Variant
ReDim arr(5 To 7)
For i = 5 To 7
Set s = w.Shapes.AddShape(1, 800, i * 120 - 599, 100, 100)
s.Name = Range("B" & i)
s.TextFrame.Characters.Text = Range("C" & i)
s.Fill.ForeColor.RGB = RGB(0, 0, 213)
s.TextFrame.Characters.Font.ColorIndex = 19
Set arr(i) = s
Next i
Set conn = w.Shapes.AddConnector(1, 1, 1, 1, 1)
conn.ConnectorFormat.BeginConnect arr(5), 1
conn.ConnectorFormat.EndConnect arr(6), 1
End Sub
What is the difference?
declaration of all variables - s is a Shape, i is a Long, w is a Worksheet;
the declaration is forced by Option Explicit;
a new variable arr is introduced, which keeps all the newly created forms. Thus the first form is kept under arr(5) and the last form is arr(7);
the BeginConnect and EndConnect need a variable which is a form. This is where we use the arr(5) to arr(7);
You can also refer to the shape, by its name and the Shapes() collection. Thus, the last 3 lines should look like this:
Set conn = w.Shapes.AddConnector(1, 1, 1, 1, 1)
conn.ConnectorFormat.BeginConnect w.Shapes("A001"), 1
conn.ConnectorFormat.EndConnect w.Shapes("A002"), 1

VBA Format a Number in a loop for conditional formatting

I'm trying to colour code the max and min numbers on an Excel Chart. Following Peltiertech.com ideas I have a code that works. The problem however is that the numbers in Excel are formatted to have no decimal points (FormulaRange4.NumberFormat = "0"). The values being checked out by my VBA formula are NOT formatted. As a result my "min" is being read as 265.875 instead of a rounded 266. As a result of this the code is unable to find my minimum.
Does anyone have a solution to this? Below is the code. the sub routine is fairly large but the portion of concern starts with "'Sub wiseowltutorial()"
Set FormulaRange3 = .Range(.Cells(d, c + 2), .Cells(r - 1, c + 3))
FormulaRange3.NumberFormat = "0"
Set FormulaRange4 = .Range(.Cells(d, c + c + 3), .Cells(r - 1, c + c + 3))
FormulaRange4.NumberFormat = "0"
Set SelectRanges = Union(FormulaRange3, FormulaRange4)
SelectRanges.Select
ActiveSheet.Shapes.AddChart.Select
With ActiveChart
.Type = xlColumn
.HasTitle = True
.ChartTitle.Text = "Individual Employee Productivity"
.ChartTitle.Font.Bold = True
.Axes(xlCategory).HasTitle = True
.Axes(xlCategory).AxisTitle.Text = "Employees"
.Axes(xlValue).HasTitle = True
.Axes(xlValue).AxisTitle.Text = "Widgets Produced"
.Axes(xlValue).MajorGridlines.Delete
.ApplyDataLabels
.Legend.Delete
.Parent.Name = "Individual Employee Productivity"
End With
End With
'End Sub
'Sub fromYouTubewiseowltutorial()
'find the proper way to highlight the most and least productive person or person per team
Dim ppApp As PowerPoint.Application
Dim ppPres As PowerPoint.Presentation
Dim ppSlide As PowerPoint.Slide
Dim ppTextbox As PowerPoint.Shape
Dim ppiPoint As Long
Dim ppvValues As Variant
Dim pprValue As Range
Dim lMax As Long
lMax = WorksheetFunction.Max(FormulaRange4)
Dim lMin As Long
lMin = WorksheetFunction.Min(FormulaRange4)
With ActiveChart.SeriesCollection(1)
ppvValues = .Values
For ppiPoint = 1 To UBound(ppvValues)
If ppvValues(ppiPoint) = lMax Then
.Points(ppiPoint).Format.Fill.ForeColor.RGB = RGB(0, 225, 0)
End If
If ppvValues(ppiPoint) = lMin Then
.Points(ppiPoint).Format.Fill.ForeColor.RGB = RGB(225, 0, 0)
End If
Next
End With
Thanks :)
Try to use Round():
If Round(ppvValues(ppiPoint),0) = Round(lMax,0) Then
...
...
If Round(ppvValues(ppiPoint),0) = Round(lMin,0) Then

Looping through multiple Command Buttons to change their properties based on cell values

I have an interactive table filled with over 100 different command buttons, each of which assign values to variables then use a custom function to calculate their output. They reference a table on the second sheet to get the values they assign. Is there a way to, based on whether a cell contains content or not, change the color of each button? So far, here's what I have (non-functional, of course).
Sub Auto_Open()
Dim n As Integer
n = 2
Do Until n = 114
If Sheet2.Cells(n, 4) = vbNullString Or Sheet2.Cells(n, 5) = vbNullString Or Sheet2.Cells(n, 8) = vbNullString Or Sheet2.Cells(n, 9) = vbNullString Or Sheet2.Cells(n, 10) = vbNullString Or Sheet2.Cells(n, 11) = vbNullString Then
ActiveSheet.Shapes.Range(Array("CommandButton" & (n - 1))).Select
Range.Array(Selection).BackColor = 500
Else
ActiveSheet.Shapes.Range(Array("CommandButton" & (n - 1))).Select
Range.Array(Selection).BackColor = 300
End If
n = n + 1
Loop
End Sub
EDIT:
I can't explicitly state the color for each command button without having to write in over 100 different cases. I have 112 different command buttons; I'd have to write 112 seperate IF statements.
Example for one command button:
Dim cb As CommandButton
Set cb = Sheet1.CommandButton1
With Sheet2.Range("A1")
If .Value = "Red" Then
cb.BackColor = RGB(255, 0, 0)
ElseIf .Value = "Green" Then
cb.BackColor = RGB(0, 255, 0)
Else
cb.BackColor = RGB(155, 155, 155) ' gray
End If
End With
If you want to loop through many command buttons, you can do as follows. In this example, I look at cells A1:A5 on Sheet2, and set the colors of Sheet1's commandbuttons 1 through 5 accordingly.
Dim cb As CommandButton
Dim i As Long
For i = 1 To 5
Set cb = Sheet1.Shapes("CommandButton" & i).OLEFormat.Object.Object ' Ouch!
With Sheet2.Range("A1").Cells(i, 1)
If .Value = "Red" Then
cb.BackColor = RGB(255, 0, 0)
ElseIf .Value = "Green" Then
cb.BackColor = RGB(0, 255, 0)
Else
cb.BackColor = RGB(155, 155, 155) ' gray
End If
End With
Next i
The .Object.Object trick I got from here.