I'm very new to DBA so probably it's a banal mistake but I looked around and I did not found anything that could help me.
I'm trying to populate a combobox dynamically using the content of a column (column "A" in this specific case) using a macro linked to a button. If the analyzed cells are empty everything goes smoothly and the message "done!" appears, but if there is any data in the cells I get the error "424 object required access".
I don't know if it would help: I took the code from this youtube video https://www.youtube.com/watch?v=x8O59GtatH8 and adapted it (just removed the listox) the complete code is at 5.35
I'm probably misunderstanding something very basic. I am guessing the declaration of the combobox.
Sub prova_stessa_scheda()
row_review = 1
Dim TheSheet As Worksheet
Set TheSheet = Sheets("Listino_prezzi")
Do
DoEvents
row_review = row_revieew + 1
item_in_review = TheSheet.Range("A" & row_review)
If Len(item_in_review) > 0 Then ComboProva_Change.AddItem (item_in_review) 'this is the command that gives the error
Loop Until item_in_review = ""
MsgBox "Done!"
End Sub
I expected that when the macro gets triggered the combobox gets filled with the value written in the cells of column "A" instead I got the error 424.
If you put your code into the Worksheet module of the sheet where the combobox is placed, VBA is assuming that you want to access the element CombProva of that sheet (this is what is done in the video, only with different names).
However, if you put your code into a regular module, VBA does not know what CombProva is. You have to tell VBA that you want to access it from a specific sheet. There are several ways to do so:
(1) Use
With ThisWorkbook.Sheets("Listino_prezzi")
.ComboProva.AddItem (item_in_review)
End With
Note that the following code will throw an compiler error. This is because TheSheet is of type Worksheet, so it could be any worksheet, and a worksheet does not have anything named ComboProva.
Dim TheSheet As Worksheet
Set TheSheet = Sheets("Listino_prezzi")
With TheSheet
.ComboProva.AddItem (item_in_review) ' <-- Compiler error
End With
(2) You can access the sheet also by its CodeName. If you look to the video: The sheet itself was renamed to Admin Site, but the CodeName is still Sheet1 (the CodeName can only be changed in the VBA editor in the Property-window). So you can write
With Sheet1
.ComboProva.AddItem (item_in_review)
End With
(3) You can access the combobox by name from the Shapes-collection of the sheet (basically everything that is put on a sheet but not within an cell is a Shape). However, as you are dealing with ActiveX-controls, this is a little bit ugly.
Dim sh as Shape
Set sh = TheSheet.Shapes("ComboProva")
With sh.DrawingObject.Object
Call .AddItem("Variante x")
End With
Related
The code is:
Sub Copy_Filtered_Table()
Dim aSheet As Worksheet
Dim i As Long
i = ActiveSheet.Index
ActiveSheet.AutoFilter.Range.Copy
-> Set aSheet = ActiveWorkbook.Worksheets.Add(After:=i)
aSheet.Range("A1").PasteSpecial
End Sub
The workbook format is .xlsm Excel 2016
it has sheets after and before the active sheet
Also I Have tried doing it with out the aSheet variable like this
ActiveWorkbook.Worksheets.Add After:=i
It did not work too. both cases gives error 1004 Method 'Add' of object 'Sheet' faild.
If I ommited the After parameter it works but putting the result new sheet before the active sheet which exactly I am avoiding.
In order to insert relative to an existing sheet, you need to provide the actual sheet rather than its index, using one of:
Set aSheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(i))
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Worksheets(i)
Which one you choose depends on whether you immediately want to do something with the sheet without searching for it again but I suspect you already know that, given your question.
As an aside (though I haven't tried), I suspect getting the index of the current sheets then turning that back into the current sheet object is a bit unnecessary. You may want to just try:
Set aSheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.ActiveSheet)
I have written a function called GenerateCSV which writes data to a csv file. This function is stored in a Module ("Module 1").
I am sharing the code below for completeness, but I think its not necessary for my question.
Option Explicit
Sub GenerateCSV(ExcelStartRange As String, OutputFileName As String)
'Variable declaration
Dim Data As Variant
Dim MaxRow As Integer
Dim MaxColumn As Integer
Dim Row As Integer
Dim Column As Integer
Open OutputFileName For Output As #1
MaxRow = 2
MaxColumn = 722
For Row = 1 To MaxRow
For Column = 1 To MaxColumn
Data = Range(ExcelStartRange).Offset(Row - 1, Column - 1).Value
If Column < MaxColumn Then
Write #1, Data,
Else
Write #1, Data
End If
Next
Application.StatusBar = "Row = " & Row
Next
Close #1
End Sub
I have also written a Macro in the worksheet "OutputCFs" which calls GenerateCSV:
Private Sub CommandButton1_Click()
Call GenerateCSV(Range("StartRange1"), Range("OutputFileName1"))
Call GenerateCSV(Range("StartRange3"), Range("OutputFileName3"))
End Sub
When I press the macro button in "OutputCFs", it works fine. However, when I move/copy-paste the macro button to a different worksheet (say, "Guide"), it doesnt work anymore.
What should I add to my code in order for the Macro-button to also work in the "Guide" worksheet.
Thank you.
The issue …
… is that in
GenerateCSV(Range("StartRange1"), Range("OutputFileName1"))
you did not precisely specify in which worksheet your ranges are. So Excel starts guessing which worksheet you meant and it gets it wrong sometimes. So depending on which is the active sheet or where exactly this code is written Excel's guessing procedure changes, and this is messing it up.
Solution
For all Range, Cells, Columns, Rows objects (and other objects that are located in a worksheet) always specify explicitly in which workbook and worksheet they are, to prevent Excel guessing and making assumptions.
GenerateCSV ThisWorkbook.Worksheets("OutputCFs").Range("StartRange1"), ThisWorkbook.Worksheets("OutputCFs").Range("OutputFileName1")
This is reliable and will ensure that it always works with this specific workbook ThisWorkbook with this specifc worksheet Worksheets("OutputCFs") in it. Now there is no room for Excel guessing or making assumptions. Excel has a very clear statement and it will follow it. The more precise you are in your code, the more precise Excel will follow.
Highly recommended to always do that for all your objects located in worksheets otherwise you never know when it might start failing.
If you have more code go and check it immediately and specify all workbooks properly.
Recommendation
If you need some support in this and writing clean and solid code have a look at the Rubberduck AddIn for VBA. It can automatically warn you if you have ranges without having specified a worksheet. It would tell you
Member 'Range' implicitly references 'ActiveSheet'.
in its Code Inspector. Also Rubberduck comes with a lot of other useful stuff.
One problem is that GenerateCSV() is expecting a String as an input and your button code is giving it a Range() Object as an input.
EDIT#1:
This can lead to problems. For example if Range("StartRange1") has the value A1, then the button code will assume that this means A1 on the same sheet the the button is on.
I'm working on a spreadsheet that breaks out the tasks in a given department. Each task is then assigned to a person in that department using a data validation drop down that dynamically fetches values from the tables that list each employee/role in the department. The tables are on a different sheet than the task breakdown.
Each individual needs their own background color that automatically fills in when their name is selected from the drop down on the tasks sheet. What I'm hoping to do is write a macro that looks for that person's name in the table (note that I'm using named ranges) and then matches the formatting of the selected cell to their row in the table. I'm a super beginner with VBA and have hit the end of my abilities. Several answers that come close to what I want to do, but in terms of adapting it for my specific use case, I'm stuck.
I grabbed code from this thread, which is essentially the result I want to achieve, except that their key is on the same sheet and mine can't be: https://superuser.com/questions/472918/excel-conditionally-format-a-cell-using-the-format-of-another-content-matching
So far, I've compiled this:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If VarType(Target) > vbArray Then Exit Sub
' if multiple cells are changed at once, then exit
Dim kr1 As Range
Dim kr2 As Range
Dim KeyRange As Range
Dim TargetRange As Range
Dim lCell As Object
Dim kCell As Object
Set kr1 = Application.Range("ESFormattingRange")
Set kr2 = Application.Range("CSFormattingRange")
Set KeyRange = Application.Union(Range("kr1"), Range("kr2"))
' formatting key is here
Set TargetRange = ThisWorkbook.Worksheet("Sheet3").Range("A:X")
' changing cells in this area
For Each kCell In KeyRange.Cells
If kCell.Value <> "" Then
For Each lCell In TargetRange.Cells
If lCell.Value = kCell.Value Then
' only change cells that match the edited cell
lCell.Font.Color = kCell.Font.Color
lCell.Interior.Color = kCell.Interior.Color
' copy whatever you feel needs to be copied
End If
Next
End If
Next
End Sub
When I run this, I get the following method error, but no lines are highlighted when I try to debug:
Compile error:
Method or data member not found
I'm thinking maybe there's something wrong with the way I've constructed my range variables, but I've googled everything I can think of and I'm at a loss.
Any help is greatly appreciated!
The VBE should be highlighting the word Worksheet in ThisWorkbook.Worksheet("Sheet3").Range("A:X").
"Method or data member not found" means Worksheet isn't a member of ThisWorkbook.
You can fix this by pressing CTRL+SPACE to autocomplete the member name to Worksheets.
Alternatively, you can re-type the . dereferencing operator after ThisWorkbook, and press TAB when the names list dropdown is shown, highlighting the Worksheets member - that will also autocomplete the member name to Worksheets.
Rule of thumb, if you type a . dereferencing operator and then type something that isn't in the names list, you can expect this compile error.
When you make this typo against a Variant or Object variable, the code will happily compile, but error 438 will be thrown at run-time - like this:
ThisWorkbook.Worksheets("Sheet3").Ragne("A:X") ' <~ typo compiles. Option Explicit can't save you.
The reason is that Worksheets returns an Object reference, so any member calls chained to it are resolved at run-time. A safer way to code is to declare a local Worksheet variable to hold this object, and then work with that object instead:
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("Sheet3")
sourceSheet.Rnage("A:X") ' <~ typo throws at compile-time now!
If the worksheet object exists in ThisWorkbook at compile-time however, then it's probably a better idea to work with its code name instead. Locate Sheet3 in the Project Explorer (CTRL+R), then find its (Name) property - change it to e.g. SourceSheet. And then you can do this:
SourceSheet.Range("A:X") ' <~ a typo wouldn't compile here.
...without needing to explicitly declare a SourceSheet.
I have a spreadsheet that is used to log information. In one sheet you enter the data then VBA updates a second sheet where the info is stored.
I want to write a code that will check if a cell on the last row of the log (which will be changing as it updates each time) equals a cell on the input page.
The aim is to stop someone updating the log twice, I already have an alert that it has been updated but want to put a foolproof system in place to stop an entry being logged twice.
I am new to VBA so do not really know where to start.
The below is an example of achieving this. I have added comments to explain what is happening in the VBA.
In Excel, press Alt+F11
In the project window on the left, expand it if its not already and
double click on 'ThisWorkbook'
If it is not already there, type Option Explicit as the first
thing in the main window. This means the code will not run unless
all variables that are used are declared, this is good practice
Past the below code into the window
With the cursor in the code you can press F8 to run it line by line
to see what is happening or F5 to run it in one go.
You will want to adjust it to your required workbooks, worksheets, and cells/columns.
Public Sub Sample()
'Clearly declare variables, in the case we are using them
'to reference a workbook and a worksheet
Dim WkBk As Workbook
Dim WkSht As Worksheet
'Set the WkBk variable (which was declared as a workbook,
'which means it can only be used for workbook objects.
'I this instance we are refering to ThisWorkbook,
'which is as it sounds.
Set WkBk = ThisWorkbook
'We can now make a reference to a specific worksheet
'within our referenced workbook
Set WkSht = WkBk.Worksheets("Sheet2")
'This IF statement is comparing the value of cell
'A1 on Sheet1 to the the value of the last populated cell
'in column A of Sheet2 (the sheet we created a reference to)
If WkBk.Worksheets("Sheet1").Range("A1") = WkSht.Range("A" & WkSht.Rows.Count).End(xlUp) Then
MsgBox "It was a match"
End If
Set WkSht = Nothing
Set WkBk = Nothing
End Sub
I'm a very new, self-taught programmer, so please keep this in mind in your responses. I have extensively searched this and other forums and can't seem to find a similar question.
The following code has been working for weeks and has not been changed. (My macro includes more variables and code, but I know from taking it apart that those pieces work, so I've left them out for clarity). From what I can tell the PasteSpecial function is specifically not working.
Dim StimSheet As String
ActiveCell.Rows("1:290").EntireRow.Select
Selection.Copy
'Copies the data for the current stimulus
StimSheet = Application.InputBox("Enter the name of the stimulus")
'asks name of the stimulus
Sheets.Add After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = StimSheet
'adds new sheet at the end and names whatever you input as stimulus name
Sheets(StimSheet).Select
Selection.PasteSpecial Paste:=xlPasteValues
'pastes data into new sheet
At this point there is no error, the macro simply stops after copying and creating the new sheet.
Here's what I know / have tried:
The macro is successfully making and naming the new sheet and copying the selection to the clipboard, because I can manually paste it after running the macro. It seems to be getting stuck at the paste piece.
Other macros that use the exact same format of copy / paste special are still working correctly.
Another forum with a similar program suggested typing "Application.EnableEvents=True" into the immediate window. This did not change anything.
This macro has worked for several weeks with no errors. I have made new macros using previously saved code in case something inadvertently was changed in the current one, but this did not work either.
The paste option will work one time on a new file and then ceases to work again.
Thank you in advance for your suggestions.
You might find the problem is that you don't have much control over which workbook and worksheet this code applies to. It's better to avoid ActiveSheet, Select, and Sheet with no parent as much as you can.
If you only need to copy the values of cells without any formatting, then Paste isn't needed either.
Try changing your code to the following and see if you have any better luck:
Const BOOK_NAME As String = "Book1.xlsm" 'change this to your workbook name
Const SOURCE_SHEET_NAME As String = "Sheet1" 'change this to your sheet name
Dim wb As Workbook
Dim sourceSheet As Worksheet
Dim newSheet As Worksheet
Dim newSheetName As String
Dim validName As Boolean
Dim rng As Range
' Set the book, sheet and range objects
Set wb = Workbooks(BOOK_NAME)
Set sourceSheet = wb.Worksheets(SOURCE_SHEET_NAME)
Set newSheet = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
' Acquire the new sheet name and check it's valid.
Do
newSheetName = InputBox("Enter the name of the stimulus")
On Error Resume Next
newSheet.Name = newSheetName
validName = (Err.Number = 0)
On Error GoTo 0
If Not validName Then MsgBox "Sheet name isn't valid. Try again."
Loop Until validName
' Write the values into the new sheet
Set rng = sourceSheet.Cells(1, 1).Resize(290, sourceSheet.UsedRange.Columns.Count)
newSheet.Range(rng.Address).value = rng.Value2
I moved this line:
StimSheet = Application.InputBox("Enter the name of the stimulus")
to the top of the method and it seems to work reliably. I wish I could tell you exactly why, but at least you can proceed. Perhaps it has something to do with the focus changing.
Also, when it failed for me (Office 2013) I got the following error:
Run-time error 1004:
Application-defined or object-defined error.
When the Sub was in a Sheet code behind, and this:
Run-time error '1004'
PasteSpecial method of Range class failed.
When pasted in a Module.