Excel VBA: Create shapes hierarchy from list - vba

I'm trying to loop through an "ordered" list to create several rectangle shapes in hierarchy style (and link them with elbow connectors). Example: on my WBSdata sheet, I have the following
A B
1 0. Box 0. lvl1
2 0.1. Box 0.1. lvl2
3 Comment 1
4 Comment 2
5 0.1.1. Box 0.1.1. lvl3
6 Comment 1
7 Comment 2
8 Comment 3
9 0.2. Box 0.2. lvl2
10 0.2.1. Box 0.2.1. lvl3
11 0.2.2. Box O.2.1. lvl3
12 Comment 1
13 Comment 2
14 1. Box 1. lvl1
15 Comment 1
16 Comment 2
17 1.1. Box 1.1. lvl2
Would output something like this on the WBS sheet:
Basically, read the "index" in column A, if it's first level (2 characters in column A), draw a blue box and write the corresponding value from column B, then look at the line below, if it's a level 2 box (4 characters), draw it below (a bit shorter on the left side), assign it the value ; same for lvl 3 box. If column A i empty, create a text box below the shape, and add all the comments.
So far (see code below), I managed to create a box (yay), style it and add the text, as well as create a text box (with a line on the side, like in the picture, but i'd need it to be the same "dynamic" height as the text box), but i can't get it to add all the comments. I can't get the magic to understand that it needs to move to the next "level" (go from blue box to green box for example).
I haven't yet tried to connect each box to its "hierarchical superior", but that's another story :)
I'm pretty sure i'm not managing my variables correctly (mainly the counter), making it reset at the right time, etc...
Any tips to send me on the right direction?
Public Sub wbsShape()
Dim wbs, wbsdata As Worksheet
Set wbs = ThisWorkbook.Sheets("WBS")
Set wbsdata = ThisWorkbook.Sheets("WBSdata")
i = 2 'counter, because data starts on line 2
ileft = 100 'initial position from left of sheet
itop = 100 'initial position from top of sheet
lg = 175 'main box width
ht = 50 'main box height
ind = 10 'indent (for lines, or smaller boxes)
impred = RGB(128, 0, 0) 'red
impgreen = RGB(0, 128, 0) 'green
impblue = RGB(0, 0, 128) 'blue
impgrey = RGB(200, 200, 200) 'light grey for border
black = RGB(0, 0, 0)
white = RGB(255, 255, 255)
Do While Not IsEmpty(wbsdata.Cells(i, "A").Value)
With wbs.Shapes.AddShape(msoShapeRectangle, ileft, itop, lg, ht)
.Fill.ForeColor.RGB = impblue
.Line.ForeColor.RGB = impgrey
.Line.Weight = 1
.Name = wbsdata.Cells(i, "B").Value
With .TextFrame
With .Characters
.Text = UCase(wbsdata.Cells(i, "B").Value)
With .Font
.Color = white
.Name = "Arial"
.Size = 14
.FontStyle = "Bold"
End With
End With
.HorizontalAlignment = xlHAlignCenter
.VerticalAlignment = xlVAlignCenter
End With
End With
i = i + 1
If IsEmpty(wbsdata.Cells(i, "A").Value) Then
wbs.Shapes.AddLine(ileft + ind, itop + ht, ileft + ind, itop + ht + 100).Line.ForeColor.RGB = RGB(10, 10, 10)
With wbs.Shapes.AddTextbox(msoTextOrientationHorizontal, ileft + 2 * ind, itop + ht, lg - ind, 30)
.Line.Visible = msoFalse
.Fill.Transparency = 1
With .TextFrame.Characters
.Font.Name = "Arial"
.Text = wbsdata.Cells(i, "B").Value
End With
End With
End If
itop = itop + ht + 20
Loop
End Sub

