What is wrong with the following VBA Code related to range selection? - vba

Set dr = Range(Selection, Cells(Rows.Count, Selection.Column).End(xlUp)(xlToRight))
Basically, I want to select a whole range spanning across numerous rows and columns with data being populated interspersed
It works perfectly upto Xlup. But when I add Xltoright, it doesn't take effect.
enter image description here

If you are trying to go right and down of current selection then consider the following code.
As you later attempt to select in sheet 1 I am going to assume you actually meant Worksheet("Sheet1").
If that is the case you can more safely do the following:
Sub hi()
Dim dr As Range
With ThisWorkbook.Worksheets("Sheet1")
Set dr = .Range(Selection, .Cells(.Rows.Count, Selection.Column).End(xlUp).End(xlToRight))
End With
Debug.Print dr.Address
End Sub
Note:
Bear in mind that Cells /Range without a qualifying Worksheet will use the Activesheet. See the excellent discussion here:
Is the . in .Range necessary when defined by .Cells?.
Synopsis:
With "." is faster, avoids potential for error 1004 and is generally considered best practice.

Related

Difficulties with copying text from one word range to another - returns error code "This command is not available"

I am trying to copy contents from a specific range in a Word table, to another range within the same table. I am aware this code is quite messy/simple, but i am currently just trying to get it to work and mapping the different ranges. The current copy/paste method worked well until i added the last range, where it returns "Run-time error '4605'
This command is not available.".
My first attempt was using selection.copy/paste, but that seems to be less efficient (and returned a similar, if not the same, error). I have tried using Rng=Rng2.text, however that somehow only transfers part of the range.
When i round the code in debug step-by-step it works - so it seems like the code is running too fast for the clipboard to follow along or something like that? I suppose i have to use a different method, but currently i am out of ideas (not very experienced with working with ranges in Word) - any ideas?
Note that some of the ranges share cells, which may complicate things. Also, this is my first post on here, so i apologize in advance if it may be a bit messy.
The code:
Sub test()
Set Rng = ActiveDocument.Range(start:=ActiveDocument.Tables(4).Cell(23, 3).Range.start, End:=ActiveDocument.Tables(4).Cell(26, 4).Range.End)
Rng.Copy
Set Rng2 = ActiveDocument.Range(start:=ActiveDocument.Tables(4).Cell(23, 2).Range.start, End:=ActiveDocument.Tables(4).Cell(26, 3).Range.End)
Rng2.Paste
Set Rng = ActiveDocument.Range(start:=ActiveDocument.Tables(4).Cell(22, 4).Range.start, End:=ActiveDocument.Tables(4).Cell(22, 5).Range.End)
Rng.Copy
Set Rng2 = ActiveDocument.Range(start:=ActiveDocument.Tables(4).Cell(22, 3).Range.start, End:=ActiveDocument.Tables(4).Cell(22, 4).Range.End)
Rng2.Paste
Set Rng = ActiveDocument.Range(start:=ActiveDocument.Tables(4).Cell(23, 6).Range.start, End:=ActiveDocument.Tables(4).Cell(26, 6).Range.End)
Rng.Copy
Set Rng2 = ActiveDocument.Range(start:=ActiveDocument.Tables(4).Cell(23, 4).Range.start, End:=ActiveDocument.Tables(4).Cell(26, 5).Range.End)
Rng2.Paste
End sub

VBA Runtime Error 1004 “Application-defined or Object-defined error” when setting Range in macro

