One of these Excel Autoshapes is not acting like the other - excel

I have the same snippet of code opening three different macros...
Set c = ActiveSheet.Shapes(Application.Caller)
In two of them, that line captures the shape I need just fine. In the third, it throws...
Run-time error '-2147024809 (80070057)':
The item with the specificed name wasn't found.
Yet when I debug and highlight Application.Caller in this problem macro, I can see it knows what shape it's looking at (in this case, msoShapeSnip2SameRectangle). The ones that work are msoShapeDownArrow and msoShapeMathMultiply, if that makes any difference.
Any ideas on why it's not working in this third macro? I've tried defining it both as a Shape and Object first.

Seems like there's a length limit to the value passed to Application.Caller
If I insert that shape type to a sheet I get a shape called "Snip Same Side Corner Rectangle 1" (length=33), but the value passed to Application.Caller is "Snip Same Side Corner Rectangl" (length=30)
Note it's not a problem with the specific shape type, just the length of the default name. If you rename the shape to something shorter it should be fine.
EDIT: previously - How to get the Shape Clicked without Application.Caller

Related

How to reference "active/selected" chart data point in Excel using VBA

I am looking for a way to reference active/selected chart data point in Excel using VBA.
Imagine I have a line chart, which I would like to add an error bar to. But, I do not want to add error bars to the whole series, but only to ONE, selected point. See the screen below:
What I want to do is to add a vertical error bar that would point down to the X-axis, something like this:
I KNOW how to do it in Excel, there are multiple ways, for example, adding a new one-point series and then adding an error bar. There are other ways. The issue I have is HOW to reference active/selected data point.
If I would choose to create a new, one point series, I need to know the point number to do that. I know (I used it) that you can reference points with Points object/method. Sadly, I do not know how to extract the selected point number, coordinates, whatever, so I can work with it later on in my project.
I cannot add any code, as everything I have done is formatting and playing with error bars, as well as iterating through existing, ALL data points (the code would have no use in this case). What I am looking for is THE selected point information, so I could refer to it as .Point(x) with x being my previously extracted point number, without being forced to reference point number right away like .Point(8) (I do not know the specific number, as I just clicked on it).
I have seen the way to extract it using chart events, but this is a an overkill for what I want to do in my little simple project (especially how to reference the "extracted" point in other macros, outside the class module).
Any ideas? All help is greatly appreciated, as I am lost after 3 days of trying to find the way to reference it.
To get the index, you can parse the point's Name, which is in the format:
S<series number>P<point number>
Sub Test()
If TypeOf Selection Is Point Then
Dim p as Point
Set p = Selection
Debug.Print CLng(Split(p.Name, "P")(1)) ' this is p's index
End If
End Sub
To get more information about that point, such as the x and y values, perhaps you could do the following:
Sub Test()
If TypeOf Selection Is Point Then
Dim p As Point
Set p = Selection
Dim i As Long
i = CLng(Split(p.Name, "P")(1))
Dim s As Series
Set s = p.Parent
Debug.Print s.Values(i) ' Values is a one-based array so you can use the point index to get its corresponding value
Debug.Print s.XValues(i)
End If
End Sub

"On Error GoTo" ignored when searching for second horizontal axis

