VBA Chart automation using ActivateChartDataWindow - vba

I'm building a chart automation script in powerpoint and i have any issue when calling upon "ActivateChartDataWindow".
I would use "Activate" instead of "ActivateChartDataWindow", but "Activate" loads the full Excel program and makes the whole routine run slow and ulgy.
The problem I have is that "ActivateChartDataWindow" does work to populate the charts, but when I manually go to edit the data - right click, edit data - to access the excel application, it does not seem to want to load!
It has been driving my crazy for the last 5 hours and would appreciate any ideas on how to over come this.
OLE.dlll are working correctly and the code I am using is given below.
Code below:
There are 5 slides with one chart on each page and the code below is what i am using as a point of concept
I have a felling i am using "ActivateChartDataWindow" wrong, but there is not much on the web to know what i am doing wrong! Arrrhhhh!
For i = 1 To 5
Set instance = Nothing
Set instance = ActivePresentation.Slides(i).Shapes(1).Chart.ChartData
With instance
.ActivateChartDataWindow
instance.Workbook.Sheets(1).Range("A1:H26").Value = 27
instance.Workbook.Close
End With
Next i
End Sub

As always recommended, you don't need to Activate an object to modify it. If you're trying to handle a Workbook embedded in a slide, you can do it this way
' This function will get you a Workbook object embedded in a Slide (late binding)
Function getEmbeddedWorkbook(sld As Slide) As Object
Dim shp As Shape
On Error Resume Next
For Each shp In sld.Shapes
If shp.Type = 3 Then ' embedded chart workbook created in PP
Set getEmbeddedWorkbook = shp.Chart.ChartData.Workbook
Exit Function
End If
If shp.Type = 7 Then ' embedded workbook pasted from excel
Set getEmbeddedWorkbook = shp.OLEFormat.Object
Exit Function
End If
Next
End Function
' For Testing, I have 6 slides, Some have a workbook pasted from Excel
' OLE, shape type = 7, others have a chart created in PP (type = 3)
Sub Test()
Dim wb As Object, i As Long
For i = 6 To 6 'ActivePresentation.Slides.Count
Set wb = getEmbeddedWorkbook(ActivePresentation.Slides(i))
If Not wb Is Nothing Then
wb.Sheets(1).Range("A1:D5").Value = i * i
End If
Next
End Sub

Related

VBA Word: Change Data of charts

I want to change the data of a chart in a Word Document, but I can't find the right way to address my charts. I tried several techniques, but nothing worked. (I´d love to open a ExcelSheet in which I can just change the Data)
So to put it all together: I want to change the data (not the source), of a MS Word chart, which looks like that:
Edit(13.8.):
After request, I try to give you some "reference Code" to work with.
Sub ChangeChart()
Dim aktDocument As Document
Dim chrt As Chart
Dim SourceSheet As Excel.Worksheet
Set aktDocument = ActiveDocument
Set SourceSheet = aktDocument.Shapes(1).Chart.OpenSourceData 'I know it´s not that easy
SourceSheet.Range("B5") = newStuff
aktDocument.Shapes(1).Chart.SetSourceData = SourceSheet
End Sub
I know this may sounds utopic and ridiculous, but I just don´t know, how to address the chart in the right way, or to even work with it properly.
Edit(15.08):
Even after recreating the old charts, the following code is not able to find a shape which has a chart. And therefore it stops when the index is out of range.
Sub Test()
i = 0
Do While i < 100
i = i + 1
If ActiveDocument.Shapes(i).HasChart Then
MsgBox "found one!"
End If
Loop
End Sub
Solution(30.08.):
The answer from #Cindy Meister was the solution to my problem. After further working with it, I came to the problem, that the ChartData always opens on the screen, while running the code.
Just for reference this question was my workaround.
All Office applications use the Excel engine to create and manage charts. In Word, charts can be formatted in-line with the text or with text wrap formatting. In the former case, a chart object needs to be addressed via the InlineShapes collection, in the latter via the Shapes collection.
Since your sample code uses Shapes(1) I've used that in the code snippet below. If it's not certain that the first Shape in the document is the chart, but you've assigned the Shape a name, you can use that as the index value (for example Shapes("MyChart"). Or you can loop the Shapes collection and check HasChart.
HasChart returns True if the Shape (or InlineShape) is a Chart. It's then possible to set Shape.Chart to an object variable. The chart's data can be accessed using Chart.ChartData.Activate - if you don't use Activate it's not possible to access the data when the chart's worksheet is stored in the Word document. Only then can Chart.ChartData.Workbook return a workbook object, and through that the worksheet can be accessed using ActiveSheet. From that point on, it's like working with the Excel object model.
Sub ChangeChart()
Dim aktDocument As Document
Dim shp As Word.Shape
Dim chrt As Word.Chart
Dim wb As Excel.Workbook, SourceSheet As Excel.Worksheet
Set aktDocument = ActiveDocument
Set shp = aktDocument.Shapes(1)
If shp.HasChart Then
Set chrt = shp.Chart
chrt.ChartData.Activate
Set wb = chrt.ChartData.Workbook
Set SourceSheet = wb.ActiveSheet
SourceSheet.Range("B5").Value2 = newData
End If
End Sub