I'm going to preface this by saying that I am very new to VBA and this is my first project with it however, I'm trying quite hard because otherwise it is manual copy paste ~200 times.
Unfortunately, for a first project it has been difficult.
EDITED FOR CLARITY (HOPEFULLY): The main idea is that I need to start at the beginning of a drop down list, copy the first string listed, then paste that string down the column. This changes the numerical data adjacent to the right. I then want to select this newly changed numerical data and copy and paste it to a different sheet in the same workbook in the first blank space in column F. I then want the code to iterate through the drop down list and do this for all 51 strings in the drop down. However it needs to paste offset by 3 columns for each iteration to copy the data to the correct column in the other sheet.
Here is my code thus far
Option Explicit
Sub PtComp()
'
' PtComp Macro
'
'
Dim List1 As String
Dim Range1 As Range
Dim Line1 As Range
Dim i As Integer
Dim Begin As Range
ActiveWorkbook.Sheets("Sample Data Summary").Activate
List1 = Selection
Set Range1 = Evaluate(ActiveSheet.Range(List1).Validation.Formula1)
For Each Line1 In Range1
Selection.Copy
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
ActiveSheet.Paste
ActiveCell.Offset(0, 1).Select
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
ActiveSheet.Selection.Copy
ActiveWorkbook.Sheets("Pt Comparison").Activate
Begin = ActiveSheet.Range("F1").End(xlDown).Offset(-1, 0)
For i = 0 To 148 Step 3
Begin.Offset(0, i).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues
Next i
Next Line1
End Sub
It is highlighting this line
Set Range1 = Evaluate(ActiveSheet.Range(List1).Validation.Formula1)
Any help would be greatly appreciated. Sorry if my code is trash, like I said, first timer hoping to get better.
EDIT: Also, I looked back at older questions with the same error and thought that it was maybe because it wasn't clear what worksheet I was trying to define the range in, hence why my code is full of 'ActiveSheet' but still no luck.
Your code assumes List1 contains a valid range address, and thus that the active cell on that "Sample Data Summary" worksheet, contains a valid range address.
Apparently that isn't always the case. Search for more details on the On Error statement for ideas about how you could go about handling that situation.
You need to read up on How to avoid using Select in Excel VBA macros, and know that clipboard operations in a tight loop is pretty much the single slowest thing you can do in Excel-VBA.
Seems you want something like this:
Set Range1 = Evaluate(Selection.Validation.Formula1)
Your code blows up on Range(List1) because List1 does not contain a valid range address.

Condense largely(Unpractical) loop based VBA code; nested For...Next loops

