Deselect Subrange - vba

I want to lock the range A4:B9 in my sheet. Now as it looks like the only way to accomplish that is to set the Lock=false status to all cells I do not want to be locked and then protect the whole file.
My problem is, that I have just a little range that has to be protected, so I need to find a way to create a range with all cells but e.g. A4:B9. I know intersect and union but cannot come up with an idea to apply them to get my goal accomplished.

I wrote this that works for me:
Sub deselect_subranges()
Dim cell As Range
Dim rngAll As Range
Dim rngMy As Range
Dim rngNew As Range
Set rngAll = ThisWorkbook.Worksheets(1).Range("A1:AZ400")
Set rngMy = ThisWorkbook.Worksheets(1).Range("C3:E8")
Set rngNew = Nothing
For Each cell In rngAll
If Intersect(cell, rngMy) Is Nothing Then
If rngNew Is Nothing Then
Set rngNew = cell
Else
Set rngNew = Union(rngNew, cell)
End If
End If
Next cell
rngNew.Select
End Sub

Related

Open random URL from a range

I would need to open a random selected link from a cell to a website in my list. My internet links are put in column B, but I cannot get it to open the hyperlink after it has selected a cell from my list.
Sub Test()
Dim Sh As Worksheet
Dim Rng As Range
Dim Cell As Range
Set Sh = Worksheets("Sheet1")
With Sh
Set Rng = .Range("C1:C" & .Cells(.Rows.Count, "C").End(xlUp).Row)
End With
For Each Cell In Rng
ThisWorkbook.FollowHyperlink Cell.Value
Next Cell
End Sub
Just to be sure I got it right:
The addresses are stored in column B (in your code you're using column C)
You don't want to open all of the addresses, but only one random one?
The addresses are full URLs? (Like "https://stackoverflow.com/")
I tidied up your code a little bit. Read the comments, to understand what is happening.
Sub Test()
Dim Sh As Worksheet
Dim Rng As Range
Dim Cell As Range
Set Sh = Worksheets(1)
' Get a Range object of all possible addresses
Set Rng = Intersect(Sh.UsedRange, Sh.Range("B:B"))
' Open one random element of them
ThisWorkbook.FollowHyperlink Rng(Int(Rnd * Rng.Count) + 1)
End Sub

How can I copy a range of cells based on a Header to paste to another worksheet and match the headers?

I need a code to copy a range of cells (H21:H38) from my source worksheet (Acct Total) to a corresponding column on my target worksheet (COS% Tracking) based on matching headers. But the hiccup I have is that the header is in cell A6 on my source worksheet (Acct Total). I've researched it a bit and I've found this code that worked for someone else:
Sub CopyHeaders()
Dim header As Range, headers As Range
Set headers = Worksheets("ws1").Range("A1:Z1")
For Each header In headers
If GetHeaderColumn(header.Value) > 0 Then
Range(header.Offset(1, 0), header.End(xlDown)).Copy Destination:=Worksheets("ws2").Cells(2, GetHeaderColumn(header.Value))
End If
Next
End Sub
Function GetHeaderColumn(header As String) As Integer
Dim headers As Range
Set headers = Worksheets("ws2").Range("A1:Z1")
GetHeaderColumn = IIf(IsNumeric(Application.Match(header, headers, 0)), Application.Match(header, headers, 0), 0)
End Function
So my issue is that I don't know where to begin to edit this code to work like I need. This code worked by using the header above the range of cells but that won't do in my case. I'll attach pictures so that hopefully I'm not too vague.
Can someone help me to edit this code according to my needs?
Edit: Additional Picture for the source of the dates.
GL Code Tab
Look at the following construct as a starting point for a different way to solve the same problem. There are descriptive variables so you have an idea of what is happening.
Edit: As the target sheet row 3 is locked, code has been amended to use Match function to return column number where string is found (if found).
Essentially:
Set your source and target worksheets.
Set sourceWorksheet = wb.Sheets("Acct Total")
Set targetWorksheet = wb.Sheets("COS% Tracking")
Define your target value (the date you are trying to match on) and source range
targetDate = Trim$(sourceWorksheet.Range("A6"))
Set sourceRange = sourceWorksheet.Range("H21:H38")
Find the column number of where value (targetDate) is present in the target sheet
colNum = Application.WorksheetFunction.Match(targetDate, searchRange, 0)
Add error handling in case it is not present i.e. if date (as string) is not found....
ErrHand: 'code in this section.....
Set the address of where the target data will be pasted
Set targetRange = .Range(Cells(4, colNum), Cells(21, colNum))
Set the target range to be equal to the source range.
targetRange.Value = sourceRange.Value
Adapt as appropriate.
Putting it together you getting something along the lines of the following:
Option Explicit
Public Sub copydata()
Dim sourceRange As Range
Dim targetDate As String
Dim targetRange As Range
Dim wb As Workbook
Dim sourceWorksheet As Worksheet
Dim targetWorksheet As Worksheet
Dim searchRange As Range
Set wb = ThisWorkbook
Set sourceWorksheet = wb.Sheets("Acct Total")
Set targetWorksheet = wb.Sheets("COS% Tracking")
targetDate = Trim$(sourceWorksheet.Range("A6"))
Set sourceRange = sourceWorksheet.Range("H21:H38")
Set searchRange = targetWorksheet.Rows(3)
On Error GoTo ErrHand
Dim colNum As Long
colNum = Application.WorksheetFunction.Match(targetDate, searchRange, 0)
With targetWorksheet
Set targetRange = .Range(Cells(4, colNum), Cells(21, colNum))
targetRange.Value = sourceRange.Value
End With
ErrHand:
If Err = 1004 Then
MsgBox "Not found: " & targetDate
Err.Clear
Exit Sub
End If
End Sub
See the following:
Finding address of text in worksheet
Moving data between sheets

Populating ComboBox with dynamic values from another worksheet

---Update---
Thanks for the responses, I have found that DragonSamu's updated answer works perfectly.
---Original Post---
I have been trying to figure out where I am going wrong for the past few hours but I can't spot it. I think it's because the script is trying to draw the value from the active worksheet which is not what I want. Hopefully somebody can put me on the rite track - I think the answer should be relatively obvious but I just can't see it!
Basically, I am trying to populate a Combobox with a dynamic range of values that exist in another worksheet (but in the same workbook). I can get the Combobox to populate when I run the script in the worksheet 'Materials' (which is where the dynamic list is drawn from) but not when I run it in the worksheet 'Products'.
Unfortunately the script is designed to populate Products with Materials so is be run in a UserForm when the 'Products' worksheet is open and the 'Materials' worksheet would therefore be inactive.
I should also note that this script has been adapted from code I found elsewhere on this forum, so if it seems familiar I thank you in advance :)
Private Sub UserForm_Initialize()
Dim rRange As Range
On Error GoTo ErrorHandle
'We set our range = the cell B7 in Materials
Set rRange = Worksheets("Materials").Range("B7")
'Check if the cell is empty
If Len(rRange.Formula) = 0 Then
MsgBox "The list is empty"
GoTo BeforeExit
End If
'Finds the next empty row and expands rRange
If Len(rRange.Offset(1, 0).Formula) > 0 Then
Set rRange = Range(rRange, rRange.End(xlDown))
End If
'The range's address is our rowsource
Mat1_Name_ComBox.RowSource = rRange.Address
Mat2_Name_ComBox.RowSource = rRange.Address
Mat3_Name_ComBox.RowSource = rRange.Address
Mat4_Name_ComBox.RowSource = rRange.Address
Mat5_Name_ComBox.RowSource = rRange.Address
BeforeExit:
Set rRange = Nothing
Exit Sub
ErrorHandle:
MsgBox Err.Description
Resume BeforeExit
End Sub
Any help is much appreciated.
Cheers,
Simon
From what I can see your code would be giving an error here:
If Len(rRange.Offset(1, 0).Formula) > 0 Then
Set rRange = Range(rRange, rRange.End(xlDown))
End If
Because your trying to set rRange by using Range() without defining the Worksheet first. This will get the Range from the ActiveWorksheet.
change it to the following:
If Len(rRange.Offset(1, 0).Formula) > 0 Then
Set rRange = Worksheets("Materials").Range(rRange, rRange.End(xlDown))
End If
best practice would be the following:
Private Sub UserForm_Initialize()
Dim wb as Workbook
Dim sh as Worksheet
Dim rRange As Range
On Error GoTo ErrorHandle
'Set the Workbook and Worksheet
set wb = Workbooks("products.xlsx")
set sh = wb.Worksheets("Materials")
'We set our range = the cell B7 in Materials
Set rRange = sh.Range("B7")
'Check if the cell is empty
If Len(rRange.Formula) = 0 Then
MsgBox "The list is empty"
GoTo BeforeExit
End If
'Finds the next empty row and expands rRange
If Len(rRange.Offset(1, 0).Formula) > 0 Then
Set rRange = sh.Range(rRange, rRange.End(xlDown))
End If
By properly defining and setting your Workbook and Worksheet you correctly reference to them and don't get errors.
Update:
the 2nd problem is that rRange.Address only places the Range location inside your .RowSource not the Sheet it needs to look at.
change:
Mat1_Name_ComBox.RowSource = rRange.Address
to:
dim strSheet as String
strSheet = "Materials"
Mat1_Name_ComBox.RowSource = strSheet + "!" + rRange.Address
This way it will include the Sheet name into the .RowSource

