DataLabel.Formula

WernerGg

New Member
Joined
Oct 19, 2010
Messages
43
Chart data Series can have DataLabels at all or some Points. Unfortunately no data Range as for X- and Y-Values can be associated to the labels as a whole. But at least one can manually enter a formula like "='MySheet'!$D$17" into a label and such have labels with arbitrary dynamic text.

The Excel DataLabel class does not support this formulas. It has no methods or properties for that. No idea why the <ACRONYM title=Microsoft>MS</ACRONYM> programmers just forgot that and do not repair that since years. Instead the class has two properties .Caption and .Text which provide the value (but not the formula) of the label text.

I know about an old trick using
Code:
strFormula = ExecuteExcel4Macro("GET.FORMULA(SELECTION())")
but this does no longer work in Excel 2007.

What is missing is a DataLabel.Formula property or methods so that on can write
Code:
With aDataLabel 
    oldFormula = .Formula 
    newFormula = NowIModifyThat(oldFormula) 
    .Formula = newFormula 
End With

In Excel 2010 this seems to exist but not in earlier versions.

Does anybody know how to get and set the formula of a data label? Does anybody have an undocumented trick or a DLL for that?
.
 
Workbook example ( Excel 2007 )

I've just gotten hold of a PC running XL 2007 and hopefully the code now works . I have also gathered all the scattered routines in the previous code into a single Function plus got rid of all the timers hence making the code much shorter, more compact and easier.

Code in a standard module:

Code:
Option Explicit
 
Private Declare Function FindWindowEx Lib "user32" _
    Alias "FindWindowExA" ( _
    ByVal hWnd1 As Long, _
    ByVal hWnd2 As Long, _
    ByVal lpsz1 As String, _
    ByVal lpsz2 As String) As Long
 
Private Declare Function PostMessage Lib "user32" _
    Alias "PostMessageA" _
    (ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lParam As Any) As Long
 
Private Declare Function SetFocus Lib "user32.dll" _
    (ByVal hwnd As Long) As Long
 
Private Declare Function LockWindowUpdate Lib "user32" _
    (ByVal hwndLock As Long) As Long
    
Private Declare Function OpenClipboard Lib "user32" _
(ByVal hwnd As Long) As Long
 
Private Declare Function EmptyClipboard Lib "user32" _
() As Long
 
 Private Declare Function CloseClipboard Lib "user32" _
() As Long

Private Const WM_SETFOCUS = &H7
Private Const WM_KILLFOCUS = &H8
Private Const WM_LBUTTONDOWN = &H201
 
Private bFBVisible As Boolean
Private oDataObject As Object
Private oActivecell As Range
Private lFBhwnd As Long
Private lXLhwnd As Long
 
Sub test()
    
   MsgBox GetDtataLabelFormula(sh:=Sheet1, chartIndex:=1, serie:=1, point:=4)
 
End Sub
 
Private Function GetDtataLabelFormula(sh As Worksheet, _
chartIndex As Long, serie As Long, point As Long) As String
 
    Dim t As Single
 
    On Error GoTo Oops
      
    'store the FBar visible state.
    bFBVisible = Application.DisplayFormulaBar
    
    'get the FBar hwnd.
    lXLhwnd = FindWindowEx(0, 0, "XLMAIN", Application.Caption)
    lFBhwnd = FindWindowEx(lXLhwnd, 0, "EXCEL<", vbNullString)
    
    'lock the screen update.
     LockWindowUpdate lXLhwnd
     
    'store the activecell.
    Application.Windows(ThisWorkbook.Name).Activate
    Set oActivecell = ActiveCell
    
    'show the FBar.
    If Not bFBVisible Then Application.DisplayFormulaBar = True
    
    'select the datalabel.
    sh.ChartObjects(chartIndex).Activate
    ActiveChart.SeriesCollection(serie).Points(point).DataLabel.Select
        
    'set the keyboard focus on the FBar.
    PostMessage lFBhwnd, WM_SETFOCUS, 0, 0
    PostMessage lFBhwnd, WM_LBUTTONDOWN, 0, 0
 
    'clear the clipboard.
    OpenClipboard 0
    EmptyClipboard
    CloseClipboard
 
    'copy the FBar text to the clipboard.
    With Application
        .SendKeys "{HOME}"
        .SendKeys "^+{END}"
        .SendKeys "^c"
        .SendKeys "{ESC}"
    End With
    
    'get a pointer to the dataobject interface.
    Set oDataObject = _
    GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
 
    'retrieve the text from clipboard.
    oDataObject.GetFromClipboard
 
    'select back the activecell.
    DoEvents
    oActivecell.Select
    
    'restore the FBar initial visible state.
    Application.DisplayFormulaBar = bFBVisible
 
    'run a brief delay to take effect.
    t = Timer
    Do
        DoEvents
    Loop Until Timer - t >= 0.1

    'return function with the FBar text.
    GetDtataLabelFormula = oDataObject.GetText()
 
    'restore the screen updating.
    LockWindowUpdate 0
 
    'cleanup.
    Set oDataObject = Nothing
  
    Exit Function
 
