VBA Word: Change Data of charts - vba

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

Related

Use VBA to change source file of chart pasted into PowerPoint using Link Data option

I have a PowerPoint presentation in which I create charts in Excel and then link them into the PowerPoint. There are two ways to do this:
Paste Special > Paste Link > Microsoft Excel Chart Object
Paste > Keep Source Formatting and Link Data / Use Destination Theme and Link Data
I would late like to use VBA to change the source Excel file. To do this, consider the following code:
Private Sub PrintLinks()
Dim pptPresentation As Presentation
Dim pptSlide As Slide
Dim pptShape As Shape
Set pptPresentation = ActivePresentation
For Each pptSlide In pptPresentation.Slides
For Each pptShape In pptSlide.Shapes
If pptShape.Type = msoChart Or pptShape.Type = msoLinkedOLEObject Or pptShape.Type = msoLinkedChart Then
Debug.Print pptShape.LinkFormat.SourceFullName
pptShape.LinkFormat.SourceFullName = "PATH/TO/NEW/FILE"
pptShape.LinkFormat.Update
End If
Next
Next
End Sub
This will work for the Paste Link case, but not the Link Data case, in which case pptShape.Type = msoChart. My question is if there is a way to make it work with Link Data as well. Wtih Paste Link, the SourceFullName property will point to a specific chart object, like filename1.xlsx!Chart 1, and changing it to filename2.xlsx!Chart 1 will work as expected. In contrast, under the Link Data option the SourceFullName property only points to filename1.xlsx and I cannot figure out how to see what chart object within the file it is pointing to. Regardless, if I change SourceFullName to filename2.xlsx no error will be thrown, but as far as I can tell the pointer is still to filename1.xlsx, as the chart doesn't change.

VBA Chart automation using ActivateChartDataWindow

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

Referencing Charts By Name Only in PowerPoint VBA

I have been searching for hours to try to find the answer to this question, but to no avail, so I'm hoping I can find the answer here.
I want to create a variable that refers to a pre-existing chart in PowerPoint so I can start automating its data. I want to refer to the chart by its name to make things very easy, but no matter what I do I cannot seem to give PPT a satisfactory Chart address.
I have tried almost every possible variation of the below, but without success:
Dim chrtPP As PowerPoint.Chart
Set chrtPP = ActivePresentation.Slides(1).Shapes.Charts("Chart3")
Could someone please tell me what I'm doing wrong?
Thanks!
You need to reference the shape by name (a 'Shape" in PowerPoint is actually any object that is on a slide and can be a simple shape, textbox, table, chart, group, media clip etc.). If you're on PowerPoint 2010 and higher, press Alt+F10 to open the selection pane to find the name of the selected chart object. It may be a standard chart object or a chart within a placeholder object. You can then reference the chart as follows:
Option Explicit
Sub ChartStuff()
Dim oShp As Shape
Dim oCht As Chart
Set oShp = ActivePresentation.Slides(1).Shapes("Chart 3")
If oShp.HasChart Then
Set oCht = oShp.Chart
End If
' Do stuff with your chart
If oCht.HasTitle Then Debug.Print oCht.ChartTitle.Text
' Clean up
Set oShp = Nothing
Set oCht = Nothing
End Sub
The key in programming PowerPoint is to ignore the object name in the Object Model for 'Shape' as it's very misleading!

How to add a new spreadsheet with VBA-Code, using VBA

I am creating a macro and part of the macros function is to make VBA create a new spreadsheet. Because of the nature of distribution the name will change. I need to add code to this spreadsheet. Is there anyway I can do this?
Jook has already explained how it works. I will take it a step further.
The syntax of adding a worksheet is
expression.Add(Before, After, Count, Type)
If you check inbuilt Excel's help then you can see what Before, After, Count, Type stands for
FROM EXCEL"S HELP
Parameters (All 4 parameters are Optional)
Before - An object that specifies the sheet before which the new sheet is added.
After - An object that specifies the sheet after which the new sheet is added.
Count - The number of sheets to be added. The default value is one.
Type - Specifies the sheet type. Can be one of the following XlSheetType constants: xlWorksheet, xlChart, xlExcel4MacroSheet, or xlExcel4IntlMacroSheet. If you are inserting a sheet based on an existing template, specify the path to the template. The default value is xlWorksheet.
Once the sheet is created then you need to use .insertlines to create the relevant procedure and to also embed the code that you want to run.
NOTE - IMP: If you want the code to embed code in the VBA project, you need to ensure that you have "Trust Access to the VBA Project Object Model" selected. See snapshot.
Here is an example where I am creating a sheet and then embedding a Worksheet_SelectionChange Code which will display a message "Hello World"
CODE - TRIED AND TESTED
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim nLines As Long
Dim VBP As Object, VBC As Object, CM As Object
Dim strProcName As String
Set ws = Worksheets.Add
Set VBP = ThisWorkbook.VBProject
Set VBC = VBP.VBComponents(ws.Name)
Set CM = VBC.CodeModule
strProcName = "Worksheet_SelectionChange"
With ThisWorkbook.VBProject.VBComponents( _
ThisWorkbook.Worksheets(ws.Name).CodeName).CodeModule
.InsertLines Line:=.CreateEventProc("SelectionChange", "Worksheet") + 1, _
String:=vbCrLf & _
" Msgbox ""Hello World!"""
End With
End Sub
This is how the new sheet code area looks once you run the above code.
the following code will add you a spreadsheet.
Public Sub Workbook_Add()
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets.Add(, , 1, xlWorksheet)
With wks
'set codename of wks
ThisWorkbook.VBProject.VBComponents(.CodeName).Name = "tblWhatever"
'set tablename of wks
.Name = "whatever"
'add code (untested demo)
'ThisWorkbook.VBProject.VBComponents(.CodeName).CodeModule.InsertLines 1, "Option Explicit"
'add code (as of example from excel-help)
'Application.VBE.CodePanes(1).CodeModule.InsertLines 1, "Option Explicit"
End With
End Sub
If you need to add VBA-Code to this specific spreadsheet, you should further inspect the VBProject object - look for CodeModule and then i.e. InsertLines.
A further hint for you - I would try to use the CodeNames of your tables. It is less likely to be changed - BUT it might be not that comfortable to use in your code at first. I had to get used to it, but for me it has many advantages against using a tables name.
Hope this helps ;)
The default .Add method adds a sheet at the start of the list. Often you want to add it at the end before adding the code lines, as explained by Siddarth Rout. To do that anywhere you can use:
ActiveWorkbook.Worksheets.ADD After:=ActiveWorkbook.Sheets(ActiveWorkbook.Worksheets.Count)
It is easier to read if you have defined and set WB:
Dim WB as Excel.workbook
Set WB = ActiveWorkbook
WB.Sheets.ADD After:=WB.Sheets(WB.Sheets.Count)
Set VBC = ActiveSheet 'If using in Siddarth Rout's code above
Sheets and Worksheets are interchangeable, as illustrated.