Error on Union when looping through multiple worksheets

I'm trying to delete rows in one sheet that match criteria from rows taken from multiple other worksheets. I need to cycle through all the other worksheets in my workbook, and each time I find something that matches, I delete the entire row in the first sheet. I'm getting Error 1004 on Union. I thought this might be caused because you can't use Union across sheets, so I set it to Nothing after each sheet. I'm still getting the same error.
Here's the code:
Sub findRemaining()
Dim rngToDel As Range
Dim fRng As Range 'Fund range
Dim wCell As Range 'Working sheet cell
Dim wRng As Range 'Working sheet range
Dim WS_Count As Integer
Dim I As Integer
Set fRng = Worksheets("All").Range("B2:B1495")
WS_Count = ActiveWorkbook.Worksheets.Count
For I = 2 To WS_Count
Set rngToDel = Nothing
Set wRng = Worksheets(I).Range("B2:B200")
For Each wCell In wRng 'Loop through all working cells
' if wCell found in Fund range then delete row
If Not IsError(Application.Match(Trim(wCell.Value), fRng, 0)) Then
If rngToDel Is Nothing Then
Set rngToDel = wCell
Else
Set rngToDel = Union(rngToDel, wCell)
End If
End If
Next wCell
If Not rngToDel Is Nothing Then rngToDel.EntireRow.Delete
Next I
End Sub
The problem was I set range to delete as wCell in wRng, but really what I wanted to delete was cells in fRng. By fixing that the rest of the code worked perfectly. (thanks chris)

