Protecting the Specific Shapes and Images in Excel VBA - excel

I have an Excel Sheet with some macros. Also, I have some navigation shapes and images on my sheet. I want users of this sheet, cannot change this shapes and images positions, can't select them and can't move them.
Is there any way to Protect some specific objects?
Regards.

I believe this is an age old question ever since Shapes were added to MS Excel and the answer to which I myself was looking for many years already.
I just found out 3 days ago, on my own, how to lock MS Excel Freeform shapes like Choropleth Map shapes from being moved around, reformatted or worst, deleted, all WITHOUT needing to lock the WorkSheet, or eventually the WorkBook.
And I think I must share my discovery with the world because everyone wants to lock their Shapes!
Steps: (I work with Excel VBA and with msoFreeform shapes mostly but I think any shape should be working and manually added shapes through Excel UI should work too and in other Office Apps as well)
1.(yourWorkSheet or )ActiveSheet.Shapes.AddChart (through VBA but MAYBE you can add chart through Excel UI and then delete the only chart)
(no need for any other parameter because we just need the chart container, "ChartObject")
2.If you don't have some already, create a shape either through Excel UI or through VBA with AddShape method or BuildFreeform on the Chart directly or on to the worksheet.
3.Copy/Paste the created shape (if created through Excel UI or through VBA on the worksheet) on to the BLANK Chart Container. (NOT drag and drop)
4.Format the ChartContainer Rectangle window as required (try "No Fill & No Outline") through VBA or Excel UI
5.There are 3 options regarding protection of a Chart
(Embedded chart here because I don't work with Chart Sheets, may be this might work with them)
source:[https://peltiertech.com/Excel/ChartsHowTo/ChartProtection.html]
But here, only the relevant 2 will be shown:
5(a)ActiveChart.ProtectFormatting = True
That protection will block any formatting changes on the Shape and the Chart via "Chart Tools Menu" or "Drawing Tools - Format Menu" or moving or resizing with mouse or deleting BUT will show the ChartContainer window upon Selection via Mouse but non-selectable via VBA
eg. yourworksheet.ChartObjects("YourChartName").Chart.ProtectFormatting=True
5(b)ActiveChart.ProtectSelection = True
That will stop the shape or the chart from being selected altogether so this is the end of story
eg. yourworksheet.ChartObjects("YourChartName").Chart.ProtectSelection=True
The best thing about this method is that the shape can still be accessible through VBA like
eg.yourworksheet.ChartObjects("YourChartName").Chart.Shapes("YourShapeName or Index").whatever
except Shape.Select which should be obvious and there is NO need to lock the Worksheet or Workbook at all.
NB:1)The interesting finding here is that the 2 protections do not replace each other (if applied one after another) but more like stacked with each other meaning if both (if you really want) were set True first and then after setting either one False, the other restriction still remains.
2)Even if selection is protected as above, the chart can still be accessible through the Selection Pane, therefore:
Application.CommandBars("Selection and Visibility").Enabled = False
and also blocking the Worksheet Export are advisable but I think these are overkill nonetheless included for completeness' sake.
Discovered and tested on MS Excel 2010 so YMMV.

