this is my first post here,
I'm working on a presentation for a client, they want a color-coded map of Europe. The individual countries should be colored green-yellow-red depending on a certain risk-score. They (and me, too) thought this would be easily doable by somehow linking the PPT to an excel and then doing some conditional formatting. It seems we were very wrong.
I've first familiarized myself with Excel VBA to try and understand how VBA works. I created a map consisting of the European country shapes and named each shape accordingly. Then I created the dynamic coloring in excel using code like this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("B2") = "opposed" Then
ActiveSheet.Shapes.Range(Array("Austria")).Select
Selection.ShapeRange.Fill.ForeColor.RGB = RGB(255, 0, 0)
Else
If Range("B2") = "undecided" Then
ActiveSheet.Shapes.Range(Array("Austria")).Select
Selection.ShapeRange.Fill.ForeColor.ObjectThemeColor = msoThemeColorAccent4
Else
If Range("B2") = "approving" Then
ActiveSheet.Shapes.Range(Array("Austria")).Select
Selection.ShapeRange.Fill.ForeColor.ObjectThemeColor = msoThemeColorAccent6
End If
End If
End If
End Sub
I just put the risk assessment ("opposed", "undecided", "approving") into a column, then ask what that value is, then change the color of the shape accordingly. The code works - if any value is changed, the map changes. I'm quite happy.
Now I need to make this work in Powerpoint. PP VBA seems to be quite different, and I couldn't find anything on how to make this work. I tried the following as a proof of concept:
Sub coloring()
If ActivePresentation.Slides(1).Shapes("Rect1").TextFrame.TextRange.Text.Value = "RED" Then ActivePresentation.Slides(1).Shapes("Rect2").Fill.ForeColor.RGB = RGB(255, 0, 0)
End Sub
I find it very hard to navigate PP VBA and it's really frustrating.
How I'd like to do it: I'd like to create one (hidden) slide which contains all the information (in text boxes or a table with cells or something like that) and then create multiple slides which refer to the content of the hidden slide and display color-coded information based on the content on the hidden slide. But I don't really know where to start and how to make this work.
Any ideas are welcome
Since VBA for each app closely follows the app's own object model, each will seem odd if you're accustomed to a different app's OM but not the one you're working in.
Here's a working example. Your code was almost there:
Sub coloring()
' Using With/End With can save a lot of typing:
With ActivePresentation.Slides(1)
If .Shapes("Rect1").TextFrame.TextRange.Text = "RED" Then
' It's a good idea to make sure the fill is visible
' before setting it
.Shapes("Rect2").Fill.Visible = True
.Shapes("Rect2").Fill.ForeColor.RGB = RGB(255, 0, 0)
End If
End With
End Sub
Related
I literally just got my feet wet with VBA as this is my first macro. After many hours of searching, I couldn't seem to find an answer that had a solution that worked for me so here I am.
On Sheet3 I have 3 option buttons in a group box that are linked to cell "B18" on Sheet4 (Sheet4 is hidden to the user, a backstage if you will). When any of the three option buttons are selected, 'Sheet4!B18' gets updated as it should (e.g. 1, 2, or 3). What I want to happen is to have 'Sheet3!B17' changed based upon the value in 'Sheet4!B18', or effectively: IF('Sheet4!B18'=2,SET('Sheet3!B17'="Some Text Here:"),SET('Sheet3!B17'="0%")), but still allow user input in 'Sheet3!B17'. I have one VBA macro on Sheet4 with the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Worksheet.Range("B18") = 2 Then
Worksheets("Sheet3").Range("B17") = "Some Text Here:"
Else
Worksheets("Sheet3").Range("B17") = "0%"
End If
End Sub
If I manually update 'Sheet4!B18' then the macro gets triggered with the desired results. If I use any of the 3 option buttons on Sheet3, the macro does not get triggered even though the target cell is getting updated.
In my searching I couldn't seem to find anything concrete, but from what I could tell the "Worksheet_Change" function doesn't see changes to cells from form control as changes to the linked cell are considered a "recalculation" as if it were from a formula. I don't know how correct that is, but my searching led me to believe that I would need another macro assigned on the 3 buttons and/or group box that when either of those get selected/changed, it would somehow trigger the working macro on Sheet4.
I thought that perhaps I could create a new macro that I would assign to the group box or option buttons themselves so I tried that and could not get anything to work. I tried adding the above macro code to another sub, Sub mode() and assigning to only the group box, then only the buttons, but nothing happened in either case. I proceeded to try tweaking the code just in case the references were not correct, but saw no change regardless of how I specified the reference. I am not getting any error messages, but nothing gets triggered unless I manually change the value in 'Sheet4!B18'.
Is there a way to get the first macro that I have working on Sheet4 to trigger off of the option buttons changing the target cell value, something like forcing it to look only at that one specific cell for changes? Am I stuck making another macro for the buttons and/or group box to trigger the macro on Sheet4? Am I over-complicating this and there is some built in Excel sheets function(s) that I can use?
IF/THEN is a fine way to do it. VBA also supports ternary logic with the IIF function, like this:
Worksheets("Sheet3").Range("B17") = IIF(Worksheets("Sheet4").Range("B18") = 2, "Some Text Here:", "0%")
That may seem a little difficult to read, but it's a good concept to understand, since it's present in many languages, and usually with a more simplified implementation that makes it very useful and concise.
Also, I would suggest making a couple of other alterations that may make your code easier to write, read and maintain (especially as it becomes more complex).
First, alias the worksheets, something like this:
Dim this as Worksheet: Set this = Worksheets("Sheet3")
Dim that as Worksheet: Set that = Worksheets("Sheet4")
Now you would be able to rewrite your code like this:
If that.Range("B18") = 2 Then
this.Range("B17") = "Some Text Here:"
Else
this.Range("B17") = "0%"
End If
And the ternary approach would now be:
this.Range("B17") = IIF(that.Range("B18") = 2, "Some Text Here:", "0%")
And you can get as specific as you like with the aliases. For instance, you could realias the ranges, instead of just the worksheets, like this:
Dim this as range: Set this = Worksheets("Sheet3").Range("B17")
Dim that as range: Set that = Worksheets("Sheet4").Range("B18")
this = IIf(that = 2, "Some Text Here:", "0%")
Also, I find it easier to use the cells property than the range property, especially when you start having to do cell math. In that case, Range("B17") becomes Cells(17, 2).
You can also change the way the cells are referenced in the spreadsheet by typing Application.ReferenceStyle = xlR1C1 into the immediate window. That way you don't have to mentally convert between A2 style ranges to Cartesian style (2,1).
Sometimes you just have to go through your entire thought process and type everything out before you have an "ah-hah!" moment because that is exactly what I had happen. I said to myself, "Why can't I have just one macro that gets triggered by the option buttons that checks my linked cell then proceeds to update the cell I want?" Well, eventually I was able to find the right code and this is what worked perfectly:
Sub mode() ' mode is the name of this macro
If Worksheets("Sheet4").Range("B18") = 2 Then
Worksheets("Sheet3").Range("B17") = "Some Text Here:"
Else
Worksheets("Sheet3").Range("B17") = "0%"
End If
End Sub
As it turns out, I was overlooking the simple solution and the above macro is all I need once I assigned it to the 3 option buttons in my group box, but not the group box itself. Since users will not have access to the hidden Sheet4 and therefore 'Sheet4!B18' will never have manual user input, the macro I first had on Sheet4 could be removed safely. Due to the fact that the option buttons being chosen is the trigger for the assigned macro, it executes each time the option is changed and only when the option is changed. Perfect!
EDIT:
Thanks to Chris Strickland for some tips for better code! I went on to modify the above into what you see below for slightly better performance (using Cells() instead of Range()), to save the original value to another cell and restore it if option 1 or 3 were selected, used aliases, and finally the IIf operator.
Sub mode() ' mode is the name of this macro
Dim S3 As Worksheet: Set S3 = Worksheets("Sheet3")
Dim S4 As Worksheet: Set S4 = Worksheets("Sheet4")
If IsNumeric(Cells(17, 2)) = True Then
S3.Activate
S4.Cells(18, 3) = Cells(17, 2).Value
End If
S3.Cells(17, 2) = IIf(S4.Cells(18, 2) = 2, "Some Text Here:", S4.Cells(18, 3))
End Sub
I have a simple vba code in Word 2010:
Sub IncreaseIndent()
For Each p In Selection.Paragraphs
p.LeftIndent = p.LeftIndent + InchesToPoints(0.25)
p.FirstLineIndent = InchesToPoints(-0.25)
Next
End Sub
It works great, does what I need, and I have it associated to a shortcut key. But I'm trying to figure out one last glitch it has. When I use it, the paragraph indents, but it's not visually refreshed properly in the document. I have to scroll so that the text goes out of view, and then scroll it back. (Any action that makes Word re-render works, like switching to another program whose window is on top of Word, and back again.) After that, the paragraph looks as it should.
I'm thinking I'm missing some kind of p.Refresh / Re-render / Recalc command, but don't know what that is. Anyone know how to cause the refresh in the vba code?
Thanks,
Sandra
I was not able to replicate what you describe, but there is a .ScreenRefresh method which might do the trick.
https://msdn.microsoft.com/en-us/library/office/ff193095(v=office.15).aspx
Note: in the example code provided at MSDN (and as modified slightly, below), when I test it the toggling ScreenUpdating property has no effect, it always appears to update for me when I run it, even when set explicitly to False
Sub t()
Dim rngTemp As Range
Application.ScreenUpdating = False
Set rngTemp = ActiveDocument.Range(Start:=0, End:=0)
rngTemp.InsertBefore "new"
Application.ScreenRefresh
Application.ScreenUpdating = True
End Sub
I want a graph only to appear when a condition is fulfilled. To be more precise: I have a drop down menu that changes the content of a graph. If the menu point "Total revenue" is clicked, I want a second graph to appear. I am new to VBA and this is what I came up with so far:
Sub Iffuntion()
Dim SelectedChart As Range
Dim notVisible As Boolean
If Range("D100").Value = Range("E100").Value Then
ActiveSheet.ChartObjects("Testchart").Visible = True
Else
ActiveSheet.ChartObjects("Testchart").Visible = notVisible
End If
End Sub
It works, but I have to execute the VBA to make the graph appear/disappear and I would like that to happen automatically. Also the condition should eventually be in another worksheet to keep the sheet with the graphs nice and tidy. I read that to achieve this I have toI have to activate the other worksheet. Would you recommend this way or is there a better solution?
Thanks for the help and best regards!
Pete
EDIT: Here is the link to a sample file with the proposed solution of Cor_Blimey, that I couldn't get to work properly. The interconnections in the excel are more complicated than they would have to be, but I wanted to be as accurate ad possible in displaying what is actually happening in my excel. Thanks for taking a look!
https://dl.dropboxusercontent.com/u/18406645/sample.xlsm
Assuming you mean that they change, from a data validation drop down list, the contents of a cell then you can put your code into the Worksheet's Worksheet_Change event. This event is fired when the user changes the content of a cell (or by an external link).
Then test for the cell being the right cell then run your code.
Like:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Intersect(Target, Me.Range("D100"))
If Not rng Is Nothing Then
If rng.Value = Me.Range("E100").Value Then
Me.ChartObjects("Testchart").Visible = True
Else
Me.ChartObjects("Testchart").Visible = False
End If
End If
End Sub
I have a project whose requirements include a circular reference (just so you know why I'm deliberately putting this in my workbook).
Within the doc, I'd like for each cell in the circle to calculate only once. I know this is possible through the Windows Button > Excel Options > Formulas > Enable Iterative Calculations, but I have no way to enforce that option on everyone who touches the workbook. Is there any way (through VBA, maybe, or cell/sheet options?) to make a cell calculate its value only once?
Sounds like a longshot to me, but I really really appreciate your help :)
Something like this:
Private Sub Workbook_Open()
With Application
.Iteration = True
.MaxIterations = 1 '<-- or whatever the maximum allowable # you want
.MaxChange = 0.001 '<-- modify as necessary, or remove if desired
End With
End Sub
Private Sub Workbook_Close()
Application.Iteration = False
End Sub
Place these in the Workbook module.
This was one of the first answers on Google, which you would've found had you done any searching on your own:
http://www.mrexcel.com/forum/excel-questions/444155-need-macro-enable-iterative-calculation.html
A few questions!
Question One
I'd like this program to create three checkboxes. I want one that says "days" to be in A2, one that says "hours" to be in A3, and one that says "minutes" to be in A4. Is there any way to make it resize to fill in that cell, or do I have to size it manually?
Here is what I have so far:
Sub CheckBoxMacro()
ActiveSheet.CheckBoxes.Add(111.75, 28.5, 52.5, 17.25).Select
Selection.Characters.Text = "Hello World"
End Sub
I tried putting Range("A2") in where it has the numbers, but that didn't work.
Question Two
How do I delete a series from a graph? I'm making a graph using VBA, and it keeps adding a blank third series. It shows up in the legend, and I'm not sure how to make it go away.
Question Three
How do I make a graph fill a specific range? I found out how to do it using VBA a while ago, but I can't for the life of me find out how to do it again. I'd like a graph to fill a specific range, like F1 to K8. That way if the other columns to the left change due to user input, the graph while still stay in that range, making everything look nice.
Thank you!
Make a checkbox cover a cell
Sub CheckBoxMacro
With ActiveSheet.Range("A2")
ActiveSheet.CheckBoxes.Add(.Left, .Top, .Width, .Height).Select
Selection.Characters.Text = "Hello World"
End With
End Sub
If the series is blank, perhaps you are not correctly identifying the source data range. Otherwise, try this to remove the last series from the active chart:
ActiveChart.SeriesCollection(ActiveChart.SeriesCollection.Count).Delete
This is similar to the answer to 1.
Dim ChartRange As Range
Set ChartRange = ActiveSheet.Range("F1:K8")
With ActiveChart.Parent
.Left = ChartRange.Left
.Top = ChartRange.Top
.Width = ChartRange.Width
.Height = ChartRange.Height
End With