Deleting images but can't avoid deleting command button - excel

I'm not a regular user of vba, so when I started doing this code I was totally blank. I already deleted all the images on the worksheet, including command buttons and a logo I didn't meant to delete.
This is my code
Private Sub CommandButton2_Click()
Dim Pic As Object
Range("D20:D3000").ClearContents
For Each Pic In ActiveSheet.Pictures
Pic.Delete
Next Pic
End Sub
As you can see I need it to delete the images on the D column, but it deletes the images of the whole sheet.
I can't find a way to exclude command buttons (I'm using 2 on that sheet) of the deleting instruccion. Would some of you please, please, please help me? I'm a mess right now.

I need it to delete the images on the D column, but it deletes the images of the whole sheet.
You are iterating all pictures on the sheet, and never verify where on the sheet the picture is before you invoke its Delete method.
Interestingly, if you have one picture and one ActiveX command button on Sheet1, then Sheet1.Pictures.Count returns, unexpectedly, 2 - that's why the loop is also deleting command buttons.
I'd suggest iterating the Shapes collection instead: a Shape object has an interface that makes it much easier to tell a picture apart from an ActiveX button, ...and to know where on the sheet it's at.
Using Shape.Type we can know if we're looking at a msoPicture, and with Shape.TopLeftCell we can get a Range object representing the top-left cell the picture is located at; if the Column of that Range is 4, then we're looking at a shape whose upper-left corner is located in column D. Thus:
Dim currentShape As Shape
For Each currentShape In ActiveSheet.Shapes
If currentShape.Type = msoPicture And currentShape.TopLeftCell.Column = 4 Then
currentShape.Delete
End If
Next
Note how declaring an explicit type that isn't Object for our loop variable, we get compile-time validation, and autocomplete/intellisense for every single one of these member calls, whereas calls made against Object are all late-bound (i.e. compiles perfectly fine with typos, even if you have Option Explicit at the top of your module) and will only blow up at run-time if anything is wrong (e.g. error 438 if you try to invoke a member that doesn't exist).

The following compares the picture's range with your range and deletes it if they intersect:
Private Sub CommandButton2_Click()
Dim objPicture As Object
Dim objPictureRange As Object
Dim objRange As Object
Set objRange = Range("D20:D3000")
objRange.ClearContents
For Each objPicture In ActiveSheet.Pictures
' Get Picture's range
Set objPictureRange = Range(objPicture.TopLeftCell.Address & ":" & objPicture.BottomRightCell.Address)
' Check if Picture is in Range
If Not Intersect(objRange, objPictureRange) Is Nothing Then
' Delete picture
objPicture.Delete
End If
Next Pic
End Sub

Related

Excel VBA - 1004 Error code when removing picture from excel sheet

I have a made a VBA based complaints form that keeps track of a number of details about a complain. One feature that i added lately is that it is now possible to add a picture to the report/form.
When the form is submitted all the filled cells are copied to a seperate spreadsheet and the form itself needs to wiped and the pictures need to be removed so that a new report can be filled if neccessary. It is like a reset.
In order to remove the pictures I copied the below piece of script. About 90% of the time it works perfectly fine and the images are removed and the form is back to it's original form however every once in a while for unknown reason i get a Error 1004 "Application Defined or Object Defined Error". When i receive this error i am unable to remove the pictures and need to restart the excel file.
Within VBA highlighted in yellow it says that the k.TopLeftCell is the cause of it.
With Sheets("Klachtformulier")
Dim k As Shape, rng As Range
Set rng = Sheets("Klachtformulier").Range("A43:H47")
For Each k In ActiveSheet.Shapes
If Intersect(k.TopLeftCell, rng) Is Nothing Then
Else
k.Delete
End If
Next k
I tried to change activesheets to the sheet("name"), tried change the range, tried to change shape dim into a picture dim and tried to exit the for after one loop however all without succes so far. Most of the time these changes cause the pictures from not being removed anymore.
Any idea what could be the cause or the solution?
I think the problem is likely that you are deleting members of a collection (the Shapes collection) while iterating over it using 'For ... Each'. When deleting, you should use 'For ... Next' and loop from the end of the collection to the start:
Dim k As Shape, rng As Range
Dim i As Long
Set rng = Sheets("Klachtformulier").Range("A43:H47")
For i = ActiveSheet.Shapes.Count To 1 Step -1
Set k = ActiveSheet.Shapes.Item(i)
If Not Intersect(k.TopLeftCell, rng) Is Nothing Then
k.Delete
End If
Next i
I tweaked the logic of your If statement and removed the With line as (in the code you posted) it isn't doing anything useful.

Selecting a shape