Exporting Excel Range as image (VB.NET)

I have a working excel vba macro that does what I want from here and I am trying to convert it to VB.NET.
The code from VBA:
Sub bah()
''' Set Range you want to export to file
Dim rgExp As Range: Set rgExp = Range("B2:C6")
''' Copy range as picture onto Clipboard
rgExp.CopyPicture Appearance:=xlScreen, format:=xlBitmap
''' Create an empty chart with exact size of range copied
With ActiveSheet.ChartObjects.Add(Left:=rgExp.Left, Top:=rgExp.Top, _
Width:=rgExp.Width, Height:=rgExp.Height)
.Name = "ChartVolumeMetricsDevEXPORT"
.Activate
End With
''' Paste into chart area, export to file, delete chart.
ActiveChart.Paste
ActiveSheet.ChartObjects("ChartVolumeMetricsDevEXPORT").Chart.Export "C:\Users\ajohnson\Desktop\workdamnit.jpg"
ActiveSheet.ChartObjects("ChartVolumeMetricsDevEXPORT").Delete
End Sub
What this does is take an excel range and then put it into a chart that is a copy of the range and save it as a JPG.
Here is my most recent attempt at making it VB.NET:
Dim xlApp As New Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim xlRange As Excel.Range
xlWorkBook = xlApp.Workbooks.Open("C:\test.xlsx")
xlWorkSheet = xlWorkBook.Sheets("Sheet1")
xlRange = xlWorkSheet.Range("B2:C6")
With xlWorkSheet.ChartObjects.add(xlRange.Left, xlRange.Top, xlRange.Width, xlRange.Height)
.name = "Chart1"
.activate()
End With
xlWorkSheet.ChartObjects("Chart1").Paste()
xlWorkSheet.ChartObjects("Chart1").chart.export(Filename:="C:\Users\ajohnson\Desktop\saveit.jpg")
xlWorkSheet.ChartObjects("Chart1").delete()
I am running into trouble converting the ActiveChart.Paste method. I can't get it to work in VB.NET. It either throws an error or It just leaves an empty box when I do it in VB.NET (if I add .chart before the paste it runs, but doesn't paste any values), but in VBA it fills in the values of interest. I have tried creating a chart object, but that did not seem to work either.
I feel like I am close to having it sorted out, but I can't quite get it. I suppose I could leave it as a VBA macro and call it from VB.NET, but that seems absurd on some level. Any help would be greatly appreciated. I am also open to different approaches, its just this is the thing I came across that worked well in VBA, so I figured it was a good starting point.
Thanks as always!
I just had to hit the MSDN up a little harder to get there. Turns out you have to put the chartobject inside a chart, the code I got working looks like:
xlRange = xlWorkSheet.Range("B2:C6")
xlRange.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture)
Dim oChtobj As Excel.ChartObject = xlWorkSheet.ChartObjects.add(xlRange.Left, xlRange.Top, xlRange.Width, xlRange.Height)
Dim oCht As Excel.Chart
oCht = oChtobj.Chart
oCht.Paste()
oCht.Export(Filename:="C:\saveit.jpg")
oChtobj.Delete()
I was going to delete the question, since it got solved by me so quickly (this ignores the decent bit of time I spent before I posted it here), but when I search for a problem like mine it comes to this page, so maybe this will help someone in the future. If you are looking to copy a range from excel to a jpg for some reason (perhaps attaching it to the body of an outlook email, because that is what I am doing), this should work for you.
And the C# equivalent requires the call to Activate() or COMException will be thrown
Excel.Range xlRange = xlWorkSheet.Range("B2:C6");
range.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture);
Excel.ChartObject chartObj = myWorksheet.ChartObjects().Add(range.Left, range.Top, range.Width, range.Height);
chartObj.Activate(); // Don't Forget!
Excel.Chart chart = chartObj.Chart;
chart.Paste();
chart.Export(#"C:\image.png");
chartObj.Delete();