Merge a custom figure in powerpoint - vba
I have custom that creates of map of the US in powerpoint.
Sub ArrayLoop(array1, array2, amountOfLine)
Dim i As Long
For i = 0 To amountOfLine
With ActivePresentation.Slides(1).Shapes.AddLine(BeginX:=array1(i), BeginY:=array2(i), EndX:=array1(i + 1), EndY:=array2(i + 1)).Line
.DashStyle = msoLineDashDotDot
.ForeColor.RGB = RGB(50, 0, 128)
End With
Next
End Sub
Sub TestArrayLoop()
Dim USA1, USA2
Dim amount As Integer
USA1 = Array(316.0954, 321.021, 332.9831, 337.205, 337.205, 346.4698,
351.3953, 354.9135, 361.9501, 367.5793, 370.394, 371.8012, 374.6158, 376.7268,
375.3195, 376.7268, 383.0596, 385.1706, 378.8377, 376.0232, 378.1341,
378.8377, 368.9866, 364.061, 366.172, 371.0976, 373.9122, 382.356, 388.6888,
393.6144, 397.1327, 394.318, 393.6144, _
384.4669, 384.4669, 376.7268, 374.6158, 369.6902, 368.2829, 366.172,
366.172,
361.9501, 358.4318, 354.9135, 350.6917, 347.8771, 347.8771, 347.8771,
347.1734, 346.4698, 350.6917, 343.6551, 345.0624, 342.2478, 339.4332,
337.9087,
330.8721, 317.5027, 314.6881, 312.5772, 310.4662, 316.0954, 319.6137,
323.132, 325.2429, 327.3539, 328.7612, 335.7977, 339.4332, 337.205,
338.7296,
335.7977, 331.5757, 330.1685, 325.9465, 324.5393, 322.4283, 319.6137,
318.2064, 315.3918, 313.9845, 309.7626, 306.2443, 306.2443, 311.1698,
311.8735,
308.3553, 306.2443, 303.4297, 302.0224, 297.0969, 290.0603, 285.8384, 279.5055, 280.2092, 280.9128, 278.8019, 275.2836, 267.5435, 264.0252, 265.4325,
260.5069, 254.8777, 247.1376, 242.212, 237.2865, 223.917, 220.3988, 214.7696, 211.2513, 206.9121, 206.9121, 214.0659, 219.6951, 227.4353, 232.3609,
231.6572, 233.7682, 239.3974, 247.1376, 247.8412, 309.0589, 316.0954)
USA2 = Array(247.1064, 248.5467, 254.3079, 263.6699, 267.9909, 265.1102, 260.7893, 260.0691, 258.6288, 251.4273, 252.1475, 259.349, 257.1885, 257.9087,
260.0691, 262.9498, 257.9087, 255.028, 254.3079, 249.987, 247.8265, 244.9459, 247.1064, 251.4273, 246.3862, 243.5056, 240.625, 241.3451, 240.625,
237.0242, 234.1435, 226.942, 223.3412, 218.3002, 215.4195, 200.2962, 206.7776, 208.218, 206.7776, 206.7776, 196.5754, 195.8553, 190.8142, 191.5343,
190.094, 190.8142, 194.415, 198.1357, 206.0575, 208.9381, 217.58, 224.0613, 234.8637, 237.0242, 235.5839, 222.621, 221.9009, 213.9792, 213.9792, 207.4978,
205.3373, 187.9335, 184.3327, 182.1723, 182.1723, 174.9708, 169.2095,
167.7692, _
164.8886, 158.4072, 154.0862, 150.4854, 149.7653, 156.9669, 163.4483, 155.5265, 152.6459, 156.2467, 152.6459, 147.6049, 141.1235, 133.9219, 144.0041,
147.6049, 151.9258, 156.2467, 159.8475, 158.4072, 158.4072, 162.0079, 160.5676, 160.5676, 157.687, 159.1273, 161.2878, 165.6087, 164.8886, 160.5676,
162.0079, 159.1273, 156.2467, 154.8064, 151.9258, 149.7653, 151.2056, 145.4444, 151.9258, 155.5265, 154.0862, 150.4854, 149.0452, 200.2962, 203.897,
201.0164, 215.4195, 219.0203, 224.7815, 229.1024, 237.0242, 242.0653, 245.6661, 245.6661, 247.1064)
amount = UBound(USA1) - LBound(USA2) + 1
amount = amount - 2
ArrayLoop USA1, USA2, amount
End Sub
This all works fine but the thing is that now I cant select the whole figure. So im looking for a way so I merge in it a figure which I can drag around the screen.
Any thoughts on how I can do this? Preferably in VBA
Your main issue is that you are adding many individual lines. For the code to work the way you envision, you somehow have to add your shape as a single line. To do this, change your sub from this:
Sub ArrayLoop(array1, array2, amountOfLine)
Dim i As Long
For i = 0 To amountOfLine
With ActivePresentation.Slides(1).Shapes.AddLine(BeginX:=array1(i), BeginY:=array2(i), EndX:=array1(i + 1), EndY:=array2(i + 1)).Line
.DashStyle = msoLineDashDotDot
.ForeColor.RGB = RGB(50, 0, 128)
End With
Next
End Sub
to this:
Sub ArrayLoop(array1, array2)
'you will need a single array of points for the call.
'whether you want to pass in 2 arrays and then merge them
'or pass in a single merged array is up to you
With ActivePresentation.Slides(1).Shapes.AddPolyline(<an array of points>).Line
.DashStyle = msoLineDashDotDot
.ForeColor.RGB = RGB(50, 0, 128)
End With
End Sub
You will need to tweak your array of points to get this to work.
Related
How to pass string user input (RGB) to VBA
I have a userform with RGB values to be assigned to shapes that will be later created by the macro: Private Sub UserForm_Initialize() With lstChosenColor lstChosenColor.AddItem "RGB(0, 0, 0)" lstChosenColor.AddItem "100, 100, 100" 'different from the above to show one alternative of my trials End With End Sub However I do not know how to insert the selected value into the macro itself. I tried in many ways: Dim lstChosenColor As String 'somewhere else i saw it as Long, tried but without success ' Dim ChosenColor As String ' ChosenColor = lstChosenColor 'I tried this one, too If lstChosenColor = False Then MsgBox "No Color Selected" Else: New_Shape.Fill.ForeColor.RGB = lstChosenColor.Selected 'I tried also 'New_Shape.Fill.ForeColor.RGB = lstChosenColor and 'New_Shape.Fill.ForeColor.RGB = RGB(lstChosenColor) End If Set New_Shape = myDocument.Shapes.AddShape(Type:=msoShapeOval, Left:=Shp_Cntr - ((Shp.Width + 2) / 2), Top:=Shp_Mid - ((Shp.Width + 2) / 2), Width:=Shp.Width, Height:=Shp.Width) ' New_Shape.Fill.ForeColor.RGB = RGB(lstChosenColor) 'I commented this as it is part of a repeating block for a various number of shapes and I thought I could assign the RGB value above Could anyone please advise?
If you use (eg) "100, 100, 100" as the value you can do something like: Dim v, arr v = lstChosenColor.Value 'get selected value arr = Split(Replace(v, " ", ""), ",") 'remove any spaces and split to array 'assign each array element as an argument to RGB() New_Shape.Fill.ForeColor.RGB = RGB(CLng(arr(0)), CLng(arr(1)), CLng(arr(2)))
ms-access shorten vba code
I'm using the following code alot in my project: txtVoornaam.Locked = False txtVoornaam.BorderStyle = 4 txtVoornaam.BorderColor = RGB(255, 165, 0 txtAchternaam.Locked = False txtAchternaam.BorderStyle = 4 txtAchternaam.BorderColor = RGB(255, 165, 0) txtAfdeling.Locked = False txtAfdeling.BorderStyle = 4 txtAfdeling.BorderColor = RGB(255, 165, 0) I wonder if there is a way to not display this in my code or shorten this. The code gets very long if i use this a few times..
Whenever you need to repeat a set of instructions, instead of copy+pasta'ing code your first reaction should be to ask yourself "how can I avoid copying this chunk over and over?" - and the solution is pretty much always to extract a method and parameterize it. So you take one of the repeated chunks: txtAchternaam.Locked = False txtAchternaam.BorderStyle = 4 txtAchternaam.BorderColor = RGB(255, 165, 0) and then copy it one last time in a new scope: Private Sub RenameMe() txtAchternaam.Locked = False txtAchternaam.BorderStyle = 4 txtAchternaam.BorderColor = RGB(255, 165, 0) End Sub Then you extract the parameters: Private Sub RenameMe(ByVal target As Control) target.Locked = False target.BorderStyle = 4 target.BorderColor = RGB(255, 165, 0) End Sub Then you replace the repeated chunks with calls to that new procedure: RenameMe txtVoornaam RenameMe txtAchternaam RenameMe txtAfdeling Or if that's still tedious you can iterate controls and call that procedure in the loop body - whatever works best for you. And if you need more flexibility, extract more parameters and make them Optional as needed: Private Sub RenameMe(ByVal target As Control, Optional ByVal lockCtrl As Boolean = False, Optional ByVal brdrStyle As Long = 4, Optional ByVal brdrColor As Long = 42495) target.Locked = lockCtrl target.BorderStyle = brdrStyle target.BorderColor = brdrColor End Sub Now the hard part is to give RenameMe a meaningful name that properly conveys what's going on here. I'd suggest FormatControl or something along these lines.
An option if you have several controls that you are creating through a form would be to do the following: Dim names() As String names = Split("txtVoornaam,txtAchternaam,txtAfdeling", ",") Dim ctrl As Variant Dim ctrlName As Variant For Each ctrl In Me.Controls For Each ctrlName In names If StrComp(ctrlName, ctrl.Name) = 0 Then ctrl.Locked = False ctrl.BorderStyle = 4 ctrl.BorderColor = RGB(255, 165, 0) End If Next ctrlName Next ctrl This code iterates through each of the control names that fit your list. However, this is much less efficient than Mat's Mug's answer because you are iterating through the entire list of controls in your form, but it does showcase how you might take a list of static names and iterate through them and a collection. If you wanted to change all the text controls this would be the way to do it; simply remove the ctrlName check. As Parfait has correctly pointed out, you could shorten the code to the following if you are confident in your control names: Dim names() As String names = Split("txtVoornaam,txtAchternaam,txtAfdeling", ",") Dim ctrlName As Variant For Each ctrlName In names With Me.Controls(ctrlName) .Locked = False .BorderStyle = 4 .BorderColor = RGB(255, 165, 0) End With Next ctrlName
function Lockdown(strControl) with me(strControl) .locked = false .borderstyle = 4 .bordercolor = RGB(255,165,0) end with use me or forms!formname depending on where you're calling from
if your controls are the same, obviously put them in a single sub/function that you can call from anywhere. i would not try to lock or change the format of textboxes, instead just enable/disable, and it will handle the format for you: textbox.enabled = true/false if you are doing this on multiple forms and really want a single sub/function to control enabling/disabling the textboxes on each form, then there are various ways of doing that as well, solution will depend on your needs, but certainly doable and some have already commented above. for example, you can use the "tag" property of the textboxes to flag the textboxes on that form that you want to enable/disable. you can then have a single sub/function that would take in the form as reference, and then you can read the "tag" property of all textboxes on that form and if they are the ones you flagged, you would proceed to enable/disable them
Change Border Color of a Range Without Changing the Linestyle/Weight
I have a nicely formatted range of cells with different border line weights (some of them are medium thickness and some of them are thin, in no particular pattern). I want to run a macro that changes the color of the borders to grey, but every time I do it, it changes all of the border weights to xlThin automatically. I want to keep the original line thickness so I don't have to go through and change the respective ones back to xlMedium, which would be tedious. Can someone help me out? Is this possible? The code I currently have is simple, and it changes the color correctly. It just also changes the line weight automatically, even though I don't specify the weight or linestyle at all: Range("NamedRange").Borders.Color = RGB(150, 150, 150)
This, on my Excel 2016, will only change the color of the cell border, without changing the size: Sub changeColorOnly() Dim rng As Range, cel As Range Set rng = Range("C6:C9") For Each cel In rng cel.Borders.Color = RGB(150, 150, 150) Next cel End Sub Does it still change the size for you? Edit: Hm, I suspect there's something else going on in your code, as I can recolor a named range without it affecting the borders. However, just because I was already working on another alternative, you could also use these subs (and tweak as necessary) Dim brdrTop, brdrLeft, brdrRight, brdrBtm, brdrInside Sub changeColor() saveBorderSize Range("myNamedRange") Range("MyNamedRange").Borders.Color = RGB(150, 150, 150) resetBorderSize Range("myNamedRange") End Sub Private Sub saveBorderSize(cel As Range) brdrTop = cel.Borders(xlEdgeTop).Weight brdrLeft = cel.Borders(xlEdgeLeft).Weight brdrRight = cel.Borders(xlEdgeRight).Weight brdrBtm = cel.Borders(xlEdgeBottom).Weight brdrInside = cel.Borders(xlInsideHorizontal).Weight End Sub Private Sub resetBorderSize(cel As Range) cel.Borders(xlEdgeTop).Weight = brdrTop cel.Borders(xlEdgeLeft).Weight = brdrLeft cel.Borders(xlEdgeRight).Weight = brdrRight cel.Borders(xlEdgeBottom).Weight = brdrBtm cel.Borders(xlInsideHorizontal).Weight = brdrInside End Sub
Try .Borders.Color = RGB(216,216,216) I ran the below script to try to identify the closest color to normal gridlines. My eyes are not great so check it out yourself to find the best color. BTW I agree it makes no sense that MS overrides the border color defying reason. Angry employees and too much bureaucracy - that's my theory. Sub borcol() Dim i As Integer For i = 1 To 250 ActiveCell.Borders.Color = RGB(i, i, i) ActiveCell.Offset(1, 0).Select Next i End Sub
To change the cell border color in a loop, using the enum value for each border makes it easy to loop through them. This code will change the border color of the selected cell. If there's no line the MsgBox will indicate its value. Sub CellBorderColour() Dim MyBorder(5 To 12) As String Dim i As Integer MyBorder(5) = "xlDiagonalDown" MyBorder(6) = "xlDiagonalUp" MyBorder(7) = "xlEdgeLeft" MyBorder(8) = "xlEdgeTop" MyBorder(9) = "xlEdgeBottom" MyBorder(10) = "xlEdgeRight" MyBorder(11) = "xlInsideVertical" MyBorder(12) = "xlInsideHorizontal" For i = 5 To 12 With Selection.Borders(i) If .LineStyle > 0 Then .Color = RGB(100, 100, 100) Else MsgBox ("Borders(" & MyBorder(i) & ").LineStyle is: " & .LineStyle) End If End With Next i End Sub
Flag a line chart series if it is over another series
I have 2 sheets with about 10-20 graphs per sheet. every graph is of the same format witht the same series names. one series is called "forecast spendings" and the other is called "spendings should-be." I need to flag the chart when the forecast spendings line goes over the spendings shout-be line. I was thinking making a red dot on the given point(s). I tried using a bunch of tricks with conditional foratting by making other data tables and manipulating the values but with no success. VBA will probably be the solution. I've never used VBA on charts though so im not sure how to procede. I've been doing sone research but i dont know how to modify codes in accordance to my needs due to my inexperience with charts. I think comparind an array of the 2 series would be the answer. this would then have to loop for each chart and then loof for each sheet. I found this code that seems useable to me but i dont understant what is being referenced. I'm guessing this is assuming that htere is only one chart wiht one serie: Dim chartIterator As Integer, pointIterator As Integer, _ seriesArray() As Variant For chartIterator = 1 To ActiveSheet.ChartObjects.Count seriesArray = ActiveWorkbook.Sheets("Sheet1").ChartObjects(chartIterator). _ chart.SeriesCollection(1).Values For pointIterator = 1 To UBound(seriesArray) If seriesArray(pointIterator) >= 0 Then ActiveWorkbook.Sheets("Sheet1").ChartObjects(chartIterator). _ chart.SeriesCollection(1).Points(pointIterator).Interior.Color = _ RGB(146, 208, 80) Else ActiveWorkbook.Sheets("Sheet1").ChartObjects(chartIterator). _ chart.SeriesCollection(1).Points(pointIterator).Interior.Color = _ RGB(255, 0, 0) End If Next pointIterator Next chartIterator Please explain your answer so i can understand it and repeat it. Thank you in advance for your time!
This seemed to work fine for me. Sub tester() Dim co As ChartObject For Each co In ActiveSheet.ChartObjects CheckChart co.Chart Next co End Sub Sub CheckChart(cht As Chart) Dim s As Series, sForecast As Series, sShould As Series Dim i As Long 'see if we can find the required series on this chart For Each s In cht.SeriesCollection Debug.Print s.Name If s.Name = "forecast spendings" Then Set sForecast = s If s.Name = "spendings should-be" Then Set sShould = s Next s 'series located? If sShould Is Nothing Or sForecast Is Nothing Then MsgBox "required series not found!" Else 'found the series, so compare the point values 'assumes same # of points in both lines ' and same start/end For i = 1 To sShould.Points.Count If sForecast.Values(i) > sShould.Values(i) Then 'label point With sForecast.Points(i) .HasDataLabel = True .DataLabel.Position = xlLabelPositionAbove .DataLabel.Text = "!!!" .DataLabel.Characters.Font.Color = vbRed End With End If Next i End If End Sub
Excel 2010 VBA - Storing decimal in array and using to chart percentage of stored value
SO Community, I'm looking to automate some of the metrics that are used at my work using VBA. I am currently trying to read through an array that I have my ticketing raw data stored in and then either store the value as a decimal or percentage. After this is stored in the array, I am attempting to create or update a chart series with the array and display this value as a percent. I suspect that I'm just missing some syntax for this, but I have checked SO, MSDN and Excel help and have had no luck. I have attached the relevant code below: FUNCTION Function calcTopApplications(iArray As Variant) Dim m_counter As Long, r_counter As Long, placeholder As Double Dim fNav_counter As Long, pmoNav_counter As Long, rmgr_counter As Long, wlm_counter As Long, total_counter As Long ReDim tkt_month_arr(12), tkt_fnav_arr(12) For m_counter = 1 To 12 fNav_counter = 0 pmoNav_counter = 0 rmgr_counter = 0 wlm_counter = 0 total_counter = 0 For r_counter = 2 To UBound(iArray, 1) If iArray(r_counter, 1) <> iArray(r_counter - 1, 1) Then If CDate(iArray(r_counter, 5)) >= DateAdd("m", -m_counter, DateSerial(Year(Date), Month(Date), 1)) Then If CDate(iArray(r_counter, 5)) < DateAdd("m", (1 - m_counter), DateSerial(Year(Date), Month(Date), 1)) Then total_counter = total_counter + 1 If StrConv(iArray(r_counter, 7), vbLowerCase) = "franchise navigator" Then fNav_counter = fNav_counter + 1 End If End If End If End If Next r_counter placeholder = FormatNumber(fNav_counter / total_counter, 2) tkt_month_arr(12 - (m_counter - 1)) = CLng(DateAdd("m", -m_counter, DateSerial(Year(Date), Month(Date), 1))) tkt_fnav_arr(12 - (m_counter - 1)) = placeholder Next m_counter End Function SUBROUTINE If Me.ChartObjects("Top 4 Applications Ticket Volume") Is Nothing Then On Error GoTo 0 With Me.Shapes.AddChart .Left = Me.Range("A16").Left .Top = Me.Range("A16").Top .Width = Me.Range("A16:S16").Width .Height = Me.Range("A16:A30").Height .Select End With With ActiveChart .ChartType = xlLine .ChartStyle = 42 .HasDataTable = True .HasTitle = True .Parent.Name = "Top 4 Applications Ticket Volume" .ChartTitle.Caption = "Open/Close Ticket Volume by Month (Top 4 Applications)" .Axes(xlCategory).TickLabels.NumberFormat = "mmm yyyy" End With With ActiveChart.SeriesCollection .NewSeries .Item(1).Name = "Franchise Navigator" .Item(1).XValues = tkt_month_arr .Item(1).Values = tkt_fnav_arr End With Else With Me.ChartObjects("Top 4 Applications Ticket Volume") .Select End With With ActiveChart.SeriesCollection .Item(1).XValues = tkt_month_arr .Item(1).Values = tkt_fnav_arr End With End If This gives me the values for the percentage but does not behave on the chart as a percentage (have the % symbol).
When you create a chart "normally" and add a data table, all you have to do is format the source cells, and the table follows. But the method you use means you don't have "source cells"; and as far as I was able to tell, Microsoft doesn't provide a method to modify the formatting of the data table when it's generated with your method. An "ugly workaround" is to create a hidden sheet, put the data there, and format it correctly. Point to this data when you create the data table, and the formatting will be correct. It would be nice if Microsoft provided the flexibility you are asking for... sigh