Oops:
 
    LockWindowUpdate 0
    DoEvents
    
    If Not oActivecell Is Nothing Then
        oActivecell.Select
    End If
    
    MsgBox Err.Description
    
End Function
 
Upvote 0

Excel Facts

Waterfall charts in Excel?
Office 365 customers have access to Waterfall charts since late 2016. They were added to Excel 2019.
Workbook example ( Excel 2007 )

I've just gotten hold of a PC running XL 2007 and hopefully the code now works . I have also gathered all the scattered routines in the previous code into a single Function plus got rid of all the timers hence making the code much shorter, more compact and easier.

Thanks Jaafar for this working solution. I have modified it a bit and written a test program. See: http://cid-756851a4f36096af.office.live.com/view.aspx/Public Documents/getFormulaXL2007.xlsm (Hopefully one can download the file).

I made some slight changes - see the program comments. The procedure GetSelectableFormula_DoesAll(aSelectable as Object) accepts anything which, after selection, shows its formula in the formula bar.
Code:
Option Explicit
Private Declare Function FindWindowEx Lib "user32" _
    Alias "FindWindowExA" ( _
    ByVal hWnd1 As Long, _
    ByVal hWnd2 As Long, _
    ByVal lpsz1 As String, _
    ByVal lpsz2 As String) As Long
Private Declare Function LockWindowUpdate Lib "user32" _
    (ByVal hwndLock As Long) As Long
 
Private Declare Function SetFocus Lib "user32.dll" _
    (ByVal hwnd As Long) As Long
Private Declare Function PostMessage Lib "user32" _
    Alias "PostMessageA" _
    (ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lParam As Any) As Long