VB.NET - Programatically close the chart data object

My program is automating PowerPoint to loop through a series of chart parameters and create a new chart per parameter set. So far it works well for the first chart - however, it throws an error when attempting to create a second chart because the chart data grid is already open, and I can't find a method to properly close or dispose of the data grid after generating the graph.
Abridged code:
Imports Powerpoint = Microsoft.Office.Interop.PowerPoint
Imports Excel = Microsoft.Office.Interop.Excel
Private Sub generatePowerPoint(Qnum As String)
Try
'Create PowerPoint object and assign a presentation / slide to it
Dim oApp As Powerpoint.Application
Dim oPres As Powerpoint.Presentation
Dim oSlide As Powerpoint.Slide
oApp = New Powerpoint.Application()
oApp.Visible = True
oApp.WindowState = Powerpoint.PpWindowState.ppWindowMinimized
oPres = oApp.Presentations.Add
'Prepare to generate charts based on parameters in a listbox
Dim slideCount = lbQuestions.Items.Count
For slideN = 1 To slideCount
'Add a blank slide per graph request
oSlide = oPres.Slides.Add(slideN, Powerpoint.PpSlideLayout.ppLayoutBlank)
'Create a new shape object for each slide
Dim chartShape(slideCount) As Powerpoint.Shape
' What's causing the error: assign a chart object to the next shape object.
' This works for the first slide, but then throws an error that the PowerPoint
'Chart Data Grid is still open, preventing it from creating a new chart.
chartShape(slideN - 1) = oSlide.Shapes.AddChart2(-1, ChartFind(chartType), 50, 50, 775, 410)
Dim cData = chartShape(slideN - 1).Chart.ChartData 'Activate to refresh
Dim workbook = cData.Workbook
workbook.Application.Visible = False
Dim datasheet = workbook.Worksheets(1)
Dim colNumber As Integer = 2
Dim firstRowNumber As Integer = 2
datasheet.rows.clear()
datasheet.columns.clear()
For r = categoryNames.Count - 1 To 0 Step -1
datasheet.Cells(r + firstRowNumber, 1) = categoryNames(r)
Next
... Code to assign data and format the chart object ...
'Refresh the range accepted by the chart object
chartShape(slideN-1).Chart.Refresh
'Loop again
Next
I've spent some time going through the PowerPoint Interop docs and the PowerPoint Chart Object Model docs on msdn (e.g. https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2010/ff760412(v=office.14), https://msdn.microsoft.com/en-us/vba/powerpoint-vba/articles/chartdata-object-powerpoint), and it seems that there's while there's a method to call the Chart Data Grid (chartdata.activate()) , there isn't a method to close the Chart Data Grid.
The exact error message thrown is "System.Runtime.InteropServices.COMException (0xBFFF64AA): The chart data grid is already open in 'Presentation 1 - PowerPoint'. To edit the data for this chart, you need to close it first. at Microsoft.Office.Interop.PowerPoint.Shapes.AddChart2( ..."
Does anyone have a suggestion?
Solved, mostly. For those who may have the same issue:
chartShape.Chart.ChartData.Workbook.close()
This is an undocumented method / IntelliSense will not provide it (hence the capitalization on Close), but after opening a chart object and editing the data, make sure you finish the code block with this before attempting to create a new chart object.
Now, this doesn't work if the open workbook isn't the one you opened (so for example, I can't test if there is a workbook opened by the user, and if so, close it). I'm resolving this issue by encapsulating the AddChart2 method in a Try Catch method, and if an error is thrown I let the user know to close the window and exit the subroutine so the program doesn't crash.

Run macro and hyperlink in one mouse click

I need a button in a PowerPoint slide that when I click it, it will, 1) run a macro and 2) hyperlink to another slide within the same presentation.
I can only see a way to do one or the other, not both at the same time.
My macro code is:
Sub question1_real()
Dim oSh As Shape
Dim oSl As Slide
Dim lScore As Long
' By doing it this way it's easy to change to a different slide if you
' need to later for some reason:
Set oSl = ActivePresentation.Slides(18)
' Change this if your shape is named something else:
Set oSh = oSl.Shapes("TextBox 2")
With oSh
' Make sure it's not blank to start with:
If Len(.TextFrame.TextRange.Text) = 0 Then
.TextFrame.TextRange.Text = "1"
End If
lScore = CLng(.TextFrame.TextRange.Text)
lScore = lScore + 1
.TextFrame.TextRange.Text = CStr(lScore)
End With
End Sub
My VBA skills are zero. The above code is borrowed from someone. I used the Insert Action option in PowerPoint to get it to work.
Assuming that you've given a shape a Run Macro action setting and chosen the subroutine you've posted above, you can add this function to the VBA project:
Sub JumpTo(lSlideIndex As Long)
SlideShowWindows(1).View.GoToSlide (lSlideIndex)
End Sub
Then wherever you want to jump to another slide, call it like so:
Call JumpTo(42) ' or whatever slide you want to jump to
or just
JumpTo 42
It's more convenient to have this in a Function if you need to use it more than once in the presentation. If it's strictly a one-shot, you can just paste this into your existing code:
SlideShowWindows(1).View.GoToSlide (42)

