Avoid overlapping shapes in Visio - vba

I recorded a macro to add custom shapes from stencils and assigned to command button.
When adding shapes multiple times, the shapes are adding on top of existing shapes that I added previously. Is there any way to stop that happening?
Sub Circle ()
Dim DiagramServices As Integer.
DiagramSevices=ActiveDocument.DiagramServicesEnabled.
ActiveDocument.DiagramServicesEnabled = visServiceVersion140 + visServiceVersion150.
ActiveDocument.Windows.ItemEx("Test").Activate.
Application.ActiveWindow.Page.Drop Application.Documents.Item("Custom.vssx").Masters.ItemU("Circle"),9,7.
ActiveDocument.DiagramServicesEnabled = DiagramServices.
End Sub.

#Fallen, please try this code
Sub ForFallen()
' determine variable for spatially related shapes
Dim vsoReturnedSelection As Visio.Selection
' define the shape
Dim sh As Shape
' determine variable coordinates of the shape
Dim x As Integer, y As Integer
' assign initial coordinates of the shape
x = 7
y = 9
' drop shape to the point with initial coordinates
Set sh = ActivePage.Drop(Application.Documents.Item("Custom.vssx").Masters.ItemU("Circle"), x, y)
' get the set of spatially related shapes for dropped shape position
Set rel = sh.SpatialNeighbors(visSpatialOverlap, 0.25, 0)
' if shape overlapped other shapes start next loop
If rel.Count > 0 Then
' this loop is repeated until there are no overlapped shapes left under the shape
Do
' increment X-position for 2 inches
x = x + 2
' move shape to new position
sh.SetCenter x, y
' obtaining a set of spatially related shapes for a new location of shape
Set rel = sh.SpatialNeighbors(visSpatialOverlap, 0.25, 0)
Loop While rel.Count > 0
End If
End Sub
Read more about SpatialNeighbors property and SetCenter method…

Related

Display random number in slide using VBA

I need to generate a random number between 1 and 30 and display it on every slide. I found the following code online:
Sub UpdateRandomNumber(oSh As Shape)
Dim X As Long
'Make the shape’s text a random number
'X or less
'Change 12 below to any number you’d like:
X = 30
oSh.TextFrame.TextRange.Text = CStr(Random(X))
End Sub
Function Random(High As Long) As Long
'Generates a random number less than or equal to
'the value passed in High
Randomize
Random = Int((High * Rnd) + 1)
End Function
Sub RandomNumber()
End Sub
I need the code to do one thing differently:
The object prompting the action is in the same spot on all slides. When generating and displaying a random number, all slides should be changed accordingly.
When I leave the slide, the previously generated number should be shown instead of the one that was previously generated on this slide.
This creates a random number between 1 and 30. Change the shape name to the actual shape used in your file:
Sub ShapeNumber()
Dim X As Long
Dim ShapeNumber As String
Dim oSlide As Slide
Dim oShape As Shape
X = 30
Randomize
ShapeNumber = Int((X * Rnd) + 1)
For Each oSlide In ActivePresentation.Slides
For Each oShape In oSlide.Shapes
If oShape.Name = "Rectangle 3" Then
oShape.TextFrame.TextRange.Text = ShapeNumber
End If
Next oShape
Next oSlide
End Sub

Line up shapes to have coincident edges Visio VBA

