How to parse through a row using information pulled from a user form - excel

I am attempting to create a userform which takes input from userform1 and passes it to userform2 which displays the information belonging to that set of data on userform2. The problem is that once the overall category is selected from row 1 (CATBOX), I need to limit the parser to the subcomponents in row 2 as there are other subcomponents in other categories on the same row. Each Category in row 1 is a series of merged cells.
I have already tried using 'find' to find the value of userform1!CATBOX and return the position to get the starting column. Then I tried to find the range of the merged cell so that I could get the end point. I then tried to limit the parser to the range of columns on row 2 to collect my information. I included the last bit of code to simply display the values of the start and end points onto userform2, it is not necessary to my code.
With ActiveSheet
Set ra = ActiveSheet.Cells.Find(What:=UserForm1!CATBOX.Value, After:=Range("A1"), _
LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False).Activate
Set rng = Range(ra)
If rng.MergeCells Then
Set rng = rng.MergeArea
Set rngStart = rng.Cells(1, 1)
Set rngEnd = rng.Cells(rng.Rows.Count, rng.Columns.Count)
End If
Set rag = UserForm2.Controls.Add("Forms.Label.1", "rag", True)
With rag
.Caption = rngStart.Address
.Left = 10
.Width = 50
.Top = 50
End With
Set rag2 = UserForm2.Controls.Add("Forms.Label.1", "rag2", True)
With rag2
.Caption = rngEnd.Address
.Left = 70
.Width = 50
.Top = 50
End With
End With
The result I am looking to get is the ability to parse that second row of information limited to the range of columns established by the merged category above it.