Private Declare Function OpenClipboard Lib "user32" _
    (ByVal hwnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32" _
    () As Long
Private Declare Function CloseClipboard Lib "user32" _
    () As Long
Private Const WM_SETFOCUS = &H7
Private Const WM_KILLFOCUS = &H8
Private Const WM_LBUTTONDOWN = &H201
Private Const EGF_LOCK As Boolean = True   ' Lock screen updates during get formula
Private Const EGF_WAIT As Single = 0#  ' Waiting time in sec
 
Public Function GetSelectableFormula_DoesAll(aSelectable As Object) As String
' Get the formula out of a selectable Object. This can be anything, e.g.
' a DataLabel, a ChartTitle, a cell - whatever.
' Returns nullstring if no formula.
'
' 27.10.2010: Original by Jaafar Tribak, slightly modified by Werner Geiger (Gg):
'             - local instead of global variables
'             - Public instead of Private
'             - better error message
'             - locking and waiting controlled by global constants
'             - return nullstring if no formula
' 28.10.2010, Gg: Explicit DataLabel parameter
' 28.10.2010, Gg: Any selectable object as parameter
 
    Dim oDataObject As Object, oActiveCell As Range
    Dim bFBVisible As Boolean, lFBhwnd As Long, lXLhwnd As Long, t As Single
    Dim MyName As String
    MyName = "GetSelectableFormula_DoesAll"
    ' Initialize
    GetSelectableFormula_DoesAll = ""
    On Error GoTo Oops
 
    'store the FBar visible state.
    bFBVisible = Application.DisplayFormulaBar
 
    'get the FBar hwnd.
    lXLhwnd = FindWindowEx(0, 0, "XLMAIN", Application.Caption)
    lFBhwnd = FindWindowEx(lXLhwnd, 0, "EXCEL<", vbNullString)
 
    'lock the screen update.
    If EGF_LOCK Then LockWindowUpdate lXLhwnd
 
    'store the activecell.
    Application.Windows(ThisWorkbook.Name).Activate
    Set oActiveCell = ActiveCell
 
    'show the FBar.
    If Not bFBVisible Then Application.DisplayFormulaBar = True
 
    'select the object.
    aSelectable.Select
 
    'set the keyboard focus on the FBar.
    PostMessage lFBhwnd, WM_SETFOCUS, 0, 0
    PostMessage lFBhwnd, WM_LBUTTONDOWN, 0, 0
 
    'clear the clipboard.
    OpenClipboard 0
    EmptyClipboard
    CloseClipboard
    'copy the FBar text to the clipboard.
    With Application
        .SendKeys "{HOME}"
        .SendKeys "^+{END}"
        .SendKeys "^c"
        .SendKeys "{ESC}"
    End With
 
    'get a pointer to the dataobject interface.
    Set oDataObject = _
            GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
 
    'retrieve the text from clipboard.
    oDataObject.GetFromClipboard
    'select back the activecell.
    DoEvents
    oActiveCell.Select
 
    'restore the FBar initial visible state.
    Application.DisplayFormulaBar = bFBVisible
    'run a brief delay to take effect.
    '@@Gg: why?
    t = Timer
    Do
        DoEvents
    Loop Until Timer - t >= EGF_WAIT
    'return function with the FBar text.
    GetSelectableFormula_DoesAll = oDataObject.GetText()
    ' but not if it is no formula
    If Left(GetSelectableFormula_DoesAll, 1) <> "=" Then _
        GetSelectableFormula_DoesAll = ""
    'restore the screen updating.
    LockWindowUpdate 0
 
    'cleanup.
    Set oDataObject = Nothing
 
    Exit Function
Oops:
    LockWindowUpdate 0
    DoEvents
    If Not oActiveCell Is Nothing Then oActiveCell.Select
    MsgBox "Error " & Err.Number & ": " & Err.Description, vbOKOnly + vbExclamation, MyName
End Function

Disabling the locking makes sense only for debugging. The adjustable waiting time shows that the code works even with no wait. I hope that we do not really need this wait.


From performance reasons I then split the code into three procedures GetSelectableFormula_Open, GetSelectableFormula, GetSelectableFormula_Close which can be used like:
Code:
' Initialize the GetSelectableFormula-sequence
lFBhwnd = GetSelectableFormula_Open(oDataObject, bFBVisible, oActiveCell)
' We process all DataLabels on the Series
For Each pt In sht.ChartObjects(chartIdx).Chart.SeriesCollection(seriesIdx).Points
    If pt.HasDataLabel Then
        formula = GetSelectableFormula(pt.DataLabel, lFBhwnd, oDataObject)
        ' ...
    End If
Next pt
' We process the chart title
With sht.ChartObjects(chartIdx).Chart
    If .HasTitle Then
        formula = GetSelectableFormula(.ChartTitle, lFBhwnd, oDataObject)
        ' ...
    End If
End With
' Finalize the GetSelectableFormula-sequence
Call GetSelectableFormula_Close(oDataObject, bFBVisible, oActiveCell)

The three procedures are:
Code:
Public Function GetSelectableFormula_Open(ByRef oDataObject As DataObject, _
                    ByRef bFBVisible As Boolean, ByRef oActiveCell As Range) As Long
' Initialize for GetSelectableFormula
' See there
' 28.10.2010, Gg: created
 
    Dim lXLhwnd As Long, lFBhwnd As Long
    Dim MyName As String
    MyName = "GetSelectableFormula_Open"
    ' Initialize
    GetSelectableFormula_Open = 0
    On Error GoTo Oops
 
    'store the FBar visible state.
    bFBVisible = Application.DisplayFormulaBar
 
    'get the FBar hwnd.
    lXLhwnd = FindWindowEx(0, 0, "XLMAIN", Application.Caption)
    lFBhwnd = FindWindowEx(lXLhwnd, 0, "EXCEL<", vbNullString)
 
    'lock the screen update.
    If EGF_LOCK Then LockWindowUpdate lXLhwnd
 
    'store the activecell.
    Application.Windows(ThisWorkbook.Name).Activate
    Set oActiveCell = ActiveCell
 
    'show the FBar.
    If Not bFBVisible Then Application.DisplayFormulaBar = True
 
    'get a pointer to the dataobject interface.
    Set oDataObject = _
            GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
 
    'return function with the FBar handle.
    GetSelectableFormula_Open = lFBhwnd
 
    Exit Function
Oops:
    LockWindowUpdate 0
    DoEvents
    If Not oActiveCell Is Nothing Then oActiveCell.Select
    MsgBox "Error " & Err.Number & ": " & Err.Description, vbOKOnly + vbExclamation, MyName
End Function
Public Function GetSelectableFormula(aSelectable As Object, _
            lFBhwnd As Long, oDataObject As DataObject) As String
' Get the formula out of a selectable Object aSelectable. This can be anything, e.g.
' a DataLabel, a ChartTitle, a cell - whatever.
' Returns nullstring if no formula.
' The other parameters are delivered by a preceeeding call to GetSelectableFormula_Open
' - lFBhwnd must be the formula bar window handle.
' - oDataObject must be a dataobject interce object
'
' Usage:
'   ' get the current context and the formula bar window handle
'   lFBhwnd = GetSelectableFormula_Open(oDataObject, bFBVisible, oActiveCell)
'   ' process all objects you want
'   ...
'   formula = GetSelectableFormula(aSelectable, lFBhwnd, oDataObject)
'   ...
'   ' restore the former context
'   Call GetSelectableFormula_Close(oDataObject, bFBVisible, oActiveCell)
'
' Alternative, which does all three steps in one:
'   formula = GetSelectableFormula_DoesAll(aSelectable)
'
' 27.10.2010: Original by Jaafar Tribak, slightly modified by Werner Geiger (Gg):
'             - local instead of global variables
'             - Public instead of Private
'             - better error message
'             - locking and waiting controlled by global constants
'             - return nullstring if no formula
' 28.10.2010, Gg: Any selectable object as parameter
' 28.10.2010, Gg: Splitted into three parts
 
    Dim t As Single
    Dim MyName As String
    MyName = "GetSelectableFormula"
    ' Initialize
    GetSelectableFormula = ""
    On Error GoTo Oops
 
    'select the object.
    aSelectable.Select
 
    'set the keyboard focus on the FBar.
    PostMessage lFBhwnd, WM_SETFOCUS, 0, 0
    PostMessage lFBhwnd, WM_LBUTTONDOWN, 0, 0
 
    'clear the clipboard.
    OpenClipboard 0
    EmptyClipboard
    CloseClipboard
    'copy the FBar text to the clipboard.
    With Application
        .SendKeys "{HOME}"
        .SendKeys "^+{END}"
        .SendKeys "^c"
        .SendKeys "{ESC}"
    End With
 
    'retrieve the text from clipboard.
    oDataObject.GetFromClipboard
    'run a brief delay to take effect.
    '@@Gg: why?
    t = Timer
    Do
        DoEvents
    Loop Until Timer - t >= EGF_WAIT
    'return function with the FBar text.
    GetSelectableFormula = oDataObject.GetText()
    ' but not if it is no formula
    If Left(GetSelectableFormula, 1) <> "=" Then _
        GetSelectableFormula = ""
    Exit Function
Oops:
    LockWindowUpdate 0
    DoEvents
    MsgBox "Error " & Err.Number & ": " & Err.Description, vbOKOnly + vbExclamation, MyName
End Function
Public Function GetSelectableFormula_Close(oDataObject As DataObject, _
                    bFBVisible As Boolean, oActiveCell As Range) As Boolean
' Finalize for GetSelectableFormula
' See there
' 28.10.2010, Gg: created
 
    Dim t As Single
    Dim MyName As String
    MyName = "GetSelectableFormula_Close"
    ' Initialize
    GetSelectableFormula_Close = False
    On Error GoTo Oops
 
    'restore the FBar initial visible state.
    Application.DisplayFormulaBar = bFBVisible
    'select back the activecell.
    oActiveCell.Select
 
    'cleanup.
    Set oDataObject = Nothing
 
    'restore the screen updating.
    LockWindowUpdate 0
    DoEvents
 
    'return function
    GetSelectableFormula_Close = True
    Exit Function
Oops:
    On Error GoTo 0
    LockWindowUpdate 0
    DoEvents
    If Not oActiveCell Is Nothing Then oActiveCell.Select
    MsgBox "Error " & Err.Number & ": " & Err.Description, vbOKOnly + vbExclamation, MyName
End Function
 
Upvote 0
I made the error handling code of my routines
  • GetSelectableFormula_DoesAll
  • GetSelectableFormula_Open,
    GetSelectableFormula,
    GetSelectableFormula_Close
a bit more robust. You can find the workbook with the code and a test procedure in the MS Windows/Office Live/Office SkyDrive cloud:
http://cid-756851a4f36096af.office.live.com/view.aspx/Public Documents/getFormulaXL2007.xlsm


It's a bit tricky to download from the MS cloud:
  • Click the link
  • An Excel Web-App will start which shows the workbook. But this is useless, because it can handle no VBA. Don't use the App's File menue for download. This will give you a castrated version without the code.
  • Left click the file name "getFormulaXL2007.xlsm" on the very top above the Excel Web-App.
  • This will lead to another page where you can see and download the pure file.
And I registered like Jaafar on Box.net. You can find the workbook there:
http://www.box.net/shared/xl3l6q0g5z
The download is straight forward.
 
Upvote 0
Werner

I'm going through the code and was just wondering why you don't use Selection.Formula once you've selected the data point.

When I do that I seem to get the formula, though I am using Excel 2010.

Perhaps that's the difference.

Anyway I removed the screen locking and clipboard stuff and jiggled the code about a wee bit and it seems to work.

Note, I am in no way suggesting what I tried is a solution - I'm pretty sure it isn't.

Haven't had a chance to fully test but it does seem to work in some cases.

Plus I am using Excel 2010.:)