I am currently working on an Excel tool that I have equipped with one button and one shape-object.
The button is a select button to "select" the shape object. The idea is to Select a shape-object a Picture and change its color after selecting it.
I was able to locate the problem to the clicked Sub of the Select button.
To check if I'm correct I have written a the Macro Select_MyClicked and afterword used the call instruction to invoke the macro from within the Clicked-function of the select button.
Sub Select_MyClicked()
Dim ElementName As String
Dim Shp As Object
Set Shp = Sheets("Tabelle1").Shapes(ElementName)
Shp.Select
End Sub
==================================================================
Private Sub CommandButton3_Click()
Call Select_MyClicked
End Sub
==================================================================
What is interesting now is:
When I use the Button the Image is selected but in the Picture format register there i nothing selectable
If I cklick on the Image itselfe or use the Select_MyClicked Macro indepentently everything in the picture format register is selectable
I also tried to write the select instruction directly into the Button-Clicked private sub. Same result nothing selectable
What I want to do is select an image and change its color. My second question is does somebody know how to open the Colorpennel (with the many colored Rectangles) using vba ?
You need to reference the Shape by its Name. I assigned the name "myshape" to the Shape before running:
Sub Select_MyClicked()
Dim ElementName As String
Dim Shp As Shape
ElementName = "myshape"
Set Shp = Sheets("Tabelle1").Shapes(ElementName)
Shp.Select
End Sub
The code runs even if Tabelle1 is not the active sheet.
I have finally find the solution. It seems like it makes a difference which button you use. In my case it had to be the control elements not the activeX elements

VBA to get selected shape name in Combobox

I am new to VBA. i have few shapes in a worksheet.
I want to get the name of shape to appear in combobox and character name in another Combobox, when any particular shape is selected. so i can rename that shape and link to particular excel column.
i have tried following.
With Selection
ActiveSheet.ComboBox1.Value = ActiveSheet.Shapes(Application.Caller).Name
End with
Not sure where to assign above code.
I tried assigning above code to a shape with .onaction as macro, it work but a marco assiged shape cannot be edited further(For design purpose).
Also It would be great if i can delete selected shape.
Thank you in advance.
You can use your code for any shape and you can change the code whenever you want, but assigning a macro, she shape will will not be selected when clicked... It becomes a kind of control.
Excepting the case when you force it to select:
Debug.Print ActiveSheet.Shapes(Application.Caller).Name
shW.ComboBox1.value.Shapes(Application.Caller).Select
You can change the code from right click context (on the chart bottom side) and choose 'Assign Macro... -> Edit'.
You can find the selected shape using the next code:
Sub testSelectedShape()
Dim shW As Worksheet, sh As Object, selSh As Object
Set shW = ActiveSheet
If TypeName(Selection) <> "Range" Then
Set selSh = Selection
Set sh = shW.Shapes(selSh.Name)
Debug.Print selSh.Name
shW.ComboBox1.value = selSh.Name
End If
End Sub
You can delete it simple using sh.Delete...

Excel Visual Basic Code Issue

I'm designing a PO that changes the cost per unit depending on the item selected in the Drop Down List.
I'm using...
Sub DropDown8_Change()
If (DropDown8.SelectedItem = "1") Then
Range("E21").Value = "54.90"
End If
End Sub
However I get the error,
Run-time error '424': Object required
If I remove the IF statement and have it simply change the contents of the Cell, It works.. So I'm assuming it is an issue with the Conditional Statement.
From my signifigant past with Visual Basic in Visual Studio, The name of the Control is included in the Method so I'm confused. I could be doing alot wrong here so bear with me :).
Thanks in advance
Working with Shapes on an Excel worksheet is kind of annoying. I usually stay away from them if I can.
Here's how you get the data you're looking for:
Sub DropDown8_Change()
Dim selectedItem As String
Dim ws As Excel.Worksheet
Set ws = Sheets(1)
Dim selectedIndex As Long
selectedIndex = ws.Shapes("Drop Down 8").ControlFormat.Value
selectedItem = ws.Shapes("Drop Down 8").ControlFormat.List(selectedIndex)
If (selectedItem = "1") Then
Range("E21").Value = "54.90"
End If
End Sub
The problem is that the method that's generated for you (in your case, DropDown8_Change()) doesn't really give you much to work with (like with Worksheet_Change(ByVal Target As Range)), and you have to deal with VBA Shapes (yuck).
You need to reference the Shape by it's actual name (unless you know the Shape's index, which isn't as easy to determine). The name can be found by right-clicking on the shape and then looking in the Range address textbox to the left of the formula bar. Then you have to go through this whole ControlFormat hoops to get what you're looking for.
Sorry for the rant. I hate VBA Shapes.

