How to SET category/series name in PowerPoint charts? - vba

I'm writing a macro to set categories/series names. New labels are taken from some dictionaries. My first step however was to get those names from each chart. So, in order to get it, I used the code below:
'works fine
'x - any integer
'whole sentence
Application.ActivePresentation.Slides(x).Shapes(x).Chart.ChartGroups(x).CategoryCollection(x).Name
'with variables
Dim objChart As Chart
Dim objChartGroups As ChartGroups
Dim objChartGroup As ChartGroup
Dim objCategoriesColl As CategoryCollection
Dim objCategory As ChartCategory
Dim strCategory As String
Set objChart = ActivePresentation.Slides(x).Shapes(x).Chart
Set objChartGroups = objChart.ChartGroups(x)
Set objChartGroup = objChartGroups.Item(x)
Set objCategoriesColl = objChartGroup.CategoryCollection
Set objCategory = objCategoriesColl(x)
strCategory = objCategory.Name
I checked this property (Name) many times on Microsoft Docs (https://learn.microsoft.com/office/vba/api/powerpoint.chartcategory.name) and it is stated that it is a read/write property. However, when I try to set a new name (in the code below) I receive an error. Is it possible there's a mistake in Docs?
Public Sub EnterNewChartCats( _
lngCategoriesCount As Long, _
objCategoriesColl As CategoryCollection, _
dctDT As Dictionary, _
dctConsts As Dictionary, _
dctRegexes As Dictionary, _
dctUniques As Dictionary)
'lngCategoriesCount - number of categories in a chart
'objCategoriesColl - CategoryCollection object (a list of categories)
'dctDT - a dictionary for names where there's no need to change the label
'dctConsts - a dictionary for non-unique names which appear many times in a presentation
'dctRegexes - a dictionary for names which can be replaced using regular expressions
'dctUniques - a dictionary for names taken from an Excel file (already done)
'booleans for check if a name appears in a dictionary
Dim blnInDT As Boolean
Dim blnInConsts As Boolean
Dim blnInRegexes As Boolean
Dim blnInUniques As Boolean
Dim blnAdd As Boolean
'creating standard variables
Dim objCategory As ChartCategory
Dim i As Long
Dim strCategory As String
Dim strUCaseToCheck As String
For i = 1 To lngCategoriesCount
Set objCategory = objCategoriesColl(i)
strCategory = Trim(objCategory.Name)
'trimmed and upper-case category string to compare with dictionary keys
strUCaseToCheck = UCase(strCategory)
'checking if a category appears in a dictionary
blnInDT = blnInDct(dctDT, strUCaseToCheck)
blnInConsts = blnInDct(dctConsts, strUCaseToCheck)
blnInRegexes = blnAnyValueLikeDctRegex(strUCaseToCheck, dctRegexes)
blnInUniques = blnInDct(dctUniques, strUCaseToCheck)
'checking if a category meets a condition - at least 1 occurrence in any dictionary
blnAdd = blnAnyValue(True, blnInConsts, blnInRegexes, blnInUniques)
'blnAlphabeticChars - a function to check if a category has any letters because
'there's no need to change such labels as '2021' etc.
If Not blnInDT And blnAdd And blnAlphabeticChars(strCategory) Then
'ERROR (objCategory.Name): Can't assign to read-only property
If blnInConsts Then
objCategory.Name = dctConsts(strUCaseToCheck)
ElseIf blnInRegexes Then
objCategory.Name = dctRegexes(strUCaseToCheck)
ElseIf blnInUniques Then
objCategory.Name = dctUniques(strUCaseToCheck)
End If
End If
Next i
Set objCategory = Nothing
End Sub
I've found a workaround (SeriesCollection(x).Values or .XValues) but it's not convenient to use. So, my question is: does exist any way to use Name to set new labels? If no - do you know other workarounds?
EDIT: I've finally managed to change labels via objChart.ChartData.Workbook but it's very slow and, more importantly, a workbook has to be activated (opened) in order to refresh categories/series names. That influenced performance and time of execution greatly so I'm still looking for any other way to do so.

Your first listing is trying to set the name of .CategoryCollection(1). But the help page that you linked to is about .ChartCategory.
In any case, here's how to set the category names:
ActivePresentation.Slides(1).Shapes(1).Chart.Axes(xlCategory).CategoryNames = Array("Test1", "Test2", "Test3", "Test4")

Related

VB.Net | Is there a way to reference a dynamic amount of variables as arguments to function/sub?

I'm trying to pass a dynamic amount of variables to a Sub by using ByRef;
Essentially I'm trying to create a module that I can easily import into my projects and make handling the file saving/loading process automated.
The Sub/Function would take a number of variables as references and then loop through them changing each one's value.
I realize I'm missing a crucial point in how visual basic's syntax works but I haven't been able to figure out what I need to do.
The code I've written for this is:
Public Sub LoadSaveToVars(ByRef KeyNamesAndVars() As Object, ByVal FileLoc As String = "")
If isEven(KeyNamesAndVars.Length) Then
Dim Contents As String = My.Computer.FileSystem.ReadAllText(FileLoc)
Dim isOnName As Boolean = True
Dim CurrentVal As String = ""
For i = 0 To KeyNamesAndVars.Length - 1
If isOnName Then
CurrentVal = GetStringValue(KeyNamesAndVars(i), Contents) 'Get the value of the key with the key name in the array
isOnName = False
Else
KeyNamesAndVars(i) = CurrentVal 'Set the variable referenced in the array to the value
isOnName = True
End If
Next
Else
Throw New ArgumentOutOfRangeException("The key names and variables supplied are not even.", "Error loading to variables!")
End If
End Sub
And here's how I try to use this function:
Dim TestVar1 As String = ""
Dim TestVar2 As String = ""
LoadSaveToVars({"key1", TestVar1, "key2", TestVar2})
To keep this question clean I did not include the other functions, but I did make a poor attempt at drawing what I want to happen: https://gyazo.com/eee34b8dff766401f73772bb0fef981a
In the end, I want TestVar1 to be equal to "val1" and TestVar2 to be equal to "val2" and to be able to extend this to a dynamic number of variables. Is this possible?

VBA Run-time error 450 from function returning a collection

Context: I am writing a function which returns words/numbers present in a string which are enclosed by parenthesis.
Example: Calling ExtractParenthesis("This {should} work. But {doesnt}.") should return a collection containing two items, should and doesnt.
Error: The error I receive from the code below is
Run-time error '450': Wrong number of arguments or invalid property
assignment
It doesn't appear on a particular line and I just receive an error message with "OK" and "Help" as options.
Code:
Public Function ExtractParenthesis(strText As String) As Collection
Dim i As Long
Dim RegExp As Object
Dim Matches As Object
Dim Output As New Collection
Set Output = Nothing
Set RegExp = CreateObject("vbscript.regexp")
RegExp.Pattern = "{(.*?)}"
RegExp.Global = True
Set Matches = RegExp.Execute(strText)
For i = 0 To (Matches.count - 1)
Output.Add Matches(i).submatches(0)
Next i
Set ExtractParenthesis = Output
End Function
It works exactly the way you want it for me:
Option Explicit
Public Sub TestMe()
Dim myColl As New Collection
Set myColl = ExtractParenthesis("This {should} work. But {doesnt}.")
Debug.Print myColl(1)
Debug.Print myColl(2)
End Sub
Public Function ExtractParenthesis(strText As String) As Collection
Dim i As Long
Dim RegExp As Object
Dim Matches As Object
Dim Output As New Collection
Set Output = Nothing
Set RegExp = CreateObject("vbscript.regexp")
RegExp.Pattern = "{(.*?)}"
RegExp.Global = True
Set Matches = RegExp.Execute(strText)
For i = 0 To (Matches.Count - 1)
Output.Add Matches(i).submatches(0)
Next i
Set ExtractParenthesis = Output
End Function
I receive "should" and "doesnt" on the immediate window (Ctrl+G). Probably you are not aware that you are returning a collection. It should be used with the Set keyword.
To run it from the immediate window, try like this:
?ExtractParenthesis("This {should} work. But {doesnt}.")(1)
?ExtractParenthesis("This {should} work. But {doesnt}.")(2)
From what I understand of your comment to Vityatas answer you mean you want to run it as a worksheet function - running it directly
The changes I've made to your code will let you use it as a function:
In A1:B1 this will work: {=ExtractParenthesis("This {should} work. But {doesnt}.")}
In A1:A2 use it like this: {=TRANSPOSE(ExtractParenthesis("This {should} work. But {doesnt}."))}
NB: The curly brackets are added by Excel when you enter the formula using Ctrl+Shift+Enter rather than Enter on its own.
The one problem with the code is that you must select the correct number of cells first - if it should return three words, but you've only selected two then you'll only see the first two.
Public Function ExtractParenthesis(strText As String) As Variant
Dim i As Long
Dim RegExp As Object
Dim Matches As Object
Dim Output As Variant
Set Output = Nothing
Set RegExp = CreateObject("vbscript.regexp")
RegExp.Pattern = "{(.*?)}"
RegExp.Global = True
Set Matches = RegExp.Execute(strText)
ReDim Output(1 To Matches.Count)
For i = 1 To (Matches.Count)
Output(i) = Matches(i - 1).submatches(0)
Next i
ExtractParenthesis = Output
End Function

Access a form's control by name

not sure whether the title of this post is accurate.
I'm trying to access windows form controls and their properties by "composing" their name within a loop, but I can't seem to find the related documentation. Using VB.net. Basically, say I have the following:
Dim myDt As New DataTable
Dim row As DataRow = myDt.NewRow()
row.Item("col01") = Me.label01.Text
row.Item("col02") = Me.label02.Text
'...
row.Item("colN") = Me.labelN.Text
I'd like to write a for loop instead of N separate instructions.
While it's simple enough to express the left-hand side of the assignments, I'm stumped when it comes to the right-hand side:
For i As Integer = 1 to N
row.Item(String.format("col{0:00}", i)) = ???
' ??? <- write "label" & i (zero-padded, like col) and use that string to access Me's control that has such name
Next
As an extra, I'd like to be able to pass the final ".Text" property as a string as well, for in some cases I need the value of the "Text" property, in other cases the value of the "Value" property; generally speaking, the property I'm interested in might be a function of i.
Cheers.
You could use the ControlsCollection.Find method with the searchAllChildren option set to true
For i As Integer = 1 to N
Dim ctrl = Me.Controls.Find(string.Format("label{0:00}", i), True)
if ctrl IsNot Nothing AndAlso ctrl.Length > 0 Then
row.Item(String.format("col{0:00}", i)) = ctrl(0).Text
End If
Next
An example on how to approach the problem using reflection to set a property that you identify using a string
Dim myLabel As Label = new Label()
Dim prop as PropertyInfo = myLabel.GetType().GetProperty("Text")
prop.SetValue(myLabel, "A Label.Text set with Reflection classes", Nothing)
Dim newText = prop.GetValue(myLabel)
Console.WriteLine(newText)

VB Script code to read column value from lotus notes database

Set domSession = CreateObject("Notes.NotesSession")
Dim domDatabase
Set domDatabase = domSession.GetDatabase("server Name", "xyz.nsf")
Set domView = domDatabase.GetView("All Projects")
Up to here it's ok. But I try lot but unable to read the document values.
I am looking for the vbscript code to read the document data.
Add this:
Dim i%
Dim s$
Dim doc As Object
For i% = 1 to domView.EntryCount
Set doc = domView.GetNthDocument(i%)
s$ = doc.GetItemValue("itemname")(0)
' Do whatever you want with the string value which is now stored in s$
Next
This code assumes the items are text type. You could use simply Dim s to get any item type (number, date).
To get column values from the view you can use doc.ColumnValues(2). This returns the value of 3rd column (0 is first).

VBA - grabbing column names from lotus notes database using getColumnNames method

So I have a view (object name is 'view') in a Lotus Domino db from which I want to grab the column names and put them in an array:
Dim view As Domino.NotesView
Set view = db.GetView(viewScen)
//viewScen is a string containing the actual view's name
//db is a string containing the actual db name
These declarations work fine, but when I try to assign those values to an array using the method called 'getColumnNames', the VBA editor tells me that the method is not supported for that object:
Dim someArray() As String
//I tried both of the following with no sucess...
someArray = view.getColumnNames
someArray() = view.getColumnNames
What am I doing wrong?
I think you can do a For..Each with columns
dim idx as integer
dim OneCol as Column
redim someArray(view.Columns.Count)
For idx = 0 to view.Columns.Count - 1
someArray(idx) = view.Columns(idx).name
Next
According to the 8.0 help files, the getColumnNames method is not supported in COM/OLE. However, the attribute ColumnNames is supported. This is VB code from the Help file:
Private Sub ViewColumnNames_Click()
Dim s As New NotesSession
s.Initialize
Dim dir As NotesDbDirectory
Dim db As NotesDatabase
Dim v As NotesView
Dim cns As String
Set dir = s.GetDbDirectory("")
Set db = dir.OpenDatabase("Web test")
Set v = db.GetView("Main View")
For Each cn In v.ColumnNames
cns = cns + cn + Chr(10)
Next
MsgBox cns, , "Columns in Main View"
End Sub