I have an Excel spreadsheet consisting of several sheets. In each sheet I have a Button 1.
In order to move this button to Range("D9:E11") in all of the sheets I use the following VBA refering to the solution here:
Sub Sample()
MoveButton Sheet1, "Button 1", True
End Sub
Sub MoveButton(sh As Worksheet, btnName As String, Optional AllSheets As Boolean)
Dim Range_Position As Range
Dim ws As Worksheet
Set Range_Position = sh.Range("D9:E11")
If AllSheets = True Then
For Each ws In ThisWorkbook.Sheets
With ws.Buttons(btnName)
.Top = Range_Position.Top
.Left = Range_Position.Left
.Width = Range_Position.Width
.Height = Range_Position.Height
.Text = "Button"
End With
Next ws
Else
With sh.Buttons(btnName)
.Top = Range_Position.Top
.Left = Range_Position.Left
.Width = Range_Position.Width
.Height = Range_Position.Height
.Text = "Button"
End With
End If
End Sub
All this works perfectly so far.
However, now it can happen that some of the sheets (For example Sheet3 and Sheet5) do not have the Button 1.
In this case I get runtime error 1004 if I use the above VBA.
Therefore, I am looking for way to check if Button 1 exists in the sheet and if not the VBA should continue to the next sheet.
Something like this before the line With ws.Buttons(btnName):
If Shapes("Button 1").Exists Then
Run VBA
Else
End If
I tried to combine the VBA code above with this function in several ways but could not make it work so far.
Do you have any idea how to solve it?
It can be solved with a parody of "try..catch" construction. It's always bad to use on error check but in VBA not so many options for this.
Function like this should work for you:
Public Function isBtnExists(Optional ws As Worksheet = Nothing, Optional btnName As String = "Button 1") As Boolean
If ws Is Nothing Then
Set ws = ActiveSheet
End If
'turn off errors'
On Error Resume Next
Dim q As Object
'trying to assign button to a variable, if it doesn't exist - error number will appear in global Err object'
Set q = ws.Buttons(btnName)
'by checking the error we know exists button or not'
isBtnExists = (Err.Number = 0)
'dismiss "On Error Resume Next" not really needed here but in some cases VBA can behave weirdly, so it is better to keep it'
On Error GoTo -1
End Function
And in your code will be something like this:
For Each ws In ThisWorkbook.Sheets
If isBtnExists(ws) Then
With ws.Buttons(btnName)
.Top = Range_Position.Top
.Left = Range_Position.Left
.Width = Range_Position.Width
.Height = Range_Position.Height
.Text = "Button"
End With
End If
Next ws
I think either an error handling procedure (as per #AlexandruHapco's answer) or an iteration over buttons:
'....
For Each ws In ThisWorkbook.Sheets
For Each btn In ws.Buttons
If btn.Name = btnName Then
'Do something
Exit For
End If
Next btn
Next ws
'....
Related
I am developing a program that has multiple columns of Data that can be sorted by several of the columns. For aesthetics I am using Command Buttons click event to toggle sorting in ascending or descending order. My code is pretty simple. I am using images of "up" arrows and "down" arrows as ascending / descending indicators. All of the images are on the worksheet and depending on the sort method, the click event shows or hides the appropriate image.The coding is working correctly with one issue that I wasnt thinking about. When a user clicks the button to sort, that arrow shows and hides correctly for that column however the other columns still show an arrow which can confuse the user. I would like to hide the other images / arrows except for the images / arrows in the column that is being sorted.
See Attached Image For Clarification
In the photo above if the Player ID Command Button is pressed again the up arrow will hide and a down arrow will be visible but the other arrows will stay exactly as they are. I would like only the column being sorted to show the arrows.
The code below is used in the worksheet module using the command button click event.
Private Sub cmbAgentID_Click()
If ActiveSheet.Shapes.Range(Array("picAgentIDUp")).Visible = False Then
Call SortByAgentAsc 'sort ascending
ActiveSheet.Shapes.Range(Array("picAgentIDUp")).Visible = True
ActiveSheet.Shapes.Range(Array("picAgentIDDown")).Visible = False
Else
Call SortByAgentDes 'sort descending
ActiveSheet.Shapes.Range(Array("picAgentIDDown")).Visible = True
ActiveSheet.Shapes.Range(Array("picAgentIDUp")).Visible = False
End If
End Sub
Private Sub cmbAllHands_Click()
If ActiveSheet.Shapes.Range(Array("picAllHandsUp")).Visible = False Then
Call SortByHandsAsc 'sort ascending
ActiveSheet.Shapes.Range(Array("picAllHandsUp")).Visible = True
ActiveSheet.Shapes.Range(Array("picAllHandsDown")).Visible = False
Else
Call SortByHandsDes 'sort descending
ActiveSheet.Shapes.Range(Array("picAllHandsDown")).Visible = True
ActiveSheet.Shapes.Range(Array("picAllHandsUp")).Visible = False
End If
End Sub
Private Sub cmbCashHands_Click()
If ActiveSheet.Shapes.Range(Array("picCashUp")).Visible = False Then
Call SortByCashAsc 'sort ascending
ActiveSheet.Shapes.Range(Array("picCashUp")).Visible = True
ActiveSheet.Shapes.Range(Array("picCashDown")).Visible = False
Else
Call SortByCashDes 'sort descending
ActiveSheet.Shapes.Range(Array("picCashDown")).Visible = True
ActiveSheet.Shapes.Range(Array("picCashUp")).Visible = False
End If
End Sub
Private Sub cmbEmbers_Click()
If ActiveSheet.Shapes.Range(Array("picEmbersUp")).Visible = False Then
Call SortByEmbersAsc 'sort ascending
ActiveSheet.Shapes.Range(Array("picEmbersUp")).Visible = True
ActiveSheet.Shapes.Range(Array("picEmbersDown")).Visible = False
Else
Call SortByEmbersDes 'sort descending
ActiveSheet.Shapes.Range(Array("picEmbersDown")).Visible = True
ActiveSheet.Shapes.Range(Array("picEmbersUp")).Visible = False
End If
End Sub
Private Sub cmbFees_Click()
If ActiveSheet.Shapes.Range(Array("picFeeUp")).Visible = False Then
Call SortByFeeAsc 'sort ascending
ActiveSheet.Shapes.Range(Array("picFeeUp")).Visible = True
ActiveSheet.Shapes.Range(Array("picFeeDown")).Visible = False
Else
Call SortByFeeDes 'sort descending
ActiveSheet.Shapes.Range(Array("picFeeDown")).Visible = True
ActiveSheet.Shapes.Range(Array("picFeeUp")).Visible = False
End If
End Sub
Any Suggestions? I have been looking at ShapeRange which is new to me and Shape Arrays, but havent found what I am looking for yet.
-------Updated Code Below with Suggested Improvements Not Working-------
Created "Rotate It" Sub and assigned macro to a single arrow.
Sub RotateIt()
Dim s As Shape: Set s = ActiveSheet.Shapes(Application.Caller)
If s.Rotation = 0 Then
s.Rotation = 180
Else
s.Rotation = 0
End If
End Sub
Created 1 sub for Sorting and I think my problem is here...
Sub SortByEverything(sortKey As Range, Optional boolAsc As Boolean)
Dim sh As Worksheet: Set sh = ActiveSheet
Dim lastrow As Long: lastrow = Cells(Rows.Count, 2).End(xlUp).Row
Dim rng As Range: Set rng = sh.Range("B3:M" & lastrow)
If boolAsc Then
With rng 'your existing code for ACENDING sorting type, but using supplied sortKey...
.Sort Key1:=sortKey, Order1:=xlAscending, Header:=xlYes
End With
Debug.Print "Sort Ascending..."
Else
With rng 'your existing code for ACENDING sorting type, but using supplied sortKey...
.Sort Key1:=sortKey, Order1:=xlAscending, Header:=xlYes
End With
Debug.Print "Sort Descending..."
End If
End Sub
Created Class Module ButtonName
Option Explicit
Public WithEvents cmdButton As MSForms.CommandButton
Public Sub cmdButton_Click()
Dim sArr As Shape: Set sArr = ActiveSheet.Shapes("Arrow")
sArr.Top = cmdButton.Top: sArr.Left = cmdButton.Left + cmdButton.Width
If sArr.Rotation = 0 Then
SortByEverything cmdButton.TopLeftCell, True
sArr.Rotation = 180
Else
SortByEverything cmdButton.TopLeftCell
sArr.Rotation = 0
End If
End Sub
Created the worksheet activate sub
Option Explicit
Private arrEvents As Collection
Private Sub Worksheet_Activate()
Dim ActXButEvents As ButtonName, shp As Shape
Set arrEvents = New Collection
varSplitCol = 0
varSplitRow = 4
Call EnhancePerformance
Call FreezeSheetPanes
For Each shp In Me.Shapes
If shp.Type = msoOLEControlObject Then
If TypeOf shp.OLEFormat.Object.Object Is MSForms.CommandButton Then
Set ActXButEvents = New ButtonName
Set ActXButEvents.cmdButton = shp.OLEFormat.Object.Object
arrEvents.Add ActXButEvents
End If
End If
Next
Call NormalPerformance
End Sub
Try the next approach, please. Create a Sub to be called by all buttons Click event:
Sub HideArrows(sh As Worksheet)
Dim s As Shape
For Each s In sh.Shapes
If Right(s.Name, 2) = "Up" Or _
Right(s.Name, 4) = "Down" Then s.Visible = msoFalse
Next
End Sub
Then use your existing code in this way:
Private Sub cmbAgentID_Click() 'proceed in a similar way to all the other click events
Dim sh As Worksheet: Set sh = ActiveSheet
HideArrows sh
If sh.Shapes.Range(Array("picAgentIDUp")).Visible = False Then
Call SortByAgentAsc 'sort ascending
sh.Shapes.Range(Array("picAgentIDUp")).Visible = True
Else
Call SortByAgentDes 'sort descending
sh.Shapes.Range(Array("picAgentIDDown")).Visible = True
End If
End Sub
Edited: Try the next different approach, please. It is very compact. The whole necessary code will be the next one, in a standard module:
Create a single (Up) arrow shape and name it "Arrow"
Each (Form type) button will target the same Sub, so assign to all of them the next code. For an ActiveX button I will show the approach (a little more complicated, but not too much) at the end:
Sub Button_Click()
Dim s As Shape: Set s = ActiveSheet.Shapes(Application.Caller)
Dim sArr As Shape: Set sArr = ActiveSheet.Shapes("Arrow")
sArr.Rop = s.top: sArr.left = s.left + s.width
If sArr.Rotation = 0 Then
SortByEverything s.TopLeftCell, True 'ascending
sArr.Rotation = 180
Else
SortByEverything s.TopLeftCell 'descending
sArr.Rotation = 0
End If
End Sub
Use the sorting Subs built in the next way. They will receive the sorting key according to each pressed button position:
Sub SortByEverything(sortKey As Range, Optional boolAsc As Boolean)
Dim sh As Worksheet
Set sh = ActiveSheet
If boolAsc Then
'your existing code for ACENDING sorting type, but using supplied sortKey...
'....
Debug.Print "Sort Ascending..."
Else
'your existing code for ACENDING sorting type, but using supplied sortKey...
'....
Debug.Print "Sort Descending..."
End If
End Sub
In order to change the arrow orientation/sorting type, please assign the next code to the "Arrow" shape:
Sub RotateIt()
Dim s As Shape: Set s = ActiveSheet.Shapes(Application.Caller)
If s.Rotation = 0 Then
s.Rotation = 180
Else
s.Rotation = 0
End If
End Sub
This approach philosophy would be the next: When press a button the "Arrow" shape will be moved to its right side. According to its rotation property, the sorting will be done ascending or descending. Then the arrow rotation will be adapted. If it remains down oriented and next time, for a different column, you need to sort descending, just click the arrow shape and it will rotate for the appropriate sorting type. You need only a single sorting Sub being informed about the sorting key and sorting type...
In case of ActiveX button, Application.Coller does not return the shape calling the sub name and a Class Events Wrapper is necessary...
a) Insert a class module, name it ButtonName and copy the next code:
Option Explicit
Public WithEvents cmdButton As MSForms.CommandButton
Public Sub cmdButton_Click()
Dim sArr As Shape: Set sArr = ActiveSheet.Shapes("Arrow")
sArr.top = cmdButton.top: sArr.left = cmdButton.left + cmdButton.width
If sArr.Rotation = 0 Then
SortByEverything cmdButton.TopLeftCell, True
sArr.Rotation = 180
Else
SortByEverything cmdButton.TopLeftCell
sArr.Rotation = 0
End If
End Sub
Note: No click events for all ActiveX buttons are necessary (for this specific task)!
b) Create a Private variable at the sheet level module. On top of it, in the declarations area:
Public arrEvents As Collection
c) Use Worksheet_Activate event (of course in the sheet keeping the buttons), in order to initialize the class for all ActiveX type buttons:
Private Sub Worksheet_Activate()
Dim ActXButEvents As ButtonName, shp As Shape
Set arrEvents = New Collection
For Each shp In Me.Shapes
If shp.Type = msoOLEControlObject Then
If TypeOf shp.OLEFormat.Object.Object Is MSForms.CommandButton Then
Set ActXButEvents = New ButtonName
Set ActXButEvents.cmdButton = shp.OLEFormat.Object.Object
arrEvents.aDD ActXButEvents
End If
End If
Next
End Sub
Note: When you have the code, it is not possible to press a button on the working sheet, without triggering the sheet Activate event. But, during your code preparation, it is necessary to activate another sheet and then reactivate it. Just in order to trigger the before mentioned event.
Check it please, if interested, and send some feedback.
I figured it out. Thank you to FaneDuru for helping me. I used the coding that FaneDuru provided but I separated the Up arrows and down Arrows to still leave the majority of them grouped but had to individually hide the other ones. For example in the Player ID column. In order for me to toggle the up and down arrows I had to at least have 2 arrows available. In FaneDuru code it only left me with 1 arrow to work with since the rest were not visible. The only way i could figure to to it was:
if down arrow was visible before the click event then I could hide all down arrows and all up arrows except for the arrow in that column. When the click event happens the up arrow becomes visible and the down arrow is hidden.
It was more work because i had to put the other shapes in an array individually
This is now fixed but there is always room to improve it.
Code for worksheet module
Private Sub cmbAgentID_Click()
Dim sh As Worksheet: Set sh = ActiveSheet
If sh.Shapes.Range(Array("picAgentIDUp")).Visible = msoFalse Then
hidedownarrows sh
Call SortByAgentAsc 'sort ascending
With sh.Shapes
.Range(Array("picAgentIDUp")).Visible = msoTrue
.Range(Array("picCashUp", "picAllHandsUp", "picEmbersUp", "picRBAmtUp", "PicRBUp", "picFeeUp", "picIDUp")).Visible = msoFalse
End With
Else
HideupArrows sh
Call SortByAgentDes 'sort descending
With sh.Shapes
.Range(Array("picAgentIDDown")).Visible = msoTrue
.Range(Array("picCashdown", "picAllHandsdown", "picEmbersdown", "picRBAmtdown", "PicRBdown", "picFeedown", "picIDdown")).Visible = msoFalse
End With
End If
End Sub
Private Sub cmbAllHands_Click()
Dim sh As Worksheet: Set sh = ActiveSheet
If sh.Shapes.Range(Array("picAllHandsUp")).Visible = msoFalse Then
hidedownarrows sh
Call SortByHandsAsc 'sort ascending
With sh.Shapes
.Range(Array("picAllHandsUp")).Visible = msoTrue
.Range(Array("picCashUp", "picAgentIDUp", "picEmbersUp", "picRBAmtUp", "PicRBUp", "picFeeUp", "picIDUp")).Visible = msoFalse
End With
Else
HideupArrows sh
Call SortByHandsDes 'sort descending
With sh.Shapes
.Range(Array("picAllHandsDown")).Visible = msoTrue
.Range(Array("picCashdown", "picAgentIDdown", "picEmbersdown", "picRBAmtdown", "PicRBdown", "picFeedown", "picIDdown")).Visible = msoFalse
End With
End If
End Sub
Private Sub cmbCashHands_Click()
Dim sh As Worksheet: Set sh = ActiveSheet
If sh.Shapes.Range(Array("picCashUp")).Visible = msoFalse Then
hidedownarrows sh
Call SortByCashAsc 'sort ascending
With sh.Shapes
.Range(Array("picCashUp")).Visible = msoTrue
.Range(Array("picAllHandsUp", "picAgentIDUp", "picEmbersUp", "picRBAmtUp", "PicRBUp", "picFeeUp", "picIDUp")).Visible = msoFalse
End With
Else
HideupArrows sh
Call SortByCashDes 'sort descending
With sh.Shapes
.Range(Array("picCashDown")).Visible = msoTrue
.Range(Array("picAllHandsDown", "picAgentIDdown", "picEmbersdown", "picRBAmtdown", "PicRBdown", "picFeedown", "picIDdown")).Visible = msoFalse
End With
End If
End Sub
Private Sub cmbEmbers_Click()
Dim sh As Worksheet: Set sh = ActiveSheet
If sh.Shapes.Range(Array("picEmbersUp")).Visible = msoFalse Then
hidedownarrows sh
Call SortByEmbersAsc 'sort ascending
With sh.Shapes
.Range(Array("picEmbersUp")).Visible = msoTrue
.Range(Array("picAllHandsUp", "picAgentIDUp", "picCashUp", "picRBAmtUp", "PicRBUp", "picFeeUp", "picIDUp")).Visible = msoFalse
End With
Else
HideupArrows sh
Call SortByEmbersDes 'sort descending
With sh.Shapes
.Range(Array("picEmbersDown")).Visible = msoTrue
.Range(Array("picAllHandsDown", "picAgentIDdown", "picCashDown", "picRBAmtdown", "PicRBdown", "picFeedown", "picIDdown")).Visible = msoFalse
End With
End If
End Sub
Private Sub cmbFees_Click()
Dim sh As Worksheet: Set sh = ActiveSheet
If sh.Shapes.Range(Array("picFeeUp")).Visible = msoFalse Then
hidedownarrows sh
Call SortByFeeAsc 'sort ascending
With sh.Shapes
.Range(Array("picFeeUp")).Visible = msoTrue
.Range(Array("picAllHandsUp", "picAgentIDUp", "picCashUp", "picRBAmtUp", "PicRBUp", "picEmbersUp", "picIDUp")).Visible = msoFalse
End With
Else
HideupArrows sh
Call SortByFeeDes 'sort descending
With sh.Shapes
.Range(Array("picFeeDown")).Visible = msoTrue
.Range(Array("picAllHandsDown", "picAgentIDdown", "picCashDown", "picRBAmtdown", "PicRBdown", "picEmbersDown", "picIDdown")).Visible = msoFalse
End With
End If
End Sub
Code for Standard Module
Sub HideupArrows(sh As Worksheet)
Dim s As Shape
For Each s In sh.Shapes
If Right(s.Name, 2) = "Up" Then
s.Visible = msoFalse
End If
Next
End Sub
Sub hidedownarrows(sh As Worksheet)
Dim s As Shape
For Each s In sh.Shapes
If Right(s.Name, 4) = "Down" Then
s.Visible = msoFalse
End If
Next
End Sub
My first post here, but have been successfully sourcing solutions and ideas from this website for a while now. So thanks for the collection of solutions and ideas.
Basically, I have a spread sheet application requiring the first column, Column A, to be filled with "Active X" buttons in every cell, looping through for a given quantity. I have posted one such working solution below which makes use of "form type buttons" and a Modules. This exemplifies what I consider my most favored example with working buttons. Once operational the column of buttons will correspond to relative data on the same row, and when clicked will open corresponding folders, and userforms in later developments.
The second post uses the Range function, but obviously doesn't incorporate any buttons to interactive with. However, a mouse click over this Range will obviously activate any code from within the Worksheet_Selection Change procedure...Sorry just stating the obvious!
What I have been trying to achieve is a version of code employing "activeX" Command Buttons, but after having studied some great tutorials and poured over a range of programing concepts, I still fail miserably to employ OLEObjects.
How to add a button programmatically in VBA next to some sheet cell data?
Sheet 1 Procedure:
Sub ColumnA_Buttons()
Dim buttons As Button
Dim rng As Range
Dim LineQty As Variant
Application.ScreenUpdating = False
ActiveSheet.buttons.Delete
LineQty = 5
For i = 1 To LineQty
Set rng = ActiveSheet.Range(Cells(i, 1), Cells(i, 1))
Set buttons = ActiveSheet.buttons.Add(rng.Left, rng.Top, rng.Width, rng.Height)
With buttons
.OnAction = "Buttons"
.Caption = "Line " & i
.Name = "Line " & i
End With
Next i
Application.ScreenUpdating = True
End Sub
Public Click_Button As Variant ' Make Variable Public for Userform1
'
Form Button Module:
Sub Line_Buttons()
Click_Button = Application.Caller
MsgBox Click_Button & " was Clicked"
UserForm1.Show 'Launch custom userform
End Sub
And the next option to be considered is a range detection
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' e.g., range(A1:E1) is clicked
If Not Application.Intersect(Target, Range("B2:B12")) Is Nothing Then
MsgBox "You clicked " & Target.Address
End If
End Sub
Ok. I'm posting some code that I've been working on based on this post here: Multiple active X checkboxes... . It seems I've now come to the same stand still they did as descibed in their last post :
"Yes it is individual checkboxes. You can emulate control arrays in
VBA so that each checkbox uses the same click event code, but that is
probably overkill IMO. "
And if I read Jason's post above, this is what he's questioning regarding the event code.
Any assistance welcomed in completing this code, as I have Not yet seen a working example which interlocks it to a single event, as per the form button module above.
Sub Macro1()
Dim objCmdBtn As Object
Dim i As Integer
Dim Rnge As Range
Set ColumnRange = Range("A:A") ' Set width & height of column A
ColumnRange.ColumnWidth = 5: ColumnRange.RowHeight = 15.75
'Delete previous objCmdBtn
For Each objCmdBtn In ActiveSheet.OLEObjects
If TypeName(objCmdBtn.Object) = "CommandButton" Then objCmdBtn.Delete
Next objCmdBtn 'TypeName Function returns the data-type about a variable - TypeName(varname is objCmdBtn)
With ActiveSheet
For i = 1 To 25
Set Rnge = ActiveSheet.Range(Cells(i + 1, 1), Cells(i + 1, 1))
Set objCmdBtn = Sheets("Sheet1").OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
Link:=False, _
DisplayAsIcon:=False, _
Left:=Rnge.Left, _
Top:=Rnge.Top, _
Width:=Rnge.Width, _
Height:=Rnge.Height)
With objCmdBtn
'set a String value as object's name
'.Name = "CommandButton1"
With .Object
.Caption = i
With .Font
.Name = "Arial"
.Bold = True
.Size = 7
.Italic = False
.Underline = False
End With
End With
End With
Next
End With
End Sub
Here is an example of ActiveX buttons being created and coded to run. It may take some small tweaks, but will get the job done.
Sub CreateButton()
Dim Obj As Object
Dim Code As String
Dim cellLeft As Single
Dim cellTop As Single
Dim cellwidth As Single
Dim cellheight As Single
Dim LineQty as Integer
Sheets("Sheet1").Select
LineQty = 5
For i = 1 To LineQty
Set rng = ActiveSheet.Range(Cells(i, 1), Cells(i, 1))
cellLeft = rng.Left
cellTop = rng.Top
cellwidth = rng.Width
cellheight = rng.Height
'create button
Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False, Left:=cellLeft, Top:=cellTop, Width:=cellWidth, Height:=cellHeight)
Obj.Name = "TestButton"
'button text
ActiveSheet.OLEObjects(1).Object.Caption = "Test Button"
'macro text to be added possibly by array?
Code = "Private Sub TestButton_Click()" & vbCrLf
Code = Code & "Call Tester" & vbCrLf
Code = Code & "End Sub"
'add macro at the end of the sheet module
With ActiveWorkbook.VBProject.VBComponents(ActiveSheet.Name).CodeModule
.insertlines
.CountOfLines + 1, Code
End With
Next i
End Sub
Sub Tester()
MsgBox "You have clicked on the test button"
End Sub
Note In order for this to not error on me, I had to go to the trust center and to trust center settings and macro settings and check the box "Trust Access to the VBA Project Object Model"
I am trying to open a userform through a custom excel ribbon. When I click the button in the ribbon it begins initializing and on the workbooks.open function it sends the code to the queryclose sub. The show userform code is below:
Sub RemoveFixture_onAction(control As IRibbonControl)
SelectedCompType = Fixture
Set EditComp = New ufUpdateComp
With EditComp
.Top = Application.Top + 125
.Left = Application.Left + 25
.Show
End With
End Sub
When the code begins the userform_Initialize code it ends up moving to the query_close sub. The code for that is below:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
'If wb Is Nothing Then UserForm_Initialize
wb.Close False
End Sub
As seen above, in the commented out section, I tried to return to the initialize sub when the code moved to the queryclose function. It moves to the queryclose sub when it runs the workbooks.open code and it says that the wb is nothing. I have tried opening the workbook separately and then setting the workbook as ActiveWorkbook. I also tried:
do while wb is nothing
set wb = ActiveWorkbook
loop
This loop ran endlessly until I had to manually cancel it.
It was originally set wb = workbooks.open(Test)
Private Sub UserForm_Initialize()
Workbooks.Open Test, , , , , DynoCompPassword, True
Set wb = ActiveWorkbook
Set ws = wb.Worksheets("Info")
Set ws = wb.Worksheets("Info")
Set wsC = wb.Worksheets("Calipers")
Set wsF = wb.Worksheets("Fixtures")
Set wsW = wb.Worksheets("Wheel Sims")
ws.Visible = True
wsC.Visible = True
wsF.Visible = True
btnCreate.Enabled = False
Dim rng As Range
lblLocation.Visible = False
tbLocation.Visible = False
Me.cbOut.AddItem "Sent To"
Me.cbOut.AddItem "Scrapped"
Me.cbOut.AddItem "Returned"
Me.btnCreate.Enabled = True
For Each rngprojectcode In ws.Range("ProjectCode")
Me.cbProjectCode.AddItem rngprojectcode.Value
Next rngprojectcode
Set ProjCodeDictionary = New Dictionary 'Create the dictionary
Dim i As Integer
Dim j As Integer
Dim ProjCodeString As String
Dim AssociatedCodes As ProjectCodeList
If ws Is Nothing Then Exit Sub
ProjCodeDictionary.CompareMode = vbTextCompare 'Make the .exists method case insensitive in an attempt to avoid duplicate values
Set AssociatedCodes = New ProjectCodeList 'create the class module which will split up the associated codes into individual values
i = 1
While ws.Range("F1").Offset(i, 0) <> ""
With AssociatedCodes
.SetCodes = CStr(ws.Range("F1").Offset(i, 0).Value)
For j = 1 To .NumCodes
ProjCodeDictionary.Add .ProjCode(j), i 'key, item
Next j
End With
i = i + 1
Wend
If SelectedCompType = Fixture Then
Me.lblCompNum.Caption = "Fixture ID"
Me.btnCreate.Caption = "Update Fixture"
'Automation Error occurs here
Me.Caption = "Edit Fixture"
Me.frChangeFrame.Height = 65
Me.frChangeFrame.Caption = "Bolt Circle"
Me.cbPartNum.Text = "FIX"
For Each rng In wsF.Range("FixtureNum")
Me.cbPartNum.AddItem rng.Value
Next rng
Set tbNumStuds = frChangeFrame.Controls.Add("Forms.TextBox.1", , "True")
To clarify, the queryclose sub should only be activated when the red box with the X is pressed in the userform. It is a built in function of the userform.
The only time the queryclose sub should run is when the X button is pressed on the userform.
But that's not how QueryClose works. The UserForm.QueryClose event is fired whenever the form is about to be closed, and its parameters give you means to cancel it, depending on what prompted it to close.
What you want is to run wb.Close False conditionally, when the CloseMode parameter value is vbFormControlMenu (the X button - see QueryClose constants):
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
wb.Close False
End If
End Sub
I tried to return to the initialize sub when the code [...]
Don't do this. Event handlers are meant to be invoked by VBA itself, not user code. If you need to invoke logic that you've implemented in an event handler, refactor the code out of the handler and into its own procedure instead:
Private Sub UserForm_Initialize()
DoInitializationStuff
End Sub
Private Sub DoInitializationStuff()
'...
End Sub
Lastly, the UserForm.Initialize event is fired well before the form is shown.
Set EditComp = New ufUpdateComp ' <~ initialize handler runs before this instruction returns
With EditComp
.Top = Application.Top + 125
.Left = Application.Left + 25
.Show
End With
Note that you don't need to declare the local variable if you're only using it in a With block - have the block hold the object reference instead:
With New ufUpdateComp ' <~ initialize handler runs before this instruction returns
.Top = Application.Top + 125
.Left = Application.Left + 25
.Show
End With
If you want DoInitializationStuff to run after the form is shown, invoke it in the Activate event.
I am unsuccessfully trying to adjust code that was created by a previous coworker. Currently we use this code below. It is attached to a button on an excel worksheet, this inserts an image into a specified range of cells, it resizes the image then lands on a cell below to type a description. The problem we are having is our template is now being moved from our server to outside locations. So all of the images are now just broken links. I have attempted several adjustments based on other posts, but none have been successful.
Private Sub Picture1_Click()
' Select Image From File
With Application.FileDialog(msoFileDialogFilePicker)
If .Show Then
PicLocation = .SelectedItems(1)
Else
PicLocation = ""
End If
End With
' Error Check
If PicLocation = "" Then
MsgBox "No picture selected"
Exit Sub
End If
'Initialization
Dim TargetCells As Range
ActiveSheet.Unprotect
Set TargetCells = Range("B9:H24")
' Error check 2
If PicLocation <> "False" Then
Set p = ActiveSheet.Pictures.Insert(PicLocation)
Else
Exit Sub
End If
' Set image dimensions
With p.ShapeRange
.LockAspectRatio = msoTrue
.Height = TargetCells.Height
If .Width > TargetCells.Width Then .Width = TargetCells.Width
End With
' Set image location
With p
.top = TargetCells.top
.Left = TargetCells.Left
.PrintObject = True
End With
' Close out operations
Range("a25").Select
Set p = Nothing
End Sub
I had the same issues when switching versions of Excel a few years ago. My macro now uses .Shapes.addPicture Modified a piece of your code below
If PicLocation <> "False" Then
Set p = ActiveSheet.Shapes.addPicture fileName:=PicLocation, linktofile:=False, savewithdocument:=True
Else
Exit Sub
End If
I am trying to figure out how to change 3 cells on 3 different sheets to the same value as the Command Button Caption. I have managed to get it working if there is only one command but can't seem to get it to work on multiple commands.
Private Sub CmdSME100_Click()
Worksheets("Calculator").Range("I1") = Me.CmdSME100.Caption
Worksheets("Tariff Matrix").Range("A1") = Me.CmdSME100.Caption
Worksheets("Bolt-On Matrix").Range("A1") = Me.CmdSME100.Caption
End Sub
As it stands this is the code i am trying to get to work. and i can't seem to figure out why it wont work on all the different sheets.
I need this to work as the cells that i am asking the code to change then trigger an auto filter.
Any advise will be greatly appreciated.
Thanks
Maybe you can try "activating" the sheets. Considering "Calculator" is Sheet1, "Tariff Matrix" is Sheet2 and "Bolt-On Matrix" is Sheet 3;
Private Sub CmdSME100_Click()
Sheet1.Activate
Sheet1.Range("A1") = Me.CmdSME100.Caption
Sheet2.Activate
Sheet2.Range("A1") = Me.CmdSME100.Caption
Sheet3.Activate
Sheet3.Range("A1") = Me.CmdSME100.Caption
End Sub
Set a sheet variable to access them
Private Sub CmdSME100_Click()
Dim ws As Excel.Worksheet
Set ws = Application.Worksheets(1)
ws.Range("I1") = Me.CmdSME100.Caption
Set ws = Application.Worksheets(2)
ws.Range("A1") = Me.CmdSME100.Caption
Set ws = Application.Worksheets(3)
ws.Range("A1") = Me.CmdSME100.Caption
End Sub
If your worksheets aren't reliably in the same index you can search for them by name.
The code would look something like this.
'Find the worksheet named *BBCOV*
iFoundWorksheet = 0
For iIndex = 1 To Application.ActiveWorkbook.Worksheets.Count
Set ws = Application.Worksheets(iIndex)
If UCase(ws.Name) = "BBCOV-PURGED" Then
iFoundWorksheet = iIndex
Exit For
End If
Next iIndex
If iFoundWorksheet = 0 Then
MsgBox "No worksheet was found with the name BBCOV-PURGED (this is not case sensetive). Aborting."
GoTo Abort
End If
Set ws = Application.Worksheets(iFoundWorksheet)
ws.Activate
I don't think you can grab the caption quite like that.
Try this instead:
ActiveSheet.Buttons(Application.Caller).Caption
So...
Private Sub CmdSME100_Click()
Worksheets("Calculator").Range("I1") = ActiveSheet.Buttons(Application.Caller).Caption
Worksheets("Tariff Matrix").Range("A1") = ActiveSheet.Buttons(Application.Caller).Caption
Worksheets("Bolt-On Matrix").Range("A1") = ActiveSheet.Buttons(Application.Caller).Caption
End Sub