PowerPoint VBA pass BUILT IN enumeration value to function - vba

I'm building a ribbon tab and several of the buttons insert textboxes (each with differing formats).
I have built a 'CreateTextBox' function that takes as input parameters (i) the active slide, (ii) box width, (iii) box height this works fine
I want to add a fourth parameter which is whether or not it should auto-size (so a PpAutoSize constant):
https://learn.microsoft.com/en-us/office/vba/api/powerpoint.textframe.autosize
Example of how this would play out is a line in the sub that links to the button being:
Set NewTextBox = CreateTextBox(CurrentSlide, 200, 100, ppAutoSizeNone)
But, nothing I've tried allows me to pass that constant in a way that it could be picked up like this in the function CreateTextBox:
Function CreateTextBox(sld As Slide, tbWidth As Double, tbHeight As Double, AutoSizeConstant as ???????) as Shape
Set CreateTextBox = sld.Shapes.AddTextbox(.........)
With CreateTextBox
...
...
.TextFrame.AutoSize = AutoSizeConstant
End With
End Function
Everything I can find talks about creating a custom enumeration and passing the index of the item you want. I don't want to duplicate anything or have to use class modules, just want to pass the constant per the above.
Any ideas?

Per comment from freeflow, you can specify the enumeration as the type so 'ByVal AutosizeConstant as PpAutoSize' works. Thank you!

Related

Navigate to PPT Slide by its ID or Name instead of Number