I think this is going to be a lot of work (I've stripped out a lot of your formatting), but perhaps this will start you off in the right direction.
Sub x()
Dim r As Range, v, s As Shape
ileft = 100 'initial position from left of sheet
itop = 100 'initial position from top of sheet
lg = 175 'main box width
ht = 50 'main box height
ind = 10 'indent (for lines, or smaller boxes)
impred = RGB(128, 0, 0) 'red
impgreen = RGB(0, 128, 0) 'green
impblue = RGB(0, 0, 128) 'blue
impgrey = RGB(200, 200, 200) 'light grey for border
black = RGB(0, 0, 0)
white = RGB(255, 255, 255)
For Each r In Range("A1:A4")
v = Split(r, ".")
If UBound(v) = 1 Then
Set s = ActiveSheet.Shapes.AddShape(msoShapeRectangle, ileft, itop, lg, ht)
s.Fill.ForeColor.RGB = impblue
s.TextFrame.Characters.Text = r.Offset(, 1)
itop = itop + 75
ElseIf UBound(v) = 2 Then
Set s = ActiveSheet.Shapes.AddShape(msoShapeRectangle, ileft, itop, lg, ht)
s.Fill.ForeColor.RGB = impgreen
s.TextFrame.Characters.Text = r.Offset(, 1)
itop = itop + 75
ElseIf r = vbNullString Then
Set s = ActiveSheet.Shapes.AddTextbox(msoTextOrientationHorizontal, ileft + 2 * ind, itop + ht, lg - ind, 30)
s.Line.Visible = msoFalse
s.Fill.Transparency = 1
With s.TextFrame.Characters
.Font.Name = "Arial"
.Text = r.Offset(, 1).Value
End With
itop = itop + 75
End If
Next r
End Sub

Related

VBA Powerpoint - VBA does not show borders

I am working on a function that allows me to insert a specific number of rows below a specific row in my powerpoint table. Please note that this is no standard table - it has a format in which there is one "Content Row". After, there are 2 small (height) white rows before a next "Content Row" follows. The white rows are merely for optics and have a border in between.
The code is working well, however the very last operation at the bottom - to display the border in between the rows - does not work. Simply no border appears.
Thank you SO much for any input you can provide! <3
Private Sub Insert_Click()
'Read Input from UserForm
Answer1 = UserForm1.Answer1.Text
Answer2 = UserForm1.Answer2.Text
Unload UserForm1
'Analyze Row prior operation
SmallHeight = ActiveWindow.Selection.ShapeRange.Table.Rows(2).Height
For repeat = 1 To Answer2
'Add Row
'Paster after row
BelowRow = 1 + 3 * (Answer1 - 1)
For i = 1 To 5
ActiveWindow.Selection.ShapeRange.Table.Rows.Add (BelowRow)
i = i + 1
Next
'Format "BelowRow" with Font and Text
With ActiveWindow.Selection.ShapeRange.Table.Cell(BelowRow, 1).Shape.TextFrame.TextRange
.Text = "Insert Caption"
.Font.Name = "Arial"
.Font.Size = "12"
End With
'Format two rows below "BelowRow"
intTableCols = ActiveWindow.Selection.ShapeRange.Table.Columns.Count
For r = 1 To 3
BelowRow = BelowRow + 1
For c = 1 To intTableCols
With ActiveWindow.Selection.ShapeRange.Table.Cell(BelowRow, c).Shape
.Fill.ForeColor.RGB = RGB(0, 0, 0)
.Fill.Transparency = 1
.TextFrame.TextRange.Font.Size = "1"
.TextFrame.MarginBottom = 0
.TextFrame.MarginLeft = 0
.TextFrame.MarginRight = 0
.TextFrame.MarginTop = 0
End With
Next
'Reduce Row Height
ActiveWindow.Selection.ShapeRange.Table.Rows(BelowRow).Height = SmallHeight
r = r + 1
Next
BelowRow = BelowRow - 1
'Add Border and Format
With ActiveWindow.Selection.ShapeRange.Table.Rows(6).Cells.Borders.Item(ppBorderTop)
.Weight = 3
.ForeColor.RGB = RGB(77, 77, 77)
End With
Next
End Sub

Adding border to series in a bar chart

I am using a macro to insert a chart into a spreadsheet:
Option Explicit
Sub Macro1()
Dim overskrifter As Range
Dim i As Long
Dim høgde As Long, breidde As Long
Call fjernkurver
i = 1
høgde = 240: breidde = 350
Set overskrifter = Oppsummering.Range("C5:L5")
With Kurver.Shapes.AddChart2(201, xlColumnClustered)
.Name = "Graf_" & i
With .Chart.SeriesCollection.NewSeries
.XValues = overskrifter
.Values = overskrifter.Offset(i, 0)
.Name = Oppsummering.Range("B5").Offset(i, 0)
' "Olive"
.Points(1).Format.Fill.ForeColor.RGB = RGB(128, 128, 0)
' "Dark khaki"
.Points(8).Format.Fill.ForeColor.RGB = RGB(189, 183, 107)
' Green (Atlantis)
.Points(9).Format.Fill.ForeColor.RGB = RGB(146, 208, 80)
With .Format.Line
.Visible = msoTrue
.Weight = 0.5
'.ForeColor.RGB = RGB(0, 0, 205)
.ForeColor.RGB = RGB(255, 0, 0)
.Transparency = 0
End With
End With
.Height = høgde
.Width = breidde
.Top = 5 + ((i - 1) \ 3) * (5 + høgde)
.Left = 5 + ((i - 1) Mod 3) * (5 + breidde)
.Chart.HasTitle = True
.Chart.ChartGroups(1).GapWidth = 150
.Chart.ChartGroups(1).Overlap = 0
End With
End Sub
Sub fjernkurver()
Dim co As ChartObject
For Each co In Kurver.ChartObjects
co.Delete
Next co
End Sub
For the most part it works fine, but I am having some issues with this part of the code:
With .Format.Line
.Visible = msoTrue
.Weight = 0.5
'.ForeColor.RGB = RGB(0, 0, 205)
.ForeColor.RGB = RGB(255, 0, 0)
.Transparency = 0
End With
It is supposed to add a border around all the bars in the graph, red with RGB(255,0,0), blue with RGB(0,0,255).
However, as far as I can tell, no border is added to any of the bars. Can someone please point out where I am going wrong here?
The chart ends up looking like this:
It appears that the .Format.Line property of a series applies to something else than the border of a bar chart - a guess would be that it is the line connecting the datapoints of e.g. a line or scatter chart.
To actually outline the bars, I replaced the offending code;
With .Format.Line
.Visible = msoTrue
.Weight = 0.5
.ForeColor.RGB = RGB(255, 0, 0)
.Transparency = 0
End With
with
.Border.LineStyle = xlContinuous
.Border.Color = 9851952
.Format.Line.Weight = 0.5
Please don't ask me why .Format.Line.Weight still applies to the border, at least I got it working. Big props to the people who'd written the thread where I found the answer on Ozgrid forums.

Macro Excel: To insert a circle into specific range in cell

I have a circle that has a fixed diameter and center. What I need to do now is to insert the circle into the given range. Eg, given 11 boxes of column and 10 boxes of rows to be inserted in excel cell. After entering the given range, the circle will be within the selected range with its fixed center but the boxes would have different measurement for its height and width. My question is how do I insert the circle into any given range (as in 11 x 10 or 9 x 12) with different height and width of the cells?
My code:
Sub DrawCircleWithCenter()
Dim cellwidth As Single
Dim cellheight As Single
Dim ws As Worksheet
Dim rng As Range
Dim Shp2 As Shape
CellLeft = Selection.Left
CellTop = Selection.Top
ActiveSheet.Shapes.AddShape(msoShapeOval, CellLeft, CellTop, 565 / 2, 565 / 2).Select
Selection.ShapeRange.Fill.Visible = msoFalse
With Selection.ShapeRange.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(0, 0, 0)
.Transparency = 0
End With
i = 182
Set Shp2 = ActiveSheet.Shapes.AddShape(i, CellLeft, CellTop, 20, 20)
Shp2.ShapeStyle = msoShapeStylePreset1
Set rng = ActiveWindow.VisibleRange
Selection.Left = rng.Width / 2 - Selection.Width / 2
Selection.Top = rng.Height / 2 - Selection.Height / 2
Shp2.Left = rng.Width / 2 - Shp2.Width / 2
Shp2.Top = rng.Height / 2 - Shp2.Height / 2
End Sub
If I'm understanding you correctly this could be what you're after:
Sub DrawCircleWithCenter(rng As Range)
Dim Shp1 As Shape, Shp2 As Shape
Set Shp1 = ActiveSheet.Shapes.AddShape(msoShapeOval, rng.Left, rng.Top, rng.Width, rng.Height)
Shp1.Fill.Visible = msoFalse
With Shp1.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(0, 0, 0)
.Transparency = 0
End With
Set Shp2 = ActiveSheet.Shapes.AddShape(182, rng.Left, rng.Top, 20, 20)
Shp2.ShapeStyle = msoShapeStylePreset1
Shp1.Left = rng.Left
Shp1.Top = rng.Top
Shp2.Left = rng.Left + rng.Width / 2 - Shp2.Width / 2
Shp2.Top = rng.Top + rng.Height / 2 - Shp2.Height / 2
End Sub
Sub Test()
Dim rng As Range
Set rng = Selection
DrawCircleWithCenter rng
End Sub
You can modify the Test subroutine to supply the range you're after. In the above case I use the selection that the user has highlighted in the present worksheet to draw the cross and oval centered inside it. If you choose a square area the oval becomes a circle, with a rectangular area it'll be squashed into an ellipse. It'll also work if you have varying cell widths and heights in the range you select.

Excel VBA value dynamicly named textboxes

Bottom Line Fix: Changing my dynamicly named textbox to have a _ separator between the column and row to get rid of the ambiguity of the names.
Previous Code:
Set cCntrl = PickTicketForm.Controls.Add("Forms.TextBox.1", "PalletNumber" & i & r, True)
Fix:
Set cCntrl = PickTicketForm.Controls.Add("Forms.TextBox.1", "PalletNumber" & i & "_" & r, True)
I have a userform and it has 15 text boxes columns by X rows (dynamic).
The user inputs numbers into the text boxes. Then I want them to hit a Print button on the user form to run the PrintLabel() sub and put those values into a spreadsheet vertically (B24:Bxx). Then have it print out the spreadsheet and return to the userform.
My issue is I can't seem to get the values from the textboxes.
The textbox names are in an multi-dimensional array style format:
PalletNumber & "row" & "column"
So the first row would be PalletNumber0_0 through PalletNumber0_15. The next row will be PalletNumber1_0 to PalletNumber1_15.
Update:
The user enters the value "1234" into a textbox and clicks "Look Up" to run lookup(). This then searches a spreadsheet for the number and gets all the rows that match and puts them into the userform.
Here is the code snippet
For Each c In Worksheets("Sheet1").range("A2:A" & iRowCount)
If c.value = OrderNumber Then
ReDim Preserve aGetData(6, i)
For a = 0 To 6 'Change this for total of columns Our first index will hold each col of data that is why
'it is set to 0 (arrays start at a base of zero, so
'0,1,2,3,4,5 will be each col(A,B,C).
aGetData(a, i) = c.Offset(0, a) 'This gets each value from col A,B and C
Next a
'Get the data and set it into variables.
ItemNumber = aGetData(5, i)
ItemQty = aGetData(2, i)
'Create "ItemQuantity" text box.
Set cCntrl = PickTicketForm.Controls.Add("Forms.Label.1", "ItemQuantity" & i, True)
With cCntrl
.Caption = ItemQty
.Width = 85
.Height = 18
.Top = 86 + (i * 20)
.Left = 40
.TextAlign = 1 'Left
.Font.Name = "Arial Black"
.Font.Size = "10"
.BackColor = BackgroundColor
End With
'Create "ItemNumber" box
Set cCntrl = PickTicketForm.Controls.Add("Forms.Label.1", "ItemNumber" & i, True)
With cCntrl
.Caption = ItemNumber
.Width = 340
.Height = 18
.Top = 86 + (i * 20)
.Left = 86
.TextAlign = 1 'Left
.Font.Name = "Arial Black"
.Font.Size = "10"
.BackColor = BackgroundColor
End With
'Create each inputbox for the pallets.
For r = 0 To 14
Set cCntrl = PickTicketForm.Controls.Add("Forms.TextBox.1", "PalletNumber" & i & "_" & r, True)
With cCntrl
.Width = 28
.Height = 18
.Top = 86 + (i * 20)
.Left = 354 + (r * 30)
.TextAlign = 1 'Left
.Font.Name = "Arial Black"
.Font.Size = "10"
.BackColor = BackgroundColor
.Text = i & r
End With
Next r
i = i + 1 'Increment for array in case we find another order number
'Our second index "aGetData(index1,index2) is being resized
'this represents each order number found on the sheet
LineCount = LineCount + 1
'Set the scroll bar height for the final form.
ScrollBarHeight = 150 + (i * 20)
End If
Next c
Here is that code snippet:
'Loop through first column completely ( 0 - 5 to test)
' i = 0 means go through every box in column 0 first
For i = 0 To 5
'Loop through rows.
For r = 0 To 2 '( 0 - 2 rows to test)
ActiveCell.Offset(i, 0).value = PickTicketForm.Controls("PalletNumber" & i & r).Text
Next r
Next i
Here is the userform layout:
The spreadsheet output should look like this:
You should add your controls within a For i = 0 To 5 loop as well.
If it remains empty you are adding PalletNumber0, PalletNumber1, PalletNumber2 etc. while you are searching for PalletNumber00, PalletNumber01, PalletNumber02 etc.

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.