This might be a question stemming from ignorance of OOPS concepts, but I was wondering, is it possible to work one's way backwards and reach the parent object.
'To access the embedded workbook of a Powerpoint Chart, one can use this line of code
Dim EmbdWbk
Set EmbdWbk= ThisShape.Chart.ChartData.Workbook
'Similarly can one use something like the below code to reach the chart
Dim myChart as Chart
Set myChart = EmbdWbk.Parent.Parent.Parent
'As you can see from the immediate window snap below, this just takes me
'directly to the Application bypassing the Chart and Shape.
'So is there a way this can happen ?
Related
Helo all,
I'm trying to automate the reporting system at my work. To this end I'm setting up a Macro that, at the press of a button in Excel, will:
Open a new presentation from a given template (.potx) in a given path
Add various charts and tables
Save the newly created presentation in another given path
As this is pretty new to me I'm moving step by step, but I'm stuck at the beginning. This is my code so far:
Dim PP As PowerPoint.Application
Dim report As PowerPoint.Presentation
Dim report_activeslide As PowerPoint.Slide
'Dim Slide_1_text As Shape
Dim path_template As String
Dim path_report As String
path_template = "path_template.potx"
path_report = "path_report"
Set PP = New PowerPoint.Application
Set report = PP.Presentations.Open(path_template, False, True, True)
PP.Visible = msoTrue
'Set report_activeslide = report.Slides(1)
report.SaveAs path_report, ppSaveAsOpenXMLPresentation, msoTrue
End Sub
As of now I'm able to open the presentation from the template and correctly save it. However, the moment I actually start doing anything on the presentation itself, for example taking the comment off the
'Set report_activeslide = report.Slides(1) line, Excel hard crashes.
Does anyone know where the problem is?
I'm running Office 365 on Mac if that may be of any difference.
As Ike in the comments pointed out, the code works on Windows (I had the chance to test it myself). This pointed me to the possibility of my problem being due to Mac, not to code and, as it turns out, this is correct. Indeed there are more than a few people reporting the same issue (see for example: Excel VBA crashing when referencing a PowerPoint slide index number)
So for now, until Microsoft provides a better implementation of OLE there is nothing I can realistically do to solve this.
I have a VBA code that opens a workbook. It then does the following:
ThisWorkbook.Sheets("Sheet1").Shapes.SelectAll
Selection.Delete
I thought after the SelectAll, the Selection should be the shapes just being selected, which are what I want to delete. No. It's not. It's the active cell in the just-opened workbook and it's that active cell that's deleted. Usually, Selection after Select refers to the objects just being selected. Apparently, in the case of SelectAll, that's not true. How to set the focus to the just-selected shapes?
I changed my approach by doing SelectAll then assigned the selected shapes to a shaperange object following the method in Microsoft Docs. The method is in the following:
Set myDocument = Worksheets(1)
myDocument.Shapes.SelectAll
Set sr = Selection.ShapeRange
My code is:
ThisWorkbook.Sheets("Sheet1").Shapes.SelectAll
Set sr = Selection.ShapeRange
Unfortunately, that document doesn't say what the sr is declared to. I have declared it as a shape, shapes, ShapeRange, Object, Variant. In every case, Excel complained "Object doesn't support this property or method." I wonder what it's set to in the MS document.
I know I can delete all shapes using a For loop but I'm trying to avoid doing a loop.
ThisWorkbook.Sheets("Sheet1").Shapes.SelectAll
Selection.Delete
is fundamentally wrong because it attempts to convert a Shapes Collection into a Selection object.
The Selection object exists entirely and almost exclusively for the use and benefit of the user: the user may select something to show to VBA or VBA may select something to show to the user. In your example the user is excluded from the process. Therefore involvement of the Selection object is a waste of time and resources. You wouldn't have to ask your question if you weren't trying to make something work that isn't designed to work in that way.
The correct approach is to identify the object and do with it whatever you want. The object is either the collection of all shapes on the worksheet (ThisWorkbook.Sheets("Sheet1").Shapes) or any member of it, such as ThisWorkbook.Sheets("Sheet1").Shapes(1). You also have ThisWorkbook.Sheets("Sheet1").Shapes.Count at your disposal to loop through them all or For Each Shp in ThisWorkbook.Sheets("Sheet1").Shapes.
The ShapeRange object contains another collection. It's name promises a smaller collection than all shapes on the sheet. Don't let the choice of collections confuse you. The job is to identify one or several shapes and delete them. The fact of the matter is that you do have to deal with a member of a collection and not the Selection object.
I’d like to write visual basic code that adds a “new series” to an existing plot. I’ve already managed to write the code that will select that data I want to add. So to complete the operation I did it in excel, recording the following macro:
‘desired data already selected a column of x values and one of y values to be plotted
Selection.Copy
Sheets("XVSER").Select
ActiveSheet.ChartObjects("Chart 3").Activate
ActiveChart.Paste
However, what this recorded macro does not show is I wanted to add the data as a “new series”, even though this option was explicitly selected while recording the macro. So when I run the macro it does not do the same thing I did will recording it, and adds the data to an existing series instead of creating a new series for it.
Surely there must be a way of specifying in VBA that I’d like a new series. I just don’t know how, or where to find documentation, and what I found already on stackoverflow, was difficult for me to understand, and seemed to require a different approach, which I’d rather avoid, since I’ve already developed the code to successfully select the data I want, and to select the chart I want to paste it in.
When recording MACROS with charts, not allways the result comes out the same as when recorded it. You will need to familiarize yourself with some of the ChartObject properties.
Try the code below:
Option Explicit
Sub AddSelectionasNewSeries()
Dim ChtRng As Range
Dim ChtObj As ChartObject
Dim Ser As Series
' set the selection as range >> However, try avoid using slection
Set ChtRng = Selection
' set the chart object
Set ChtObj = Sheets("XVSER").ChartObjects("Chart 3")
' add a new series with the Selection
ChtObj.Chart.SeriesCollection.Add ChtRng
End Sub
You have to use SeriesCollection.Paste, which has parameters to specify whether to add points or series and so forth. The Macro Recorder doesn't know this.
Replace
ActiveChart.Paste
with
ActiveChart.SeriesCollection.Paste Rowcol:=xlColumns, Serieslabels:=False, _
CategoryLabels:=True, NewSeries:=True
I vainly try to set the AxisBetweenCategories property to False in a Userform ChartSpace. It is a clusteredBarChart. I did the same manually in a normal chart and it worked. Recording a Marco generated the code with the AxisBetweenCategories property. Why can't I use it in the Userform ChartSpace.
me.ChartSpace1.Charts(0).Axes(0).AxisBetweenCategories = False 'doesn't work
What do I miss?
Thanks
The "Chart" inside a ChartSpace object is of type ChChart and the same properties and methods you use on a Chart (worksheet, or chartsheet) do not translate directly so unfortunately the macro recorder won't be of much help, you will have to turn to good old fashioned debugging, trial & error.
I use the Locals window to examine the objects for a hint at the object model (that's how I observe the type is ChChart, etc.)
You can then look at the available properties and Google usually can point you in the right direction, like this example. Exploring the intellisense, I see that there are really limited options that are not the same as the Chart objects on a worksheet.
After all of that, this is probably not the answer you want to hear, but it can't be done the way you want it to be done.
This seems to verify that observation and suggests that while some things are the same, others can simply not be rendered the same way.
[Chartspace Charts do] not have the refined axis crossing as Excel
does. Features between the two will be similar in certain area and
not in others
And a similar example from Microsoft:
This example sets the category axis to cross the value axis at value zero (0) in the chart workspace.
Sub SetCrossingValue()
Dim chConstants
Dim axValueAxis
Dim axCategoryAxis
Set chtContants = ChartSpace1.Constants
Set axValueAxis = ChartSpace1.Charts(0).Axes(chConstants.chAxisPositionValue)
Set axCategoryAxis = ChartSpace1.Charts(0).Axes(chConstants.chAxisPositionCategory)
axValueAxis.CrossingAxis = axCategoryAxis
axCategoryAxis.CrossesAtValue = 0
End Sub
Okay, I have an excel macro that processes a lot of data and makes a lot of charts. I inherited the code from a guy that recently retired, while the code functions it is very inefficient so I am rewriting it. One of the things I am trying to fix is he activated/selected everything. I prefer to use references and never select/activate anything.
But I am running into a problem that when I create a new workbook or chart, it will steal focus from the original workbook. This is annoying, because I usually don't add the workbook object in my references for my main workbook.
For example, when I use these lines, the new chart/workbook becomes active
Set wb = Workbooks.Add Or Set wC = wb.Charts.Add
I then use Workbooks(FileName).Activate to reactivate the original workbook
I find it annoying to have to do this every time, and was wondering if there was a way to prevent the new objects from becoming active.
Edit: I just realized that other actions cause the charts to steal focus, like moving the chart with this command wC.Move After:=wb.Worksheets(wb.Worksheets.Count)
If you declare an old worksheet after a new one I believe this accomplishes what you want. For example,
Dim newWst As Worksheet
Dim oldWsk As Worksheet
Set newWst = Worksheets.Add
Set oldWst = Worksheets("Sheet1")
Cells(1, 1) = "Test"
worked for me. It added "Test" to the old worksheet.