Excel VBA: Loop through cells and copy values to another workbook

I already spent hours on this problem, but I didn't succeed in finding a working solution.
Here is my problem description:
I want to loop through a certain range of cells in one workbook and copy values to another workbook. Depending on the current column in the first workbook, I copy the values into a different sheet in the second workbook.
When I execute my code, I always get the runtime error 439: object does not support this method or property.
My code looks more or less like this:
Sub trial()
Dim Group As Range
Dim Mat As Range
Dim CurCell_1 As Range
Dim CurCell_2 As Range
Application.ScreenUpdating = False
Set CurCell_1 = Range("B3") 'starting point in wb 1
For Each Group in Workbooks("My_WB_1").Worksheets("My_Sheet").Range("B4:P4")
Set CurCell_2 = Range("B4") 'starting point in wb 2
For Each Mat in Workbooks("My_WB_1").Worksheets("My_Sheet").Range("A5:A29")
Set CurCell_1 = Cells(Mat.Row, Group.Column) 'Set current cell in the loop
If Not IsEmpty(CurCell_1)
Workbooks("My_WB_2").Worksheets(CStr(Group.Value)).CurCell_2.Value = Workbooks("My_WB_1").Worksheets("My_Sheet").CurCell_1.Value 'Here it break with runtime error '438 object does not support this method or property
CurCell_2 = CurCell_2.Offset(1,0) 'Move one cell down
End If
Next
Next
Application.ScreenUpdating = True
End Sub
I've done extensive research and I know how to copy values from one workbook to another if you're using explicit names for your objects (sheets & ranges), but I don't know why it does not work like I implemented it using variables.
I also searched on stackoverlow and -obviously- Google, but I didn't find a similar problem which would answer my question.
So my question is:
Could you tell me where the error in my code is or if there is another easier way to accomplish the same using a different way?
This is my first question here, so I hope everything is fine with the format of my code, the question asked and the information provided. Otherwise let me know.
5 Things...
1) You don't need this line
Set CurCell_1 = Range("B3") 'starting point in wb 1
This line is pointless as you are setting it inside the loop
2) You are setting this in a loop every time
Set CurCell_2 = Range("B4")
Why would you be doing that? It will simply overwrite the values every time. Also which sheet is this range in??? (See Point 5)
3)CurCell_2 is a Range and as JohnB pointed it out, it is not a method.
Change
Workbooks("My_WB_2").Worksheets(CStr(Group.Value)).CurCell_2.Value = Workbooks("My_WB_1").Worksheets("My_Sheet").CurCell_1.Value
to
CurCell_2.Value = CurCell_1.Value
4) You cannot assign range by just setting an "=" sign
CurCell_2 = CurCell_2.Offset(1,0)
Change it to
Set CurCell_2 = CurCell_2.Offset(1,0)
5) Always specify full declarations when working with two or more objects so that there is less confusion. Your code can also be written as
Option Explicit
Sub trial()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim Group As Range, Mat As Range
Dim CurCell_1 As Range, CurCell_2 As Range
Application.ScreenUpdating = False
'~~> Change as applicable
Set wb1 = Workbooks("My_WB_1")
Set wb2 = Workbooks("My_WB_2")
Set ws1 = wb1.Sheets("My_Sheet")
Set ws2 = wb2.Sheets("Sheet2") '<~~ Change as required
For Each Group In ws1.Range("B4:P4")
'~~> Why this?
Set CurCell_2 = ws2.Range("B4")
For Each Mat In ws1.Range("A5:A29")
Set CurCell_1 = ws1.Cells(Mat.Row, Group.Column)
If Not IsEmpty(CurCell_1) Then
CurCell_2.Value = CurCell_1.Value
Set CurCell_2 = CurCell_2.Offset(1)
End If
Next
Next
Application.ScreenUpdating = True
End Sub
Workbooks("My_WB_2").Worksheets(CStr(Group.Value)).CurCell_2.Value
This will not work, since CurCell_2 is not a method of Worksheet, but a variable. Replace by
Workbooks("My_WB_2").Worksheets(CStr(Group.Value)).Range("B4").Value