Hello everyone alright let start by giving some brief background on my project then I will follow up with my specific issue and code.
Currently I am building a program to automate the process of filling a template. This template exceeds 60,000 rows of data quite often and I've built the large majority of it to work month to month by plugging in new data sheets and running it. Currently all of the work is based off of one data sheet which I import into excel manually. This data sheet does not contain all the data I need to populate the template so now I am beginning to bring in additional data to supplement this. The problem herein lies with data association. When I was originally pulling from one data sheet I didn't have to worry if the data I pulled for each row coincided with the other rows because it all came from the same sheet. Now I have to cross check data across two sheets to confirm it is pulling the correct information.
Now for what you need to know. I am trying to fill a column that will be referred to as Haircut, but before I do that I need to confirm that I am pulling the correct haircut number in correlation to a Trade ID which was already populated into the template in a previous line of code.
Using similar logic that I have been using throughout my entire project this is a snippet of code I have to perform this task.
Dim anvil as Worksheet
Dim ALLCs as worksheet
Dim DS as worksheet
'''''''''''''''''''''''''''''code above this line is irrelevant to answer this question
ElseIf InStr(1, DS.Cells(x, 2), "Haircut") Then
Anvil.Select
For y = 1 To 80
If Anvil.Cells(1, y) = "Haircut" Then
For Z = 1 To 80
If Anvil.Cells(1, Z) = "Trade ID" Then
For t = 2 To 70000
For u = 16 To 70000
If Anvil.Cells(t, Z) = ALLCs.Cells(u, 34) Then
ALLCs.Cells(u, 27) = Anvil.Cells(t, y)
End If
Next
Next
End If
Next
End If
Next
This code coupled with my other code I assume will in theory work, but I can only imagine that it will take an unbelievable amount of time(this program already takes 7 and a half minutes to run). Any suggestions on how to rewrite this code with better functionality, following this general logic?
Any help is appreciated, whether you completely revamp the code, or if you offer suggestions on how to cut down loops. I am also looking for suggestions to speed up the code in general aside from screen updating and calculation suggestions.
If I understand the logic correctly then you can replace all but one of the loops with a .Find() method like so:
'// Dimension range objects for use
Dim hdHaricut As Excel.Range
Dim hdTradeID As Excel.Range
Dim foundRng As Excel.Range
With Anvil
With .Range("A1:A80") '// Range containing headers
'// Find the cell within the above range that contains a certain string, if it exists set the Range variable to be that cell.
Set hdHaircut = .Find(What:="Haircut", LookAt:=xlWhole)
Set hdTradeID = .Find(What:="Trade ID", LookAt:=xlWhole)
End With
'// Only if BOTH of the above range objects were found, will the following block be executed.
If Not hdHaricut Is Nothing And Not hdTradeID Is Nothing Then
For t = 2 To 70000
'// Using the .Column property of the hdTradeID range, we can see if the value of Cells(t, hdTradeColumn) exists
'// in the other sheet by using another .Find() method.
Set foundRng = ALLCs.Range(ALLCs.Cells(16, 34), ALLCs.Cells(70000, 34)).Find(What:=.Cells(t, hdTradeID.Column).Value, LookAt:=xlWhole)
'// If it exists, then pass that value to another cell on the same row
If Not foundRng Is Nothing Then ALLCs.Cells(foundRng.Row, 27).Value = .Cells(t, hdHaircut.Column).Value
'// Clear the foundRng variable from memory to ensure it isn't mistaken for a match in the next iteration.
Set foundRng = Nothing
Next
End If
End With

Clearing cells in excel and 6 checkboxes

I have a button in Excel with a VBA script attached to it to clear certain cells on a sheet.
Is there a cleaner code to achieve the same result?
Also for my checkboxes for some reason 1 piece of code clears all 6 boxes, is this right?
The checkboxes are activeX boxes I added through the developer view.
Sub ClearForm()
Range("I9:I10").Select
Selection.ClearContents
Range("I13:I17").Select
Selection.ClearContents
Range("H20").Select
Selection.ClearContents
Range("C5").Select
Selection.ClearContents
Range("C9:C10").Select
Selection.ClearContents
Range("C13:C18").Select
Selection.ClearContents
Dim OleObj As OLEObject
For Each OleObj In ActiveSheet.OLEObjects
If OleObj.progID = "Forms.CheckBox.1" Then
OleObj.Object = False
End If
Next OleObj
End Sub
Well for one thing you can have a string of ranges and do it all at once.
Range("I9:I10, I13:I17, H20, C5, C9:C10, C13:C18").Select
Selection.ClearContents
as for your check-boxen, if by "clear" you mean "Removes" or "Deletes" then yes it makes sense, if on the other hand all you want to do is clear a checkbox then I think this is what you need in the loop:
OleObj.Object.Value = False
To answer your first question:
Range.Select is unecessary and actually slows execution down a bit. You can directly call .ClearContents on the range object itself. I imagine you did the Range.Select bit because of macro recorder. Whilst a useful tool to learn about Excel object model, also bear in mind that it does churn out some ugly bits ;-)
As you are performing the same set of commands several times, it is also generally better practice to encapsulate the steps into their own sub to a) have a neater 'main' procedure and b) easily enable to you adapt the process, should you later wish it.
However, this second point is definitely optional if this is a minor and unlikely to change part of your code, as the actual 'step' is just a single call to Range.ClearContents. Indeed, if it is literally intended to only clear 5 cells, I would probably just keep it like you do in the sub. I show the alternative below just for reference for more complex bits in the future.
Finally, if the group of ranges you wish to clear or do things to could change, it is also considered good practice to define a set of the ranges and enumerate the set (aka "looping through") rather than specifying identical commands for each range itself. Most objects will be handled through a Collection or an array. However for ranges, a range can contain many ranges of contiguous and non-contiguous cells. Each group of contiguous cells is referenced by using the .Areas property of the range object, which returns a range of the area. I also demonstrate this below.
Note that as another answerer has shown, Range.ClearContents can operate on multiple Areas at once so looping through Areas is not necessary in this case (it is for many other operations).
For example:
Sub ClearForm()
Dim rng As Range
For Each rng in Range("I9:I10,I13:I17,...etc...").Areas
clearRange rng
Next rng
...Rest of code...
End Sub
Private Sub clearRange(rng As Range)
rng.ClearContents
End Sub
With respect to your second question: the 6 checkboxes are cleared because you loop through all activex objects on the sheet in the last part of your code and set their Value property to False, which for a checkbox unchecks it.

VBA help in selecting entire rows on a dynamic range

Hi thanks everyone in advance.
I have a data set. lets say A3 to Z30. the number of rows and columns varies. also there are blanks in the set. So lets say i want to select the entire section but there's a blank in Z29 and X30 using
Range("A3").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
isn't going to work.
But the values in column A is continuous. So i think the first part will work
Range("A3").Select
Range(Selection, Selection.End(xlDown)).Select
now i know this may seem elementry but how the heck do i select all the rows i just highlighted? this needs to be dynamic because as i said the number of columns and rows vary.
Oh and bonus karma and kudos if you can help me to figure out the next part. I need to select the range and paste it immediately after the the last row but the value in the first cell or A31 in this case would need to change and that is being pulled from a list in sheet2
Use the .EntireRow method.
Here is an example:
Dim report as Worksheet
Set report = Excel.ActiveSheet
report.cells(1,1).EntireRow.Select
If you want to select the cells themselves, you can use the .UsedRange method.
Here is an example:
Dim report As Worksheet
Set report = Excel.ActiveSheet
report.Range(report.Cells(1, 1), report.Cells(1, report.UsedRange.Columns.Count)).Select
EDIT
Here is an example for part II of your question (as requested):
Sub test2()
Dim report As Worksheet
Set report = Excel.ActiveSheet
report.Cells(1, 1).EntireRow.Copy
report.Cells(report.UsedRange.Rows.Count + 1, 1).EntireRow.PasteSpecial xlPasteAll
End Sub
Be sure to note that the .UsedRange method also includes cells that have no values but have been formatted by the user; e.g., if you add bold font (even if you don't add the text itself) to a cell in row 1000, your .UsedRange.Rows.Count will be 1000.
Additionally, you can check my answer in the following link for more guidance. I've been told the notes are very helpful for beginners:
Excel Macro - Paste only non empty cells from one sheet to another (Stack Overflow)
You might want to look at this, and consider what you could do with Range.CurrentRegion, Range.Resize and Range.Offset, so you might get:
Range("A3").CurrentRegion.Copy
Additionally, there's no need to use Range.Select unless you want a user to see what is happening; instead of (for example) a Range.Select followed by a Selection.Copy() (which copies to the clipboard), you could just use a Range.Copy(Range), which copies direct to the target range.
As to the second part, you could:
Dim CopyRow as Long
CopyRow = Range("A3").CurrentRegion.Rows.Count
Range("A3").CurrentRegion.Copy(Range("A3").CurrentRegion.Offset(CopyRow))
Range("A3").Offset(CopyRow) = x ' Insert your reference to the Sheet 2 value here
I am aware that this thread is old, however I was looking for help with something similar. I knew my starting cell for my range, but the number of rows and columns were going to be dynamic. Using the following code worked for me:
Range("A2").Select
Range(Selection, Selection.End(xlDown).End(xlToRight)).Select
Hopefully anyone in the future can make use of this simple solution.