Excel VBA Retrieve Constant from Worksheet Code Fails When New Code is Written

In an attempt to retrieve constants from each worksheet in some reporting workbooks I use, three years ago I wrote some code that gets included in each worksheet. Here's an example of the code:
Option Explicit
' Determine the type of worksheet
Private Const shtType As String = "CR"
Public Function GetShtType()
GetShtType = shtType
End Function
In other code that gets the values from the worksheets for processing, the following section of code is used, where 'wksToCheck' is the worksheet in question. This code is stored in a personal macro workbook, not in the workbook with the worksheet code:
' Get the sheet 'type' if it has one
On Error Resume Next
shtType = wksToCheck.GetShtType()
If Err.Number <> 0 Then
' We do not have a type
shtType = "Unknown"
Err.Clear
End If ' Err.Number...
On Error GoTo Error_BuildTemplateWbk
My problem is, I use the code above to process workbooks several times a week, and I have for the past three years. Now, I am trying to write some new code with the above block to process the report workbooks in a different way. However, when I run code with the above block now, I get a 'Method or Data Member Not Found' error on the '.GetShtType()' portion of the code. I cannot compile the code and of course, consequently, the code doesn't work. I have tried adding the worksheet code to a worksheet in the macro workbook to see if that would fix the problem. It hasn't. Does anyone have any ideas? I am running Excel 2013 on a Windows 7 PC. Any ideas?
Brian
Using late-binding, should avoid the error, Dim wksToCheck As Object, but you'll lose the intellisense.
If you're open to alternatives, you may have better luck simply using the CallByName function, or using worksheet's CustomProperties.
Using CallByName preserves backwards compatibility with your older workbooks if needed:
shtType = CallByName(wksToCheck, "GetShtType", VbMethod)
Or, using CustomProperties instead of a custom method, in your worksheets:
Private Sub Worksheet_Activate()
Const PropName$ = "ShtType"
Const ShtType$ = "CR"
On Error Resume Next
Me.CustomProperties(PropName) = ShtType$
If Err.Number = 13 Then
Me.CustomProperties.Add "PropName", ShtType
End If
End Sub
Then,
' Get the sheet 'type' if it has one
On Error Resume Next
shtType = wksToCheck.CustomProperties("ShtType")
If Err.Number = 13 Then
' We do not have a type
shtType = "Unknown"
Err.Clear
End If ' Err.Number...
On Error GoTo Error_BuildTemplateWbk

Check whether a named textbox exist in the excel using VBA

Platform : MS Excel 2007(MS Visual Basic 6.0)
I have a few excel file with different textboxes in them.
All the textboxes were name. E.g TxTbox_AAAA, TxtBox_BBBB
Most of them have similar number of Textboxes with same name.
I also required to update the content inside the textboxes. But like i said... some excel file doesn't contain the textboxes.
E.g aaa.xls and bbb.xls have TexTbox_AAAA, TextBox_BBBB
and ccc.xls only have TexTbox_AAAA
my script is something like this
xlApp.ActiveSheet.TextBoxes("TextBox_AAAA").Text = TxtAAAA
xlApp.ActiveSheet.TextBoxes("TextBox_BBBB").Text = TxtBBBB
but if i run, it will encounter run-time error '1004':
Unable to get the TextBoxes property of the Worksheet class
which i suspect it is due to the excel doesn't have this textbox named "TextBox_BBBB"
so how do i put a check before xlApp.ActiveSheet.TextBoxes("TextBox_BBBB").Text = TxtBBBB
to check if this worksheet/activesheet doesn't contain TextBoxes("TextBox_BBBB"), it will not execute this step?
Since a TextBox is a Shape, here is one way to tell if a specific TextBox is on the activesheet:
Public Function IsItThere(sIn As String) As Boolean
IsItThere = False
If ActiveSheet.Shapes.Count = 0 Then Exit Function
For Each s In ActiveSheet.Shapes
If s.Name = sIn Then
IsItThere = True
Exit Function
End If
Next s
End Function
Not sure but try this:
Dim ws as Worksheet
Dim shp as Shape
Set ws = Activesheet '~~> change to suit
For Each shp in ws.Shapes
If shp.Name = "Textbox_Name" Then
'~~> your code here
End If
Next
Hope this helps
Thanks L42 and Gary's Student
I got it.. i should put
For Each s In xlApp.ActiveSheet.Shapes
instead of
For Each s In ActiveSheet.Shapes
only
Thanks for the help!!! =)