I have used VBA in the past mostly with excel, but I am not very experienced.
I want to cycle through multiple boxes and make each of them have coincident edges. Like they are sitting on top of each other. I am having trouble identifying the position of the first shape in my selection. I've tried a number of different objects including selection.shaperange.
Dim shp As Visio.Shape
Dim shp1 As Visio.Shape
Dim Pos As Double
Set shp1 = ActiveWindow.Selection.ShapeRange.Item
Pos = shp1.Cells("PinY")
For Each shp In Application.ActiveWindow.Selection
'Change the cell name to the one you want
If shp <> ActiveWindow.Selection.Item(1) Then
Pos = Pos + 6
End If
shp.CellsSRC(visSectionControls, visRowXFormOut, visXFormPinY).FormulaU = Pos & "mm"
Pos = shp.Cells("PinY")
Next shp
End Sub
Can you help me get the position of the first selected item and then I may be able to figure out the rest.
This code will abut the left sides of all but the first-selected shape with the right side of the first-selected shape:
Option Explicit
Public Sub AbutLeftsToPrimaryRight()
Dim sel As Visio.Selection
Set sel = Visio.ActiveWindow.Selection
If (sel.Count < 2) Then
Debug.Print "Select two or more shapes (Use Shift + Click)!"
GoTo Cleanup
End If
Dim shp0 As Visio.Shape
Dim shp As Visio.Shape
'// Get the selection and the primary selected shape,
'// which is item(1). See also: Selection.PrimaryItem
Set shp0 = sel(1)
'// Quick calculate the right side of shp0:
'// PinX - LocPinX + Width.
Dim dRight0 As Double
dRight0 = shp0.CellsU("PinX").ResultIU - shp0.CellsU("LocPinX").ResultIU + shp0.CellsU("Width").ResultIU
'// If shapes are rotated, flipped, or not rectangular,
'// then you'll need to use shp.BoundingBox, which
'// is more complicated
Dim dLeft As Double
Dim dx As Double, px As Double
Dim i As Integer
For i = 2 To sel.Count
'// Get the ith shape:
Set shp = sel(i)
'// Get its Pin:
px = shp.CellsU("PinX").ResultIU
'// Calculate the left side of the shape:
'// PinX - LocPinX:
dLeft = px - shp.CellsU("LocPinX").ResultIU
'// The offset:
dx = dLeft - dRight0
'// Set the new pin:
shp.CellsU("PinX").ResultIUForce = px - dx
Next i
Cleanup:
Set shp0 = Nothing
Set shp = Nothing
Set sel = Nothing
End Sub
Hope this helps!

How do I select format an active selection of words in a textbox

I'm trying to explore how do I apply some formatting to only few selected words in a textbox but so far unable to accomplish this myself.
Somehow with the code I created below, I can only use it to select all the words in the textbox instead of just a few words I want.
It would be great if anyone can provide me a simpler/ existing codes that can help me solve this please ?
Thanks in advance
Sub ActiveTextRange()
Dim sld As slide
Dim sh As Shape
Dim wordcount As Long, j As Long, x As Long, y As Long, z As Long
wordcount = ActiveWindow.Selection.ShapeRange(1).textFrame.TextRange.Words.Count
With ActiveWindow.Selection.ShapeRange(1)
.textFrame.TextRange.Words(Start:=1, Length:=wordcount).Font.Color.RGB = RGB(230, 0, 0)
End With
End Sub
The following might help. Key to this is being able to track the location of the specific text you want to change in amongst larger chunks of text; my suggestion is to format each bit of text as you add it to the shape. Cheers.
Option Explicit
Sub ActiveTextRange()
Dim vPresentation As presentation
Dim vSlide As Slide
Dim vShape As Shape
Dim vAddThisText As String
' Create a new presentation, add a slide and a rectangle shape
Set vPresentation = Application.Presentations.Add
Set vSlide = vPresentation.Slides.Add(vPresentation.Slides.Count + 1, ppLayoutBlank)
Set vShape = vSlide.Shapes.AddShape(msoShapeRectangle, 10, 10, 600, 300)
' Make the shape white with a 3pt dark red border
vShape.Fill.ForeColor.RGB = rgbWhite
With vShape.Line
.ForeColor.RGB = rgbDarkRed
.Weight = 3
End With
' Setup the shape to be left aligned, font color, top anchored, etc
With vShape.TextFrame
.TextRange.Paragraphs.ParagraphFormat.Alignment = ppAlignCenter
.TextRange.Font.Color.RGB = rgbBlack
.VerticalAnchor = msoAnchorMiddle
.TextRange.ParagraphFormat.SpaceAfter = 6
.TextRange.ParagraphFormat.WordWrap = msoCTrue
End With
' And now format the word red, which is the 7th character and is 3 long
vAddThisText = "Hello Red World"
vShape.TextFrame.TextRange.InsertAfter vAddThisText
With vShape.TextFrame.TextRange.Characters(7, 3)
.Font.Color.RGB = rgbRed
' and change other attributes if needed etc
End With
End Sub
And the output is ...
This colors the second and third words red in a Title placeholder. After Words, the first number is the starting position and the second number is the length:
Sub ColorWords()
Dim objSlide As Slide
Dim objShape As Shape
For Each objSlide In ActivePresentation.Slides
For Each objShape In objSlide.Shapes
If objShape.Type = msoPlaceholder Then
If objShape.PlaceholderFormat.Type = ppPlaceholderTitle Or objShape.PlaceholderFormat.Type = ppPlaceholderCenterTitle Then
With objShape.TextFrame2.TextRange.Words(2, 2).Font.Fill
.Solid
.ForeColor.RGB = RGB(255, 0, 0)
End With
End If
End If
Next objShape
Next objSlide
End Sub
To color a word selection, use:
ActiveWindow.Selection.TextRange.Font.Color.RGB = RGB(Red:=255, Green:=0, Blue:=0)
OK. I think I better understand the ask ... but I'm assuming in this response you're selecting text ... rather than just a shape itself. So you're editing the powerpoint, select some text in a shape, and want to run a macro to format(?) It should be as simple as creating the following in a code module (and then I created a custom access toolbar link to run the macro at the top of PowerPoint to make it quick):
Option Explicit
Sub ActiveTextRange()
ActiveWindow.Selection.TextRange.Font.Color.RGB = rgbRed
End Sub
Before:
Select the text "Red" and run macro:
Btw ... if you want to select just the shape and have some logic choose the text, the concept is a mix of this and my first answer.