Welcome to SO.Though the requirement and worksheet Data layout is not clear, It assumed as below.
Code used may be modified to your requirement and may be moved from Change Event of CATBOX to any suitable event
Private Sub CATBOX_Change()
Dim Rng As Range, SubRng As Range
Dim Rw As Long, ColSt As Long, ColEnd As Long, i As Long, ScatNo As Long
Dim Rag As Object
With ThisWorkbook.ActiveSheet
Set Rng = .Rows(1).Find(What:=UserForm1.CATBOX.Value, LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Rng Is Nothing Then Exit Sub
Set Rng = Rng.MergeArea
Set rngstart = Rng.Cells(1, 1)
Set rngEnd = Rng.Cells(Rng.Rows.Count, Rng.Columns.Count)
Rw = Rng.Row + Rng.Rows.Count
ColSt = Rng.Column
ColEnd = Rng.Column + Rng.Columns.Count - 1
Debug.Print Rw, ColSt, ColEnd
Set Rng = .Range(.Cells(Rw, ColSt), .Cells(Rw, ColEnd))
ScatNo = 0
For Each SubRng In Rng
If SubRng.Value <> "" Then
ScatNo = ScatNo + 1
Set Rag = UserForm2.Controls.Add("Forms.Label.1", "Scat" & ScatNo)
Rag.Caption = SubRng.Value
Rag.Left = 70
Rag.Width = 50
Rag.Top = ScatNo * 30
End If
Next
End With
UserForm2.Show
End Sub

Related

How to distribute a known number evenly across a range in VBA

I've a problem here, I've been trying to use VBA to distribute a known number evenly across a range.The problem is that I need to find the way where the numbers in the range be as equal as possible to each other, could you help me? or give ideas?
The data set is as follow
The known number is given by "TV Comodin" Row in color Red, and here is my try:
Sub Prueba()
Columns("A:A").Select
Set Cell = Selection.Find(What:="TV Comodín", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ActiveCell = Cell
Cell.Select
comodin = ActiveCell.Offset(0, 1).Value2
Range("A2").Select
Firstrow = ActiveCell.Row
Selection.End(xlDown).Select
Lastrow = ActiveCell.Row
j = comodin
While (j > 0)
For i = 2 To Lastrow
Range("B2").Select
Range("B" & i) = Range("B" & i).Value + 1
If j > 0 Then j = j - 1
If j = 0 Then Exit For
Next
Wend
End Sub
Basically, my code finds the "TV Comodin" row to get de number of times that the loop is gonna add 1 by 1 in every single row of its column,
Sorry, I'm a little bit new on VBA, thanks by the way.
Here's one approach. Find the smallest number in the range: add one. Repeat until you've done that (eg) 55 times.
Sub Prueba()
Dim f As Range, ws As Worksheet, comodin As Long, rng As Range, m, mn
Set ws = ActiveSheet
Set rng = ws.Range("A2", ws.Range("A2").End(xlDown)).Offset(0, 1)
Set f = ws.Columns("A").Find(What:="TV Comodín", LookIn:=xlFormulas, _
LookAt:=xlWhole, MatchCase:=False)
If Not f Is Nothing Then
rng.Value = ws.Evaluate("=" & rng.Address() & "*1") 'fill empty cells with zeros
comodin = f.Offset(0, 1).Value
Do While comodin > 0
mn = Application.Min(rng)
If mn >= 100 Then Exit Do ' exit when no values are <100
m = Application.Match(mn, rng, 0)
rng.Cells(m).Value = rng.Cells(m).Value + 1
comodin = comodin - 1
Loop
Else
MsgBox "not found!"
End If
End Sub

VBA Trying to check for a value in column and if there copy another cells value to a new column

I have a table of data in a sheet that i am looking to make some adjustments to. I have a single column called "S/R" which will have one of two values in it [Serving OR Returning]. If the value is serving i want to copy the value from a column called "1stServeX" to a new column i have added i called "Server 1st Serve X".
I have written the code below but am beginning to trip myself up and also cannot finish the last part. I am a novice and so have been using other pieces of code i have gained previously to try and piece it together, which is why i need some help.
If i can get this going then i can simply repeat it for all the "Returner" option and all the other columns i need to split too.
Thanks in advance for any help offered.
Public Sub splitServerCoordinates()
'Set a constant for the title of the Server Column
Const HEADER_SR As String = "S/R"
Dim ws As Worksheet
Set ws = Sheets("transition")
Dim strSearch As String
Dim aCell As Range
Dim COL_SR As Long
Dim COL_TARGET As Long
Dim COL_CURRENT As Long
'Find the Column Numbers of the columns we are looking for
strSearch = "S/R"
Set aCell = ws.Rows(1).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
COL_SR = aCell.Column
End If
strSearch = "1stServeX"
Set aCell = ws.Rows(1).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
COL_CURRENT = aCell.Column
End If
strSearch = "Server 1st Serve X"
Set aCell = ws.Rows(1).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
COL_TARGET = aCell.Column
End If
Dim theUsedRange As Range
Dim SRRange As Range
Dim aPlayer As Range
Dim serving As String
Dim returning As String
Dim theCounter As Long
Dim theSequence As Long
ws.Select
' clear out the Target column and add the header again
Set theUsedRange = ActiveSheet.UsedRange
Intersect(theUsedRange, Range(Columns(COL_TARGET), Columns(COL_TARGET))).ClearContents
Columns(COL_SR).Range("A1").Value = HEADER_SR
' reset the used range just in case
Set theUsedRange = ActiveSheet.UsedRange
' Get the used range for the S/R column
Set SRRange = Intersect(theUsedRange, Columns(COL_SR))
'Set value to compare to
serving = "Serving"
' Loop through the S/R column
For Each aPlayer In SRRange
' ignore the header row
If aPlayer <> HEADER_SR Then
' if we are serving then copy the value from COL_CURRENT to COL_TARGET
If aPlayer = serving Then
aPlayer.Offset(-1, COL_TARGET - COL_).Value = STUCK - HERE
End If
End If
Next aPlayer
End Sub
Some refactoring to pull out the column header location parts, and a few other tweaks. Untested, but should get you there.
Public Sub splitServerCoordinates()
Dim ws As Worksheet, c As Range
Dim COL_SR As Long
Dim COL_TARGET As Long
Dim COL_CURRENT As Long
Set ws = Sheets("transition")
'Find the Column Numbers of the columns we are looking for
COL_SR = HeaderColumnNumber(ws.Rows(1), "S/R")
COL_CURRENT = HeaderColumnNumber(ws.Rows(1), "1stServeX")
COL_TARGET = HeaderColumnNumber(ws.Rows(1), "Server 1st Serve X", True) 'add if not found
'exit if missing any required columns
If COL_SR = 0 Or COL_CURRENT = 0 Then
MsgBox "Missing 'S/R' and/or '1stServeX' !"
Exit Sub
End If
'reset target column
ws.Columns(COL_TARGET).ClearContents
ws.Cells(1, COL_TARGET).Value = "Server 1st Serve X"
'loop rows
For Each c In ws.Range(ws.Cells(2, COL_SR), ws.Cells(ws.Rows.Count, COL_SR).End(xlUp)).Cells
If c.Value = "Serving" Then
ws.Cells(c.Row, COL_TARGET).Value = ws.Cells(c.Row, COL_CURRENT).Value
End If
Next c
End Sub
'Find a header position on a row, with option to add it if not found
' Returns zero if header is not found and option to add was not set
Function HeaderColumnNumber(rng As Range, hdr As String, _
Optional AddIfMissing As Boolean = False) As Long
Dim f As Range
Set rng = rng.Cells(1).EntireRow 'only want a full row to look in
Set f = rng.Find(What:=hdr, LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not f Is Nothing Then
HeaderColumnNumber = f.Column 'found: return column
Else
'not found: do we add it, or return zero?
If AddIfMissing Then
With rng.Cells(rng.Cells.Count).End(xlToLeft).Offset(0, 1)
.Value = hdr
HeaderColumnNumber = .Column
End With
Else
HeaderColumnNumber = 0
End If
End If
End Function

Import URL as jpg and size largest column width and row height of image

I'm working on downloading about 8k jpg files from the net. The URL for the files is in column B and I want to output the actual image in column C. I have some code I've mangled together to do the download but the images are coming in small. I want them to come in the original size. So, I'd like to determine what the biggest jpg file is and make the row height and column width match it. Here is the code I have so far:
Sub Test2()
Dim Pic As Picture
Dim SrcRange As Range
Dim LastRowA As Long
LastRowA = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Set SrcRange = ActiveSheet.Range(Cells(2, 1), Cells(LastRowA, 1))
SrcRange.Rows().RowHeight = ActiveSheet.Columns(3).Width * 2
For Each cell In SrcRange.Cells
With cell
Set Pic = .Parent.Pictures.Insert(.Value)
With .Offset(, 1)
Pic.Top = .Top
Pic.Left = .Left
Pic.Height = .Height
Pic.Width = .Width
Pic.Border.Color = vbRed
End With
End With
Next
End Sub
As always, any help will be greatly appreciated. It has been about 5 years since I've done any excel vba coding. I'm a little rusty. I'm running excel 2016.
Set the picture aspect ratio to false.
Pic.ShapeRange.LockAspectRatio = msoFalse
In your code..
For Each cell In SrcRange.Cells
With cell
Set Pic = .Parent.Pictures.Insert(.Value)
Pic.ShapeRange.LockAspectRatio = msoFalse '<~~ set LockAspetRatio to false
With .Offset(, 1)
Pic.Top = .Top
Pic.Left = .Left
Pic.Height = .Height
Pic.Width = .Width
Pic.Border.Color = vbRed
End With
End With
Next
End Sub
In the above method, the picture is not saved as an Excel file, only a link is set. To save a picture to an Excel file, do the following:
Sub Test2()
Dim Pic As Picture
Dim SrcRange As Range
Dim LastRowA As Long
Dim l As Single, t As Single, w As Single, h As Single
Dim cell As Range
LastRowA = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Set SrcRange = ActiveSheet.Range(Cells(2, 1), Cells(LastRowA, 1))
SrcRange.Rows().RowHeight = ActiveSheet.Columns(3).Width * 2
For Each cell In SrcRange.Cells
With cell
t = .Top
l = .Left
w = .Width
h = .Height
Set shp = ActiveSheet.Shapes.AddPicture(.Value, msoCTrue, msoCTrue, l, t, w, h)
End With
Next
End Sub

Identify range in an Excel outline group

I have an Excel sheet that has data grouped using the outline method.
I'm having issues defining a range from the beginning of the group to the end of the group.
I have this data populating a listbox in a userform.
If a user selected any item in this group to delete I need to remove the whole group.
I think I am over thinking it but is there a good way to define this range?
Here is a sample of what I am starting with below
`Sub delrows()
Dim StartRow As Integer
Dim EndRow As Integer
'if outline level should never drop below 2.
'If it is 2 then this will always be the beginning of the range.
If ActiveCell.Rows.OutlineLevel = 2 Then
y = ActiveCell.Row
Else
y = ActiveCell.Row + 3
'y= needs to look up until it see a 2 then go back down 1 row
End If
If ActiveCell.Rows.OutlineLevel <> 2 Then
x = ActiveCell.Row + 1
'x = needs to look down until it finds next row 2 then back up 1 row
Else
x = ActiveCell.Row
End If
StartRow = y
EndRow = x
Rows(StartRow & ":" & EndRow).Select '.Delete
End Sub`
Worked on it a little bit. Have the outline level stored as a value on the sheet in column AA.
Sub delrows()
Dim StartRow As Integer
Dim EndRow As Integer
Dim Rng As Range
Dim C As Range
Dim B As Range
'if outline level shoudl never drop below 2.
'If it is 2 then this will always be the begining of the range.
If ActiveCell.Rows.outlinelevel = 2 Then
'If ActiveCell = 2 Then
y = ActiveCell.Row
Else
Set Rng = Range("AA:AA")
Set B = Rng.Find(What:="2", After:=ActiveCell,LookIn:=xlFormulas,LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False, SearchFormat:=False)
y = B.Offset(0, 0).Row
End If
If ActiveCell.Rows.outlinelevel <> 2 Then
Set Rng = Range("AA:AA")
Set C = Rng.Find(What:="2", After:=ActiveCell, LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
x = C.Offset(-1, 0).Row
Else
If ActiveCell.Rows + 1 = 3 Then
Set Rng = Range("AA:AA")
Set C = Rng.Find(What:="2", After:=ActiveCell, LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
x = C.Offset(-1, 0).Row
Else
x = ActiveCell.Row
End If
End If
StartRow = y
EndRow = x
Rows(StartRow & ":" & EndRow).Delete
End Sub
Try this:
Option Explicit
Public Sub RemoveGroup()
Dim grpStart As Range, grpEnd As Range, lvl As Long
Set grpStart = Sheet1.Range("A7").EntireRow 'test cell - A7
Set grpEnd = grpStart
lvl = grpStart.OutlineLevel
While lvl = grpStart.OutlineLevel 'find start of current group (up)
Set grpStart = grpStart.Offset(-1)
Wend
Set grpStart = grpStart.Offset(1) 'exclude 1st row in next group
While lvl = grpEnd.OutlineLevel 'find end of current group (down)
Set grpEnd = grpEnd.Offset(1)
Wend
Set grpEnd = grpEnd.Offset(-1) 'exclude 1st row in next group
With Sheet1.Rows(grpStart.Row & ":" & grpEnd.Row)
.ClearOutline
.Delete
End With
End Sub
Before and After:

MS VBA with loops and unions

Dim Counter As Integer
Dim Maxhouse As Integer
Dim FindHouse As Range
Dim RangeVar As Range
Dim HousesRange As Range
For Counter = 1 To MaxHouse
ActiveSheet.Cells(16, 2 + Counter).Select
House = ActiveCell
With Sheets("Sheet1").Range("C:KP")
Set FindHouse = Cells.Find(What:=House, _
After:=Cells(17, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not FindHouse Is Nothing Then
If Counter = 1 Then
Set HousesRange = FindHouse
Else
Set RangeVar = FindHouse
Set HousesRange = Union(HousesRange, RangeVar)
End If
End If
End With
Next Counter
For Each RCell In HousesRange.Cells
Application.Goto RCell, True
Next RCell**
Now my problem is with the for loop which traverses through the named range 'HousesRange'
So lets say that HousesRange contains [2,5,9,10].
Here HousesRange is a subset of the row [1,2,3,4,5,6,7,8,9,10] in my Sheet
And lets assume that HousesRange was established through the order of [9,10,5,2] (through the 1st for loop with the union).
Now as I traverse through HousesRange with just rCells (the second for loop), it takes me to 9, 10, 5 then 2.
But I want it to take me to 2, 5, 9 then 10
Can some body shed some light to this?
I had always thought that named ranges are ALWAYS traversed through left to right and then top to bottom.
Thank you so much in advance
Ok this is the long way round, but it should work:
Instead of using Union build your list of found houses in a dictionary object.
Then sort the ranges using Bubblesort HouseRangeDic
You should finally be able to use it in the right order:
Dim Counter As Integer
Dim Maxhouse As Integer
Dim FindHouse As Range
Dim RangeVar As Range
Dim HousesRange As Range
'****** NEW **********
Dim foundHouseCount
foundHouseCount = 1
Dim HouseRangeDic
Set HouseRangeDic = CreateObject("Scripting.dictionary")
'*********************
For Counter = 1 To Maxhouse
ActiveSheet.Cells(16, 2 + Counter).Select
House = ActiveCell
With Sheets("Sheet1").Range("C:KP")
Set FindHouse = Cells.Find(What:=House, _
After:=Cells(17, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not FindHouse Is Nothing Then
HouseRangeDic.Add foundHouseCount, RangeVar '**** NEW ***
foundHouseCount = foundHouseCount + 1 '**** NEW ***
End If
End With
Next Counter
'**** NEW ***
Bubblesort HouseRangeDic
For i = 1 To HouseRangeDic.Count
Application.Goto HouseRangeDic(i), True
Next
'************
Sub Bubblesort(ByRef rangeDic)
Dim tempRange
For i = 1 To rangeDic.Count - 1
For j = i To rangeDic.Count
If rangeDic(i).Address > rangeDic(j).Address Then
Set tempRange = rangeDic(i)
Set rangeDic(i) = rangeDic(j)
Set rangeDic(j) = tempRange
End If
Next
Next
End Sub
See if this works for you. Notice my "After:=" is set to the LAST cell of the range, so the first find starts at the beginning of the range.
Sub loopCells()
Dim FindHouse As Range
Dim HousesRange As Range
Dim rcell As Range
Dim r As Range
Dim sAdd As String
Dim House As Long
Set r = Sheets("Sheet1").Range("$C$15:$K$20") 'change to suit
House = 11'change to suit
With r
Set FindHouse = .Find(What:=House, After:=r(.Cells.Count), LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
If Not FindHouse Is Nothing Then
sAdd = FindHouse.Address
Do
If HousesRange Is Nothing Then
Set HousesRange = FindHouse
Else
Set HousesRange = Union(HousesRange, FindHouse)
End If
Set FindHouse = .FindNext(FindHouse)
Loop While Not FindHouse Is Nothing And FindHouse.Address <> sAdd
End If
End With
For Each rcell In HousesRange
Application.Goto rcell
Next rcell
End Sub

Resources