Excel 2010 command button disappears

I'm developing an Excel 2010 workbook, in a manual formulas calculation mode.
(file -> options -> formulas -> Workbook calculation -> manual)
I have some command buttons in the sheet (ActiveX controls), and I set them to move and size with cells (right click on the button -> format control -> Properties -> move and size with text).
This is since I have some rows filtered out under some conditions, and I want the buttons placed in these rows to appear and disappear as well, according to the display mode of their hosting rows.
It all goes perfectly fine, till I save he worksheet when some of the rows (hence buttons) are filtered out (i.e. not displayed).
When I re-open the file again, and expand the filtered rows, the buttons don't show. When checking their properties I see that their visible property is True, but their height is 0, and this doesn't change when I un-filter their hosting rows.
I want to emphasize again that before saving the file - both filtering and un-filtering the buttons worked well.
Would much appreciate any help here.
OK so I get the same results either with ActiveX or Form Controls. For whatever reason, it seems the control's original height does not persist beyond the save & close.
Another option would be to simply clear the AutoFilter on the Workbook's Close and Save events. However, this probably is not what you want if you like to leave some filter(s) on when you save and re-open the file. It's probably possible to save the filter parameters in a hidden sheet or by direct manipulation of the VBE/VBA, but that seems like a LOT more trouble than it's worth. Then you could re-apply the filter(s) when you re-open the workbook.
Here is what code I suggest
NOTE: I relied on the worksheet's _Calculate event with a hidden CountA formula (setting, changing, or clearing the AutoFilter will trigger this event). I put the formula in E1 just so you can see what it looks like:
Since your application relies on Calculation = xlManual then this approach will not work exactly for you but in any case, the subroutine UpdateButtons could be re-used. You would need to tie it in to another event(s) or functions in your application, as needed.
Here is the code
Option Explicit
Private Sub UpdateButtons()
'## Assumes one button/shape in each row
' buttons are named/indexed correctly and
' the first button appears in A2
Dim rng As Range
Dim shp As Shape
Dim i As Long
Application.EnableEvents = False
'## use this to define the range of your filtered table
Set rng = Range("A1:A6")
'## Iterate the cells, I figure maybe do this backwards but not sure
' if that would really make a difference.
For i = rng.Rows.Count To 2 Step -1
Set shp = Nothing
On Error Resume Next
Set shp = Me.Shapes(i - 1)
On Error GoTo 0
If Not shp Is Nothing Then
DisplayButton Me.Shapes(i - 1), Range("A" & i)
End If
Next
Application.EnableEvents = True
End Sub
Private Sub DisplayButton(shp As Shape, r As Range)
'# This subroutine manipulates the shape's size & location
shp.Top = r.Top
shp.TopLeftCell = r.Address
shp.Height = r.Height
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
MsgBox "_Change"
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
''## Assumes one button/shape in each row
'' buttons are named/indexed correctly and
'' the first button appears in A2
'Dim rng As Range
'Dim shp As Shape
'Dim i As Long
'
''## Uncomment this line if you want an annoying message every time
''MsgBox "Refreshing Command Buttons!"
'
'Application.EnableEvents = False
''## use this to define the range of your filtered table
'Set rng = Range("A1:A6")
'
''## Iterate the cells, I figure maybe do this backwards but not sure
'' if that would really make a difference.
'For i = rng.Rows.Count To 2 Step -1
' Set shp = Nothing
' On Error Resume Next
' Set shp = Me.Shapes(i - 1)
' On Error GoTo 0
'
' If Not shp Is Nothing Then
' DisplayButton Me.Shapes(i - 1), Range("A" & i)
' End If
'Next
'
'Application.EnableEvents = True
End Sub
For Another option See this article. You can re-purpose existing commands with RibbonXML customization. While this article is geared towards C# and Visual Studio it's possible to do it with the CustomUI Editor.
I had a similar problem with buttons disapearing (moving on upper left corner) when removing filters.
A solution I found was to add a row above the columns headers so that buttons were still appearing at the top of the columns but were not touching the row where filters were placed.
Adding / removing filters stop interfering with buttons' positions.
I had a similar problem where form buttons appear to work fine, but then disappear after saving and reopening the workbook. Specifically this happened when the form button where part of hidden rows (done using vba code).
Seems like a real bug, although I don't know where the link is.
By changing the form buttons to ActiveX buttons, the buttons stopped disappearing, but started moving/bunching to the top of the screen when the rows were hidden. I just added some vba to re-position the buttons (e.g. CommandButton1.Top = Range(A12:A12).Top --> moves the ActiveX command button to the 12th row).

Resources