Excel Macro: Command buttons overlap the shape in worksheet - vba

I have 2 command buttons, different height and width of the cells that need to be inserted every time and a fixed shape. Sometimes when the height and width are smaller, it tend to overlap with the command buttons. What should I do? I need the command buttons to be there. I tried to put certain range, it works but when the width and height of the cells gets bigger, it moves further away. Any idea? I'm thinking of maybe putting the range cells for the command buttons to stay as Range A and B as default. Will that work? But I don't know how to do it.

Set the top, left properties on the shape, then irrespective of the size it should always start at the same place.
Dim Fred as shape
Set Fred = activesheet.shapes.addshape(type,left,top etc,)
Fred.placement= xlfreefloating

Related

How do I change the value of the SlideMaster.Height in PowerPoint 2016 VBA?

I'm trying to automate the process of changing the height in the Slide Size dialog in the Slide Master system with VBA. When I try to change it, VBA informs me that I'm not permitted to assign a value to ActivePresentation.SlideMaster.Height because it is read-only.
I've studied the ActivePresentation object tree and have figured out to acquire the height value (with ActivePresentation.SlideMaster.Height), but the following line results in a Compile Error:
ActivePresentation.SlideMaster.Height = 1189
Changing the SlideHeight with...
ActivePresentation.PageSetup.SlideHeight = 1189
does change the height of the slide, but it doesn't have the same effect as changing the height through the Slide Master system. The primary question at this stage is if it's possible to change ActivePresentation.SlideMaster.Height with VBA, or is the Read-Only status immutable?
Sub test()
ActivePresentation.SlideMaster.Height = 1189 'Compile Error...can't assign to read-only property
ActivePresentation.PageSetup.SlideHeight = 1189 'Changes the height of the slides, _
but doesn't change the size of text within Shape elements like I need it to do.
End Sub
Here's some background...
Through a bit of trial and error, I've determined that if I change the dimensions of the slides using the slide master, the default text for Shapes is set how I want it (at pitch 18). If I don't change the dimensions in the Slide Master, the text for Shapes remains at 31. Even if a new shape is created, the font is changed to 18 and that shape is set as the default shape, if text is pasted onto the slide (with CTRL-v or Paste Special-Unformatted Text), the shape that gets created has a text-size of 31.
Just to be clear, if the default is set to 18 and I create another new Shape via Insert>Shapes, then that new shape is automatically set to 18. It's only when I paste text (using either CTRL-v or Paste Special - Unformatted) directly on the slide does it become 31.
The only thing that does what I want is making a slight change to the Slide Master Slide Size. Changing the height from 1188 to 1189 forces all of the shapes on all of the slides to go from 31 to 18. Any new text that gets pasted in the slide comes in as a shape containing 18 text.
The reason I'm posting this on Stack Overflow and not on Super User is because I have to automate this change...we have thousands of presentations to modify.

Adding a background image to a particular cell

I tried to insert the background image using following code:
Pic = "C://Picture/Logo1"
Activesheet.SetBackgroundPicture Pic
This inserts the picture to full sheet but I want to add it to particular cell or a range of cells. Please help
As far as I know excel doesn't support appending the image to a cell (with or without VBA).
The background of a single cell supports colors/gradients/fill-patters, but not the pictures.
It is possible however, to "place" the picture (shape) object with the same width and height right above the cell and make it locked and move around together with the cell if somebody attempts to resize cell widths. I personally wouldn't go that way, too much to code and too much risk of breaking the structure.

excel rowheight - a bug here?