Oh and when I do test the code it keeps on locking Excel up.:eek:
 
Upvote 0
As we established back on page 1, there is no Formula property in prior versions.
 
Upvote 0
Rory

I do realise that.:)

I did say I was using Excel 2010 and it's unlikely to be a solution, but perhaps it's worth a try in other versions.

If I get a chance I'll try it on other versions, but I don't have access to 2007 which is apparently the version this is intended for.
 
Upvote 0
I don't understand. We already established it doesn't work on older versions as the property does not exist, so what do you intend to try exactly?
 
Upvote 0
Rory

It's just a suggestion, like I said it worked for me, but I also clearly stated and have all along stated that I'm using 2010.

I can't test on earlier versions right now, but I will when I get a chance.

And I just did and, as I expected, it didn't work.

I apologize.:)
 
Upvote 0
I have two slight changes to the code
  • There where some "on error resume next" before (!) the MsgBox displaying the error. This is nonsense. Both statements must be switched.
  • The line(s): "Application.Windows(ThisWorkbook.Name).Activate"
    must be removed if the code runs in an add-in
 
Upvote 0
Werner

I'm going through the code and was just wondering why you don't use Selection.Formula once you've selected the data point.

When I do that I seem to get the formula, though I am using Excel 2010.

Perhaps that's the difference.

Anyway I removed the screen locking and clipboard stuff and jiggled the code about a wee bit and it seems to work.

Note, I am in no way suggesting what I tried is a solution - I'm pretty sure it isn't.

Haven't had a chance to fully test but it does seem to work in some cases.

Plus I am using Excel 2010.:)

Oh and when I do test the code it keeps on locking Excel up.:eek:

Ohh Norie! The whole thing is about DataLabel and ChartTitle having no ".Formula"-property in Excel 2007. In Excel 2010 there is no problem at all.
Hence if you code "formula = Selection.Formula" or directly without selection "formula = aSelectable.Formula" you get an error "438, object does not support this method" under xl2007.
 
Upvote 0

Forum statistics

Threads
1,216,091
Messages
6,128,775
Members
449,468
Latest member
AGreen17

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top