Nay Lynn's answer caused my Excel to crash. Specifically with the .ProtectSelection property being enabled (using Microsoft365 Excel). . . Excel VBA's Intellisense shows the property, so it is legitimate, but everything would be fine until the chart was selected. Playing around with this idea though, I did find a great work around.
1. Place a Chart on your sheet. Make it span across the area you want to protect
(we will expand the size of this chart later).
a. Leave Fill of Chart at Default until a later step (this helps ensure the
next steps are successful).
b. Delete all the elements present for the chart (Series label, Title, Etc.)
c. Shrink the "Plot Area" box leftover to as negligible as possible.
d. CRITICAL: Right Click the chart and choose "Select Data" - use the
option to remove all the data in the boxes of this dialog, otherwise when
you select the Rectangle added below, it will show the data references as
selections in the Worksheet behind it.
2. Insert a Rectangle into the Chart. It will have the default colors.
3. Tap `Esc` to clear the selection. If you select the shape and try to move it
around, it will take precedence over the Chart itself (this is how we'll trick
Excel later).
a. Confirm this does not allow the shape to be pulled beyond the border of the
Chart.
4. Set Fill of Chart to be "No Fill"
5. Expand the Rectangle's size to match the size of the chart.
6. Set Fill of Rectangle to be a color with 100% Transparency (NOT the same as "No
Fill" - this is critical)
a. You should be able to see all of your shapes, etc, but not touch them if you
click where the rectangle was, and trying to click and drag will also fail since the
Rectangle takes selection precedence and is also bound by the chart.
7. Set the fill of the Rectangle back to a color with 0 transparency (we need to
find the edge of the shape)
8. Select the Rectangle's border and it should then select the Chart instead (you
should see the chart Format option appear).
9. Expand the Chart's border to the ends of the Excel Sheet (ensure the top left
corner sits in the top left corner of the sheet by dragging it). You can also set
the height/width to an absurd number that users will get fed up with trying to find
if you do not wish to expand it across the entire boundaries (or if there's a hard
limitation - I did not try to expand across the entire sheet, but went to "BO400"
with no issue.
a. Expand the Rectangle to fit the Chart once again if it did not expand
automatically (in my case it did, but I cannot guarantee this behavior)
b. If you have any Buttons that DO need to be clicked, place this chart
at the bottom, place all the buttons/shapes etc. that need interaction to
the top, then bring the chart up a level until all the items needing
protection are hidden.
c. Change the Transparency back to 100%
10. After you have the Chart expanded properly, you will need to use a bit of VBA
to ensure the Chart's Formatting is protected as Nay Lynn mentions. Get the
Chart's name by selecting the border, and institute some VBA Code that gets
toggled based on your needs (you might want to include an unprotect sub
as well just in case).
Example:
Sub Protect_Sheet_With_Chart ()
dim sht as Worksheet
dim chrt as Chart
Set sht = ActiveSheet
'You can use a sheet by name for the above as well - make your code robust.
Set chrt = sht.ChartObjects("ChartNameFoundFromStep10").Chart
chrt.ProtectFormatting = True
End Sub
Sub UnProtect_Sheet_With_Chart ()
dim sht as Worksheet
dim chrt as Chart
Set sht = ActiveSheet
'You can use a sheet by name for the above as well - make your code robust.
Set chrt = sht.ChartObjects("ChartNameFoundFromStep10").Chart
chrt.ProtectFormatting = False
End Sub
11. After you protect the Chart, selecting it and deleting will not
actually delete it, NOR the rectangle, so it can't be removed!
12. Protect your code somehow and you'll be set!

Related

PowerPoint VBA Changing font color of selected item in chart

I know this sounds simple, but I haven't found any solution in the web nor this site.
So, I have a macro in Excel that changes the font color of any selected item -- range, chart, textbox, etc. -- and the code is quite simple:
Selection.Font.Color = RGB(0,0,0)
But in PowerPoint there is not such thing as the "Selection" wildcard in Excel. In PowerPoint this work well for textboxes --
ActiveWindow.Selection.TextRange.Font.Color = RGB(0,0,0)
But it does not work for charts and tables. So, for charts I use this code --
ActiveWindow.Selection.ShapeRange(1).Chart.ChartArea.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB RGB(0,0,0)
The problem is that it changes all the text in the chart -- title, labels, axis, etc. And I only need to change the font color of the selected item. for example, only the title or only the labels, depending on what the user decides to select.
I don't know how to discriminate what item is selected in the chart, in order to apply the change only to it. For example --
.ChartTitle.Format.Fill.ForeColor.RGB, etc.
Is there a way to identify what item is selected? Or to apply the changes only to it? Thank you.
The simple answer to your question is, unfortunately, no. The PPT object model has no way of returning the selected item in a chart.
John Korchok's suggestion should allow you to offer the desired colors to your users to choose, though.
You were very close. Instead of .ChartArea you can access other chart items, such as .ChartTitle.
This example loops through all the shapes on a slide, including some extra checks to prevent errors. If the shape has a chart, the chart has a title and title has text, specify the color for the chart's title font.
Sub FontColor_ChartTitle()
With ActivePresentation.Slides(1)
'Loop through all shapes on the slide
For i = 1 To .Shapes.Count
With .Shapes(i)
'If the shape is a chart
If .HasChart Then
'If the chart has a title
If .Chart.HasTitle Then
With .Chart.ChartTitle.Format.TextFrame2
'If the title contains text
If .HasText Then
With .TextRange.Font
.Fill.ForeColor.RGB = RGB(95, 37, 97)
End With
End If
End With
End If
End If
End With
Next
End With
End Sub
Since the basic issue is providing the client with more colors while avoiding having them input RGB values, I think you might want to evaluate the simplest most flexible way to do that.
For color options beyond the theme colors, adding Custom Colors to the file is a better way to go. I would drop all the VBA selection-based formatting. This article emphasizes PowerPoint, but custom colors can be used in Word and Excel as well: Custom Colors added to color picker

How to position a chart copied from excel into powerpoint using CommandBars?

I am trying to copy some charts (embedded) in different worksheets of an excel workbook using vbscript into different slides of a powerpoint. I would like to keep the link between the excel sheet and the powerpoint while doing so and therefore I used the below piece of code that allows me to keep formatting and link (instead of a simple paste or PasteSpeical. Is there any other way?) :
For i = 1 to TotalNumWorkSheets 'I iterated with indices.
Set pptSlide = pptPres.Slides.Add(i, 11) 'There is one opening slide before this.
set ws = wb.Worksheets(i)
ws.ChartObjects(1).Chart.ChartArea.Copy
pptApp.CommandBars.ExecuteMso("PasteExcelChartSourceFormatting")
pptApp.CommandBars.ReleaseFocus
With pptSlide
.Shapes.Title.TextFrame.TextRange.Text = objCurSheet.Name
'Adding some more textboxes here. Working fine. Position checks out in PPT.
.Shapes(.Shapes.Count).Left = 20 'Doesn't work for all slides.
End With
Next
The code works and copies all the charts, creates titles, adds new text as expected, but I am not able to position the charts on individual slides because after the ExecuteMso command, I don't know how to access the reference to the chart. I read in one of the SO posts that pasting using this method looses the chart selection but you can access the last .Shapes object since pasting always adds the object to the end of the list. Is that always the case? I tried accessing and positioning my chart by accessing the last object but it only works for the first slide of the loop (i.e. the first chart pasted is shifted to Left=20). The rest all charts in other slides are centered. Can someone explain where and how to add the formatting chart options? I ran into an even weirder problem. If I increase the number of worksheets, even the first plot looses it's Left formatting. The above code is the only place where I add formatting so I don't know what is happening. I am sure I am not formatting it correctly.
Many thanks for your suggestions.
Edit: One additional thing which I tested. I am using
WScript.Sleep 500
code before the For loop ends since it gives enough time for earlier operations to finish (at least that's what I understood from many other google searches).
So after some more searching and testing, I found a solution (for my case at least).
Moved the WScript.Sleep 1000 (500 didn't work for me) statement just below CommandBars.ReleaseFocus.
It makes some sense now since it is the Chart copying, pasting and linking from excel that needs time. Especially with source formatting. After that there is only text generation which I believe is not so heavy.
Cleared all the set Object variables when not used. Especially the ones associated with the "With" keyword.
set obj = CreateObject()
With obj
'Do something here.
End With
set obj = Nothing
Not clearing them, apparently, can also prevent you from closing the applications even after you use the .Close and .Quit method. At least that's what I observed. I found PowerPoint.exe running in the task manager when nothing was opened.
After doing the above, I am able to copy with format the charts and also able to set the position of the charts. The weird problem of larger number of worksheets also disappeared. Hopefully, it might help others. If someone thinks the observations are incorrect or troublesome, please correct.

Dynamic Range for Intentionally Showing Nothing

So, I've created a dynamic range for a chart, that's all well and easy.
However, in this chart there are two lines, but I only want one of the lines to show up under certain conditions, else it displays nothing! So I've tried creating my dynamic range as follows
=IF('WorksheetName'!$M$10 ='WorksheetName'!$F$31,'WorkSheetName'!dynamic_range, #N/A)
The problem is that when I do this the chart freaks out. It gives me this error:
Your formula contains an invalid external reference to a worksheet.
Verify that the path, workbook, and range name or cell reference are
correct, and try again.
If I click "ok" half the time it shows up correctly (that is, the second line disappears and the chart adjusts accordingly) and the other half the time it glitches.
Basically, how do I create a dynamic range for graphing that the chart will understand when I want it to do NOTHING and when I want it to display the range?
You need a second source range, that's cells are just empty. Applying your approach to switch between the filled range (intended to be visible) vs. the empty range (will be invisible), shall solve the issue. Note: The chart parameter "Show empty cells as:" should be set to "Gaps". (Refer to the Hidden and Empty Cells options in the chart's Select Data dialog. This is applicable to X/Y charts mainly.)

Excel VBA: Height of shapes change after copy to sheet

I encountered this weird phenonemon when copying shapes with VBA, and I don't know how to deal with this:
When Cells and Shapes are copied using the regular .Copy function, the shapes are slighty compressed in the height direction. Their placement seems right, more or less.
I use VBA 7.0 with Excel 2010.
I sincerely hope someone can help me with this. I spend quite some time finding info on this subject!
Code:
Sub RenderOverview()
' Clear Worksheet
Sheets("ModelOverzicht").Cells.Clear
Sheets("ModelOverzicht").DrawingObjects.Delete
' Copy SINGLE SECTION
Sheets("Enkele Sectie").Range("A1:AM29").Copy
Sheets("ModelOverzicht").Select
Range("A1").Select
ActiveSheet.Paste
End Sub
I came here, because I had the same problem and the answer of "user1759942" didn't solve my problem. After a little bit investigation I was able to nail down the cause of the change in size of my chart.
My origin worksheet (where I copy said chart) had a zoom of 80%, while my destination worksheet (where I paste copied chart) had no zoom (100%).
After changing both worksheets to the same zoom value (80%) and activating the destination worksheet right before pasting the copied chart, the problem was gone. I didn't even need to change the "Format Shape" - Properties - "move but dont size" like suggested by "user1759942" (by the way: this is done in VBA/VBscript by setting: [Worksheet].ChartObjects(1).Placement = xlMove ' xlMove = &H2).
Perhaps this is an answer to question of "user3250519".
this is because the shapes are tied to the cells By default. So if a cell's height / width is changed, so will the shapes height / width. Right click "Format Shape" - Properties - "move but dont size" will keep the shapes spot, but will not change the size. Try it out. you may have to resort to savign the height of the rows / shapes before pasting and apply that after pasting
--
Edit
When copying and pasting, cells heights / widths are changed to I think the height and width of the range they are being pasted to. You could also change the height and width of the target range, to match the source range, before pasting.

Protect shapes so users can modify but not delete

I have a workbook with some shapes that I don't want users to delete easily. They are linked with an index, and the index number is linked with a whole other bunch of stuff.
However, the user needs to move the shapes around and resize them.
How can I set the protection on the sheet to allow users to modify the shapes but not delete them?
The ability to do this in VBA would be useful too, as a few of my macros unprotect and then protect cells.
This is not possible.
You can lock all shapes in the workbook by using this code
Private Sub Workbook_Open()
ActiveSheet.Protect Password:="test", userinterfaceonly:=True
Dim shape As shape
For Each shape In ActiveSheet.Shapes
shape.Locked = True
Next
End Sub
or you build a plugin for Excel in dot.net.
This blog describes how you would do that for shapes and there you can use events to overide the delete.
create excel events for shapes
or
Microsoft excel shape events
This is indeed possible but with a slight workaround. No windows API. However, what are your shapes?
You can utilize ActiveX image controls and manipulate the MouseDown/MouseUp events to detect starting position and ending position via the left and top properties. Once calculating the difference in positions, you can set the image's new top/left properties to the appropriate numbers. You can even look into possible drag effects for the image so the cursor does not appearing totally still during a drag.
Alternatively, you can turn on that sheet's protection for editing objects which prevents moving/deleting innately. It still allows clicking, at which point you can assign a macro that reacts somewhat similarly to solution #1 but is more complex. Your macro can read the picture name by referencing the "application.caller" property. Each picture name can have different procedures associated with it. Read the current top and left properties of the shape. Continuing breaking the automation down into 2 steps. Programmatically unprotect the sheet, and monitor with a public boolean that an operation is in progress. Use the selection change event to monitor the next cell click at which point you can capture the subsequent top and left properties, eventually calculating where the shape will move. Programmatically protect worksheet again.

Resources