NOTE: the code below actually works! See my own answer on the cause of the issue I was having. I decided to leave the code here since I have seen other questions regarding how to delete second horizontal axis.
THE INITIAL QUESTION/ISSUE: I'm formating a series of spreadsheets that have multiple charts on them. When applying the chosen chart style (I'm using style 209 - with a code line "ActiveChart.ChartStyle = 209), some charts come back with two horizontal axis, which I don't want (some charts have two vertical axis - but that is OK). Instead of going chart by chart and manually deleting each secondary horizontal axis, I included a piece of code on my formating subroutine. The code works most of the time. But sometimes I get the error below:
VB error image
The impression I have is that the "On Error GoTo" is being "ignored". I.e. the error above happens when I get to "ActiveChart.SetElement..." line, as the chart has no secondary axis. This means that the line where I asked for the secondary axis' maximum scale (i.e., "chart_axis = ...") must have returned an error (as the secondary axis doesn't exist). Which means that the "On Error GoTo" was ignored (or didn't jump to "No_second_axis").
Here is the part of the code I'm using that deletes the second axis (if it exists):
Dim s_name As String
Dim chart_axis As Variant
For Each Shape In ActiveSheet.Shapes
s_name = Shape.Name
If Shape.Type = msoChart Then
ActiveSheet.ChartObjects(s_name).Activate
On Error GoTo No_second_axis
'Try to get the "scale" of secondary horizontal axis - error if non-existent
chart_axis = ActiveChart.Axes(xlValue, xlSecondary).MaximumScale
'If it reached this line, there was no error when getting the second horizontal axis scale (i.e., the second horizontal axis exists. No I can delete it!
With ActiveChart
ActiveChart.SetElement (msoElementSecondaryCategoryAxisNone)
End With
No_second_axis:
End If
Next Shape
End Sub
Am I missing something? Why does the "On Error Go To" appears to work sometimes but doesn't work for some charts? I can't find a "pattern" in terms of which type of chart it works with vs. a type of chart it doesn't work with.
After an extra couple of hours struggling with this issue, I decided to inspect each chart before running the sub. Using "Go To" on Excel (shortcut = F5) and selecting "objects", I could cycle through each object (by pressing TAB). What I realized is that I had some "hidden" charts (i.e., very old charts that were somehow minimized/collapsed into a obscure place in the spreadsheet). These charts had no "series" on them. For some reason, the "chart_axis = ..." part of the code above can read a secondary horizontal axis scale, but the axis really doesn't exist (as I get an error when trying to delete such axis). Maybe this is a bug on Excel or there is a logical explanation for it - but this is beyond what I need for now. I decided to answer my own question in case this example helps someone else.
The error you are getting is a generic Office error that suggests something went wrong under the hood.
To try and avoid this error I would try the following:
Use Application.ScreenUpdating=false in the beginning of the function (and then Application.ScreenUpdating=true in the end). This helped me avoid rendering problems in the when updating a large number of objects/shapes in an Office document.
OR
Use Application.ScreenUpdating=false in the beginning of every iteration of your Shape object loop and then use Application.ScreenUpdating=true after updating it.
Hopefully you will be able to spot which of the charts creates a problem and under which circumstances (or state).

Dynamic Range for Intentionally Showing Nothing

So, I've created a dynamic range for a chart, that's all well and easy.
However, in this chart there are two lines, but I only want one of the lines to show up under certain conditions, else it displays nothing! So I've tried creating my dynamic range as follows
=IF('WorksheetName'!$M$10 ='WorksheetName'!$F$31,'WorkSheetName'!dynamic_range, #N/A)
The problem is that when I do this the chart freaks out. It gives me this error:
Your formula contains an invalid external reference to a worksheet.
Verify that the path, workbook, and range name or cell reference are
correct, and try again.
If I click "ok" half the time it shows up correctly (that is, the second line disappears and the chart adjusts accordingly) and the other half the time it glitches.
Basically, how do I create a dynamic range for graphing that the chart will understand when I want it to do NOTHING and when I want it to display the range?
You need a second source range, that's cells are just empty. Applying your approach to switch between the filled range (intended to be visible) vs. the empty range (will be invisible), shall solve the issue. Note: The chart parameter "Show empty cells as:" should be set to "Gaps". (Refer to the Hidden and Empty Cells options in the chart's Select Data dialog. This is applicable to X/Y charts mainly.)

Excel VBA: Copying color from Cell.Interior.Color to MSForms.Label.BackColor

I have a userform in Excel 2003 which contains some MSForms.Label controls. I want to set the .BackColor property of each of these controls such that they match the color of some individual cells on a worksheet.
To do this I am reading the .Interior.Color property of those cells, converting it to hex and using that value to set the .BackColor property of the Label objects.
My problem is that the value coming out of .Interior.Color is almost always incorrect the first time it is read. I have tested this by running the following command in the VBA editor immediate window:
Print Hex([sourceCell].Interior.Color)
This command almost always gives the wrong value the first time round, but gives the correct value from the second time onwards. If I change the fill color of [sourceCell] and run the command again it will do the same thing, i.e. wrong value first time, right value second time onwards.
The cells in question are all filled with colors from the chart lines/fills color selection (i.e. the two bottom rows you can see in Excel's "Format Cells" dialog under the "Patterns" tab). These colors have been modified by me to give a custom set of colors and, tellingly, the "wrong" values seem to match Excel's defaults for the customized range of color picks (i.e. the default chart line/fill colors you get when you start a new workbook).
Has anyone else experienced this behaviour/have a workaround? When I try to read the values twice at runtime it doesn't work, i.e. it doesn't switch to the correct value. The code must be stopped and the userform reloaded to force the "correct" values to come out.
Kludge/workaround via Application.OnTime.
If I run the userform prep code to set the label objects' backcolors with the userform hidden, then set the main code to run from an immediate OnTime event (making sure to re-run the prep code as part of the OnTime) then I can force Excel to give me the correct "second time round" values when showing the form.
This works for me:
MyForm.MyControl.BackColor = Range(myrange).Interior.Color
.Interior.Color returns a Variant containing the RGB of the sampled range.
.Interior.ColorIndex always returns -4140 or something weird, probably because .ColorIndex is peculiar to Excel2003's color limitations.

access a chart's shape ID - excel vba

Some background first.
Excel allows duplicate names for shapes. That is, you can have both a ChartObject and an oval shape in the same worksheet with exactly the same name. You can also have two charts named both "Chart 2". If you try to reference a shape with a duplicate name, e.g.
ActiveSheet.Shapes("Dupe").Select,
excel seems to resort to returning the object with the lowest ID (and the duplicate name).
There is no way (that I know of) of linking an ActiveChart with its corresponding containing shape.
I want to create a function like
function GetAChartsShape(c as chart) as Shape,
but I don't know how. The immediate use for this would be to format the selected chart (since there is no way of globally changing a chart's font). Of course, this could also have other uses.
The name of the shape containing an embedded chart (the shape is also the chartobject) is:
activechart.parent.name
or if c is declared a chart:
c.parent.name
But of course you know you don't need to select an object to work on it, so just do what you need to do on
c.parent
which avoids the problem of duplicate names.

Resources