VBA: Select all slides of defined sections

I'm playing with a progress bar (with basically zero experience with VBA whatsoever). I found the following snippet online:
Sub ProgressBar()
On Error Resume Next
With ActivePresentation
.SectionProperties.SlidesCount(
For N = 2 To .Slides.Count
.Slides(N).Shapes("Progress_Bar").Delete
Set s = .Slides(N).Shapes.AddShape(msoShapeRectangle, 0, .PageSetup.SlideHeight - 10, N * .PageSetup.SlideWidth / .Slides.Count, 10)
Call s.Fill.Solid
s.Fill.ForeColor.RGB = RGB(128, 128, 128)
s.Line.Visible = False
s.Name = "Progress_Bar"
Next N:
End With
End Sub
Note the part with For N = 2 To .Slides.Count. I'd like the progress bar not to reach from the second slide the last one but rather from the second slide to the last slide of the section I called "conclusion". How can I do that?
Thanks!
Edit: My current workaround is a hard coded number of slides that I define as a variable at the beginning of the macro and then use the variable throughout the rest of it.
Here are a couple of bits that should get you started:
LastSlideOf returns the slide index of the last slide in the named section passed to it:
Function LastSlideOf(sSectionName As String) As Long
Dim x As Long
With ActivePresentation.SectionProperties
x = SectionIndexOf(sSectionName)
LastSlideOf = (.FirstSlide(x) + .SlidesCount(x)) - 1
End With
End Function
Function SectionIndexOf(sSectionName As String) As Long
Dim x As Long
With ActivePresentation.SectionProperties
For x = 1 To .Count
If .Name(x) = sSectionName Then
SectionIndexOf = x
End If
Next
End With
End Function

Creating a repeating line through looping by giving the x and y coordinates

I am experimenting on the paint event of VB.Net, and for this experiment I would like to create a repeating horizontal or vertical (depending on the parameter that I inputted) line and loop through until it meets the corresponding end point x and y.
Something like this:
What I'm trying to achieve is given the x and y start point and x and y end point the function should create either vertical or horizontal line that starts with the given start point until it reaches the given end point.
I can create curveline and straightline using the paintevent, but right now I don't have any idea on how to perform looping in the given x and y start point and end point.
You just need to use a For loop to iterate the x/y coordinates. Here's an example:
Public Class Form1
Private Enum Orientation
Vertical
Horizontal
End Enum
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim orient As Orientation = Orientation.Vertical
Dim x As Integer = 100 'X Coord
Dim y As Integer = 100 'Y Coord
Dim count As Integer = 10 'Number of Lines to draw
Dim spacing As Integer = 5 'Spacing between lines in pixels
Dim length As Integer = 20 'Length of each line in pixels
Dim thickness As Integer = 3 'Thickness of each line in pixels
drawLines(x, y, orient, count, spacing, length, thickness, e.Graphics)
End Sub
Private Sub drawLines(x As Integer, y As Integer, orient As Orientation, count As Integer, spacing As Integer, length As Integer, thickness As Integer, g As Graphics)
'Create the Pen in a using block so it will be disposed.
'The code uses a red pen, you can use whatever color you want
Using p As New Pen(Brushes.Red, CSng(thickness))
'Here we iterate either the x or y coordinate to draw each
'small segment.
For i As Integer = 0 To count - 1
If orient = Orientation.Horizontal Then
g.DrawLine(p, x + ((thickness + spacing) * i), y, x + ((thickness + spacing) * i), y + length)
Else
g.DrawLine(p, x, y + ((thickness + spacing) * i), x + length, y + ((thickness + spacing) * i))
End If
Next
End Using
End Sub
End Class
Have you tried something like:
For x = xstart to xend Step Spacing
Next
Where:
xstart = your start point
xend = your end point
Spacing = distance between lines