ActivePresentation.SlideShowWindow.View.GotoSlide x requires us to enter the slide number, which is varying. If I refer it to Slide Number 3 and then move the position of Slide 3, the code wouldn't refer to that slide anymore.
How do I overcome this by referring to the SlideID or SlideName instead of Slide Number.
Thank you.
If I understand the question correctly, you want to be able to go to a particular slide in the presentation regardless of where it may appear in the presentation (ie because other slides have been added before it or it's been moved to a different position).
If so, you could tag the presentation with the slide's SlideID:
ActivePresentation.Tags.Add "IndexSlide", Cstr(lSlideID)
(where IndexSlide is any convenient name you've assigned to the slide; you can have multiple tags for different slides you want to track. And lSlideID is, of course, the slide's SlideID
You'd need to write a function to retrieve the slide's SlideIndex, given the SlideID and call it like so (aircode ... you might have to move/remove a paren or two):
ActivePresentationSlideShowWindow.View.GoToSlide ( _
SlideIndexFromSlideID(cLng(ActivePresentation.Tags("IndexSlide")))
This gets the tag named IndexSlide from the presentation which is the SlideID of IndexSlide, converts it to a Long (tags are strings), passes it to your SlideIndexFromSlideID function, which returns the slide's current SlideIndex ... for you to GoToSlide with.
[Later: adding the needed function for returning SlideIndex]
Function SlideIndexFromSlideID(lSlideID As Long) As Long
SlideIndexFromSlideID = ActivePresentation.Slides.FindBySlideID(lSlideID).SlideIndex
End Function

PowerPoint VBA add shape event/ add shape with tag value

i'am currently trying to add a small function to PowerPoint using VBA, my goal is to create a gadget that works kind of like Photoshop graphics layer.
My plan is to add a layer name Tag on each shape that is drawn by user, so later I can parse through every item by loop and preform lock/unlock, show/hide shapes based on it's tag value, such as:
Sub add_shape_with_layer_tag()
Set islide = ActivePresentation.Slides(1)
Set ishape = islide.Shapes.AddShape(msoShapeRectangle, 5, 5, 80, 60)
ishape.Tags.Add "Layer", "1"
End Sub
Sub show_hide_layer_one_shapes()
Dim active_slide As Slide
Set active_slide = ActiveWindow.View.Slide
For Each ishape In active_slide.Shapes
If ishape.Tags("Layer") = "1" Then
ishape.Visible = Not (ishape.Visible)
End If
Next ishape
End Sub
However, I couldn't found a way to achieve this, so I would like to ask whether there's a method that provides following functions?
override add shape function so I can sneak tag value in to shape every time user drawn a shape
catch add shape event (if this thing did exist) so i can add tag to the last added item
a way to set a default tag value to shape, just like setting default shape color/line width
or is there any better options that is also viable?
thanks.
20200728
To John, thanks for the advice, I did found some interesting event that might be helpful for some of my other projects, however I couldn't found events that able to trigger after custom function while shape is added.
To Steve, my plan is to add a modeless userform with list UI that manage layers, the shape tag and shape fill texture/color will be determined based on what list item that currently selected.
As to saving settings, I'll use VBComponents.CodeModule to dump existing settings in userforms to a VBA module and store as text, so in theory I should able to make this function self contained in one file.
Not totally an answer, sorry SO, but comments don't allow enough scope for this. So ...
To Steve, my plan is to add a modeless userform with list UI that manage layers, the shape tag and shape fill texture/color will be determined based on what list item that currently selected.
Ah, so you're creating your own "pseudo-layers". That wasn't clear. Thanks for the add'l info. As it happens, I have a selection manager add-in that works very similarly to what you're proposing.
To John, thanks for the advice, I did found some interesting event that might be helpful for some of my other projects, however I couldn't found events that able to trigger after custom function while shape is added.
The SelectionChange event should get you there. When it fires, you'll need to check first to see if the current selection is a shape or something else. If a shape, check to see if its .Index = current slide's .Shapes.Count and also to see if you've already tagged it. If no tag AND if it's the correct index, it'll be a newly added shape. If you're tagging ALL shapes, you may only need to check to see if the .Tag(name) is blank.
As to saving settings, I'll use VBComponents.CodeModule to dump existing settings in userforms to a VBA module and store as text, so in theory I should able to make this function self contained in one file.
Why not save any needed slide or presentation level info as further slide- or presentation-level tags? PPT can absorb quite a lot of info as tags w/o getting cranky.

Passing a checkbox control to a function

I am using Access 365 and VisualBasic. I have a number of checkboxes on a form that I want to display just a subset of these at a time, so I want to reposition the top of the checkboxes so that no matter which are currently displayed, I can make them line up nicely.
So, I have declared an array of checkboxes that I want to dynamically add those checkboxes to display:
' Array holding the checkboxes that will be displayed, depending upon species, sex, etc.
Dim arrCheckBoxes(cNumCheckboxes) As CheckBox
Then as I determine that a specific check box should be shown, I want to add it to the array at the next available position using this function (which will also update the next available position):
Private Sub AddCheckbox(ByRef arrCheckBoxes() As CheckBox, ByRef chkNew As CheckBox, ByRef intCurrentCheckbox)
intCurrentCheckbox = intCurrentCheckbox + 1
arrCheckBoxes(intCurrentCheckbox) = chkNew
End Sub
My problem is that in the code that calls the AddCheckbox function, I cannot figure out how to pass the check box. I am using the following code (CatNeuter is the checkbox from my form).
Call AddCheckbox(arrCheckBoxes, Me.CatNeuter, intCurrentCheckbox)
However, Me.CatNeuter is always 0, so I think I am getting just the value, and not the checkbox control itself. I've tried numerous different methods such as:
Me.Controls!CatNeuter
Me.Controls("CatNeuter")
But I just cannot figure out how to pass the actual checkbox so I can then go through the array and change the Top property for each checkbox.
Regards,
Lise
You need to use Set for objects:
Set arrCheckBoxes(intCurrentCheckbox) = chkNew

Using varying labels in Userform code

I have a simulator with two userforms that transfer information back and forth between each other (one is MainForm, and the other is CreatureFinder).
When one of the deck slot buttons on MainForm is pushed (all 20 of which correspond to a creature in either your or the enemy's deck), it opens CreatureFinder so that you can choose which creature goes in the slot (and it also lets you edit certain parameters, like the creature's level).
The code shortened for simplicity:
If CreatureNumberLabel.Text = "1" Then
MainForm.YourCreature1Skill1Label.Text = Skill1Label.Text
MainForm.YourCreature1Skill2Label.Text = Skill2Label.Text
MainForm.YourCreature1Skill3Label.Text = Skill3Label.Text
End If
I want to remove the If Then statement, and to change "YourCreature1" to "YourCreature" & whatever value CreatureNumberLabel.Text is set to.
Should it be VBA, you can skip the
If CreatureNumberLabel.Text = "1" Then
And just type:
MainForm.Controls("YourCreature" & CreatureNumberLabel.Text & "Skill1Label").Text = Skill1Label.Text
And so on with Skill2Label.Text, Skill3Label.Text, etc...
You can use some kind of control arrays. On form load, create array(s) for controls and assign its elements (this is 20 lines of code per array), afterwards you can use them like next:
Dim CreatureNum As Integer = CInt(CreatureNumberLabel.Text) 'don't forget validation
MainFormYourCreatureSkillLabelArray(CreatureNum).Text = SkillLabel(CreatureNum).Text

Creating an userform object hierarchy with grouping in vba

First things first. There's a good chance what I want to do should really be done with VB and not VBA. But as long as it is possible I would rather use VBA.
I have a userform of essentially a big diagram made of hundreds of labels. I want to separate these labels into groups. And then separate these groups into subsystems. The idea being I have some form of heirarchy to work with. The label groups need to change color based on what I have selected in a combo box, and if I click on one of these labels I want to bring up a user form showing details of the subsystem using click events.
I'm pretty sure I need to use multiple classes to do what I want but am fairly new to using class modules. Though I get the concept.
Basically I want some functionality that goes subsystem -> label group( or part) -> color with click events for the whole subsystem and combo box events for changing label group colors.
I saw a thread online about grouping labels or text boxes but it only works to trigger the even for a group, not change the properties of the whole group once the event is triggered. I would like to set this up in classes as well so I can export the system for use in other future userforms.
I was able to create groups of labels and change them together like I wanted:
CPart (Class Module 1):
*This is meant to handle the event triggering of the labels and includes some color code that I used to test functionality of the groups changing together and functionality of changing colors.
Public WithEvents trigger As MSForms.Label
Dim pLabels As Collection
Property Set triggers(c As Collection)
Set pLabels = c
End Property
Private Sub trigger_Click()
For Each obj In pLabels
obj.BackColor = RGB(255, 0, 0)
Next obj
End Sub
CTrigger (Class Module 2):
*This took a collection of labels which were passed in through a collection variable in the userform and then stored each label as a trigger in a separate class variable, along with the whole collection of labels in that group. This way when any trigger fires the event, all of the labels change.
Dim CTrigger() As New CPart
Dim pLabels As Collection
Dim i As Integer
Property Set Labels(c As Collection)
Set pLabels = c
For i = 1 To pLabels.Count
ReDim Preserve CTrigger(1 To i)
Set CTrigger(i).trigger = pLabels.Item(i)
Set CTrigger(i).triggers = pLabels
Next i
End Property
Property Get Labels() As Collection
Labels = pLabels
End Property
I really don't like the way it works, partly because I am losing myself in the logic of it constantly, and partly because it means that in order to use this I have to make collections of labels in the userform module anyway just to run it. It is very inefficient code, but I am putting it up so you get an idea of what I am trying to accomplish.
What I would much rather do instead is have one class variable to hold my custom collection of labels (a "LabelGroup"). Another class variable is likely required to hold the labels themselves (I think). And then all I would have to do is go through and write methods for the LabelGroup class such as changecolor, and it could handle that. But I can handle that part, for now what I really need help with is setting up the class framework in a neat way, so that the module I will eventually run could just say things like:
LabelGroup1.Add Label1
LabelGroup2.Add Label2
or
Private Sub button_click()
LabelGroup1.ChangeColor(RGB(...))
End Sub
These two articles have been helping me along:
http://www.databaseadvisors.com/newsletters/newsletter200503/0503usingcustomcollections/using%20custom%20collections%20in%20microsoft%20access.asp
http://j-walk.com/ss/excel/tips/tip44.htm
I was just looking at something similar but not quite so detailed. I'm trying to improve the look of a complex userform by making it look more modern and was going to try to fake mouseOver highlighting or at least active/inactive shading for labels placed overtop of graphical buttons.
Anyway, have you considered just changing the names of the label objects so that they are prefixed/suffixed with some kind of group or subsystem ID?
That way when you pass them to a sub to change their colour, you can check the prefix or suffix.