Excel seems to work with the row heights in the following (il)logic:
If you refer to a single cell and your cell is defined "Wrap Text" and the row height is "Autofit":
When you enter more characters than what can fit to the cell width the row in the cell is changed automatically and in the end, when you press "Enter", the row height is expanded so that the whole text is visible.
If you refer to combined cells and your cell combination is "Wrap text" and "Autofit":
When you enter more characters than what can fit to the combined cells' width the row is NOT changed automatically and after "Enter" the row height is NOT adjusted to show the whole text.
I think this is not logical.
What would be the trick to get excel to automatically adjust the row height also in the case of "Wrap Text" combined cells? Any VBA solutions? (Basically you could, maybe, count how many line changes the combined cell has and adjust the rows.height property accordingly but...

Reinstate Excel chart default resizing behaviour using VBA

I am looking for a way to reinstate the default/native resizing behaviour of a chart in Excel 2010 once it has been disabled (e.g. by manipulating the chart with VBA).
Now I haven't been able to find anything anywhere about the behaviour I have in mind, so I am going to assume that it needs detailed explanation.
Input and select random numerical data into 4-5 cells in Excel, and insert a new Clustered Columns chart. You need to see a the chart's plot area. Now select the chart, and get the PlotArea.Top value with the following line
ActiveChart.PlotArea.Top
If you haven't touched the chart, this should return a value of 7. Now use one of the chart's handlebars to resize the chart vertically, and use the same command line again.
activechart.plotarea.top
Notice how the value returned is still 7. Now set this property to 7 in VBA.
ActiveChart.PlotArea.Top = 7
Again, grab one of the handlebars, resize the chart vertically and get the .top property again using:
ActiveChart.PlotArea.Top
Notice how the value has now changed. It will be either smaller or greater than 7 depending on whetehr you decreased or increased the size of the chart.
Once any element of a chart has been moved either manually or with VBA code, it loses this "absolute position" property and begins moving inside the ChartArea whenever the chart is resized. While some elements can be reset using .SetElement, this does not work for the Plot Area. For example, the following command lines do not reinstate the behaviour I am describing.
ActiveChart.SetElement msoElementPlotAreaNone
ActiveChart.SetElement msoElementPlotAreaShow
I do a lot of automated resizing of charts with VBA, and having the plot area move around by itself makes it a lot harder to predict the effect of resizing the chart and leads to inconstant results.
So back to the question: does anyone know of a way to reinstate this default behaviour, either for the entire chart, or at least specifically for the PlotArea?
Thanks in advance to anyone who may help!
Vincent
I ran into this when I manually resized the plot area and then when the legend is moved it did not resize the plot area at all.
I had tried to save my chart as a template (right click save as template in Excel 2013) but this still had the plot area manually set.
Therefore I would recommend keeping the auto-size behavior before saving a template, since the only way I know to re-set the chart auto-sizing behavior after it has been manually modified is to use a macro
Here is the macro I used to reinstate the auto-sizing behavior
Sub Macro1()
'
' this selects the chart based on the chart name
ActiveSheet.ChartObjects("Chart 4").Activate
' this selects the plot area
ActiveChart.PlotArea.Select
' this clears any custom formatting such as borders or fill colors
ActiveChart.PlotArea.ClearFormats
' this resets the auto-sizing behavior after plot area manually re-sized
ActiveChart.PlotArea.Position = xlChartElementPositionAutomatic
End Sub
References
Why plot area does not expand after clearing series legend?
Excel Chart Plot Area Auto Size - ExcelBanter

Match labels to arrows in Excel flowchart using VBA

I'm writing a code generation tool using VBA in Excel (don't ask why—long story). I need to be able to "parse" a flowchart.
The problem is that Excel allows shapes to contain text, with the exception of connectors: lines and arrows can't contain text. To label an arrow, you just put a text box on top of it—but the box isn't "attached" to the arrow in a way that VBA can easily capture.
For example, a user might draw something like this:
Within my VBA code, I can use ActiveSheet.Shapes to find that the flowchart contains seven shapes: there are five boxes (the two labels are just boxes with no border) and two arrows. Then Shape.TextFrame2 will tell me what's written inside each box, and Shape.ConnectorFormat will tell me which box goes at the start and end of each arrow.
What I need is code that can deduce:
Label A belongs to the arrow from Box 1 to Box 2
Label B belongs to the arrow from Box 1 to Box 3
I can think of three ways of doing this, none of them satisfactory.
Ask the user to group each label with its corresponding arrow.
Find out the coordinates of the endpoints of each arrow, then
calculate which arrows pass through which labels.
Find out the coordinates of the corners of each box, then calculate
which labels lie between which pairs of boxes.
Method 1 makes things easier for the programmer but harder for the user. It opens up a lot of potential for user error. I don't see this as an acceptable solution.
Method 2 would be reasonably easy to implement, except that I don't know how to find out the coordinates!
Method 3 is doable (Shape.Left etc will give the coordinates) but computationally quite messy. It also has potential for ambiguity (depending on placement, the same label may be associated with more than one arrow).
Note that methods 2 and 3 both involve trying to match every label with every arrow: the complexity is quadratic. Typical applications will have 10–50 arrows, so this approach is feasible, if somewhat inelegant.
Does anyone have a better idea? Ideally it would be something that doesn't involve coordinate geometry and complicated logic, and doesn't involve asking users to change the way they draw flowcharts.
Edited to add: example 2 in response to Tim Williams
Here's a label whose bounding box intersects the bounding box of both arrows, and whose midpoint isn't inside the bounding box of either arrow. Visually it's easy for a human to see that it belongs with the left arrow, but programmatically it's hard to deal with. If I can find out the coordinates of the arrows' endpoints, then I can calculate that one arrow passes through the label's box but the other doesn't. But if all I have is the bounding rectangles of the arrows, then it doesn't work.
Interesting problem. What if you considered the range covered by the arrow and the range covered by the textbox and matched them up based on the most overlap.
Sub ListShapes()
Dim shp As Shape
Dim shpArrow As Shape
Dim vaArrows As Variant
Dim i As Long
Dim rIntersect As Range
Dim aBestFit() As String
Dim lMax As Long
vaArrows = Split("Straight Arrow Connector 7,Straight Arrow Connector 9", ",")
ReDim aBestFit(LBound(vaArrows) To UBound(vaArrows))
For i = LBound(vaArrows) To UBound(vaArrows)
Set shpArrow = Sheet1.Shapes(vaArrows(i))
lMax = 0
For Each shp In Sheet1.Shapes
If shp.Name Like "Label*" Then
Set rIntersect = Intersect(Sheet1.Range(shp.TopLeftCell, shp.BottomRightCell), _
Sheet1.Range(shpArrow.TopLeftCell, shpArrow.BottomRightCell))
If Not rIntersect Is Nothing Then
If rIntersect.Count > lMax Then
lMax = rIntersect.Count
aBestFit(i) = shp.Name
End If
End If
End If
Next shp
Next i
For i = LBound(vaArrows) To UBound(vaArrows)
Debug.Print vaArrows(i), aBestFit(i)
Next i
End Sub
I tested this with the five box-two arrow setup and nothing more complicated. I put my two arrows in an array, but I assume you have ways to identify the arrows. I also named my untethered boxes "Label x" so I could identify them, but again I assume you have something more sophisticated.
The code loops through every arrow. Inside that loop, it loops through every shape. If it's a label, then it counts the cells in the intersection of the two ranges. Whichever has the most is stored in the best fit array.
It would be nice if you had a reasonable corpus of flow charts to test this to see where the pitfalls are. I don't think this is necessarily better than use the coordinates, just a different approach.
You can find the coordinates of the arrow's endpoints as follows.
First of all, the .Left, .Top, .Width and .Height properties describe the bounding rectangle of the arrow, as Tim Williams points out.
Next, check the .HorizontalFlip and .VerticalFlip properties. If both are false, then the arrow runs from top left to bottom right in its bounding rectangle. That is, the beginning of the arrow has coordinates (.Left,.Top) and the end has coordinates (.Left+.Width,.Top+.Height).
If either *.Flip is true, then the coordinates need to be swapped around as appropriate. E.g., if .HorizontalFlip is true but .VerticalFlip false, then the arrow runs from (.Left+.Width,.Top) to (.Left,.Top+.Height).
As far as I can tell, this is not documented anywhere on MSDN. Thanks to Andy Pope for mentioning it at excelforums.com.
Given this, method 2 seems like the best approach.