(VBA Beginner) Row 15 is my first row of the table.
I can add data using a UserForm into Row 15 but i want to if i have data in Row 15 add into the next row (in my case Row 16 always +1) this is the function that im using:
Public Function GetLastRow(TargetWorksheet As Worksheet, ColumnNo As Variant) As Long
If TargetWorksheet Is Nothing Then Exit Function
GetLastRow = TargetWorksheet.Cells(TargetWorksheet.Rows.Count, ColumnNo).End(xlUp).Row
End Function
And this is my add button:
Private Sub CommandButton1_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("OIL_")
Dim GetLastRow As Long
'Validações-----------------------------------------------------
If Me.txtID.Value = "" Then
MsgBox "Insira um ID!", vbCritical
Exit Sub
End If
If Me.txtDesc.Value = "" Then
MsgBox "Insira uma Descrição!", vbCritical
Exit Sub
End If
'---------------------------------------------------------------
If GetLastRow + 1 <= 15 Then GetLastRow = 15 Else GetLastRow = GetLastRow + 1
sh.Cells(GetLastRow, 2).Value = Me.txtID.Value
sh.Cells(GetLastRow, 11).Value = Me.txtDesc.Value
sh.Cells(GetLastRow, 29).Value = Me.txtData.Value
End Sub
For now its only inserting data into my Row 15 and if i try to add another one it just replaces for the new data, i tried a lot of things and i cant manage to add data into the next row always.
Your function is named the same as your variable, this is confusing and if you debug your code you will find the GetLastRow will always equal zero and that is causing your issue. My biggest suggestion is to learn to use the debugger!
You could change your code to something like this:
Private Sub CommandButton1_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("OIL_")
Dim lastRow As Long
'Validações-----------------------------------------------------
If Me.txtID.Value = "" Then
MsgBox "Insira um ID!", vbCritical
Exit Sub
End If
If Me.txtDesc.Value = "" Then
MsgBox "Insira uma Descrição!", vbCritical
Exit Sub
End If
'---------------------------------------------------------------
lastRow = GetLastRow(sh, 3) 'I am not sure what column you need I just used 3 for example
If lastRow + 1 <= 15 Then lastRow = 15 Else lastRow = lastRow + 1
sh.Cells(lastRow, 2).Value = Me.txtID.Value
sh.Cells(lastRow, 11).Value = Me.txtDesc.Value
sh.Cells(lastRow, 29).Value = Me.txtData.Value
End Sub
Well, problem solved this is the right way to do it
Private Sub AddButton_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("OIL_")
Dim lastRow As Long
'Validações-----------------------------------------------------
If Me.txtID.Value = "" Then
MsgBox "Insira um ID!", vbCritical
Exit Sub
End If
If Me.txtDesc.Value = "" Then
MsgBox "Insira uma Descrição!", vbCritical
Exit Sub
End If
'---------------------------------------------------------------
lastRow = GetLastRow(sh, 2)
If lastRow + 1 <= 15 Then lastRow = 15 Else lastRow = lastRow + 1
sh.Cells(lastRow, 2).Value = Me.txtID.Value
sh.Cells(lastRow, 11).Value = Me.txtDesc.Value
sh.Cells(lastRow, 29).Value = Me.txtData.Value
End Sub
And this is the right function:
Public Function GetLastRow(TargetWorksheet As Worksheet, ColumnNo As Variant) As Long
If TargetWorksheet Is Nothing Then Exit Function
GetLastRow = TargetWorksheet.Cells(TargetWorksheet.Rows.Count, ColumnNo).End(xlUp).Row
End Function
Thanks to everyone
Related
I'm making a very easy application to insert names and some other info , and I'm getting a problem in the sub. I don't know what's happening , been a long time since I used vba ....
Private Sub button_Click()
Dim linha As Long
linha = Worksheets("FAMINHO_ESCOLAS").cell(Rows.Count, 1).End(xlUp).Row + 1
Range("A" & linha).Value = boxname.Value
Range("B" & linha).Value = boxinstr.Value
Range("C" & linha).Value = boxescola.Value
Range("D" & linha).Value = boxtel.Value
Range("E" & linha).Value = boxemail.Value
End Sub
I'm getting error 438
I'm trying to return the values , when i press the "buttonright" it changes to the next data , and when i press buttonleft it shows me previous data and so on
Private Sub CommandButton1_Click()
GetFAMINHO_ESCOLASLastRow boxname1.Value, boxinstr1.Value, boxescola1.Value,
boxtel1.Value, boxemail1.Value
End Sub
Function GetFAMINHO_ESCOLASLastRow() As Range
Dim Target As Range
With Worksheets("FAMINHO_ESCOLAS")
Set Target = .Cells(.Rows.Count, 1).End(xlUp)
Set Target = Intersect(Target.EntireRow, Target.CurrentRegion)
End With
Set GetFAMINHO_ESCOLASLastRow = Target
End Function
linha is set to the last row but LR is the variable that is actually used for the last row.
linha = Worksheets("FAMINHO_ESCOLAS").Cell(Rows.Count, 1).End(xlUp).Row + 1
Cell( should be changes to Cells(.
linha = Worksheets("FAMINHO_ESCOLAS").Cells(Rows.Count, 1).End(xlUp).Row + 1
It would be better to qualify Rows.Count to the worksheet.
I prefer to write a separate sub routine to add the values. In this way, I can test the code without having to instantiate a userform.
Alternative Solution
Note: AddRowToFAMINHO_ESCOLAS will accept anywhere from 1 to 69 values.
Private Sub button_Click()
AddRowToFAMINHO_ESCOLAS boxname.Value, boxname.Value, boxinstr.Value, boxescola.Value, boxtel.Value, boxemail.Value
End Sub
Sub AddRowToFAMINHO_ESCOLAS(ParamArray Args() As Variant)
With Worksheets("FAMINHO_ESCOLAS")
.Cells(.Rows.Count, 1).End(xlUp).Offset(1).Resize(1, UBound(Args) + 1).Value = Args
End With
End Sub
AddRowToFAMINHO_ESCOLAS Demo
Addendum
This function will return the last row with values in column A.
Function GetFAMINHO_ESCOLASLastRow() As Range
Dim Target As Range
With Worksheets("FAMINHO_ESCOLAS")
Set Target = .Cells(.Rows.Count, 1).End(xlUp)
Set Target = Intersect(Target.EntireRow, Target.CurrentRegion)
End With
Set GetFAMINHO_ESCOLASLastRow = Target
End Function
You can test this function by entering the following code into the Immediate Window:
Application.Goto GetFAMINHO_ESCOLASLastRow
Response to Question Update
I changed things up a bit because the OP wants to write and retrieve the values.
Private Sub buttonleft_Click()
Dim Target As Range
Set Target = GetFAMINHO_ESCOLASLastRow
With Target
boxname.Value = .Cells(1, 1).Value
boxinstr.Value = .Cells(1, 2).Value
boxescola.Value = .Cells(1, 3).Value
boxtel.Value = .Cells(1, 4).Value
boxemail.Value = .Cells(1, 5).Value
End With
End Sub
Private Sub buttonright_Click()
Dim Target As Range
Set Target = GetFAMINHO_ESCOLASNewRow
With Target
.Cells(1, 1).Value = boxname.Value
.Cells(1, 2).Value = boxinstr.Value
.Cells(1, 3).Value = boxescola.Value
.Cells(1, 4).Value = boxtel.Value
.Cells(1, 5).Value = boxemail.Value
End With
End Sub
Function GetFAMINHO_ESCOLASLastRow() As Range
Dim Target As Range
With Worksheets("FAMINHO_ESCOLAS")
Set Target = .Cells(.Rows.Count, 1).End(xlUp)
Set Target = Intersect(Target.EntireRow, Target.CurrentRegion)
End With
Set GetFAMINHO_ESCOLASLastRow = Target
End Function
Function GetFAMINHO_ESCOLASNewRow() As Range
Set GetFAMINHO_ESCOLASNewRow = GetFAMINHO_ESCOLASLastRow.Offset(1)
End Function
I want a userform where as text is being typed into textbox1, possible values that match the text from the sheet "Data" populate listbox1 and similarly for textbox2 and listbox2. Currently when I type in textbox1, it's filling listbox2 with values from column A in the sheet that is open, instead of the sheet "Data".
Private Sub TextBox1_Change()
Dim i As Integer, ws As Worksheet
ListBox1.Visible = True
Set ws = Sheets("Data")
For i = 2 To Sheets("Data").Range("D6000").End(xlUp).Row
If UCase(Left(ws.Cells(i, 1), Len(TextBox1.Text))) = UCase(TextBox1.Text) Then
ListBox1.AddItem Cells(i, 1)
End If
Next i
End Sub
Private Sub TextBox2_Change()
Dim i As Integer, ws As Worksheet
ListBox2.Visible = True
Set ws = Sheets("Data")
For i = 2 To Sheets("Data").Range("B6000").End(xlUp).Row
If UCase(Left(ws.Cells(i, 1), Len(TextBox2.Text))) = UCase(TextBox2.Text) Then
ListBox2.AddItem Cells(i, 1)
End If
Next i
End Sub
Edit: What I ended up using:
Private Sub TextBox1_Change()
Dim i As Long
Dim arrList As Variant
Me.ListBox1.Clear
If Sheet7.Range("D" & Sheet7.Rows.Count).End(xlUp).Row > 1 And Trim(Me.TextBox1.Value) <> vbNullString Then
arrList = Sheet7.Range("D1:D" & Sheet7.Range("D" & Sheet7.Rows.Count).End(xlUp).Row).Value2
For i = LBound(arrList) To UBound(arrList)
If InStr(1, arrList(i, 1), Trim(Me.TextBox1.Value), vbTextCompare) Then
Me.ListBox1.AddItem arrList(i, 1)
End If
Next i
End If
If Me.ListBox1.ListCount = 1 Then Me.ListBox1.Selected(0) = True
End Sub
Private Sub TextBox2_Change()
Dim i As Long
Dim arrLists As Variant
Me.ListBox2.Clear
If Sheet7.Range("B" & Sheet7.Rows.Count).End(xlUp).Row > 1 And Trim(Me.TextBox2.Value) <> vbNullString Then
arrLists = Sheet7.Range("B1:B" & Sheet7.Range("B" & Sheet7.Rows.Count).End(xlUp).Row).Value2
For i = LBound(arrLists) To UBound(arrLists)
If InStr(1, arrLists(i, 1), Trim(Me.TextBox2.Value), vbTextCompare) Then
Me.ListBox2.AddItem arrLists(i, 1)
End If
Next i
End If
If Me.ListBox2.ListCount = 1 Then Me.ListBox2.Selected(0) = True
End Sub
Use ws.Cells(i, 1) instead of Cells(i, 1).
Also, should the part concerning ListBox2 be moved to TextBox2_Change() ?
Find function works quite good, but there are few exceptions that I don't understand. I have userform, I use find method to get all information about product/item by its code and showing it after button is pressed in userform. Product codes in my table consists of such codes: 1230, 1231, 1232... 1239. The main problem is that I don't understand why numbers like: 1-9, 123 doesn't trigger the msgbox "Can't find product"?
Private Sub btnSearch_Click()
Dim i As Long
Dim totalRows As Long
Dim itemCode As Range
Set itemCode = ThisWorkbook.Sheets("Data").Range("A:A").Find(Me.txtCode.Value)
totalRows = Worksheets("Data").Range("A:A").CurrentRegion.Rows.Count
'searching by code
If Trim(Me.txtCode.Value) = "" Then
Me.txtCode.SetFocus
MsgBox "Need item code"
Exit Sub
End If
If itemCode Is Nothing Then
MsgBox "Can't find product with such code"
End If
For i = 2 To totalRows
If Trim(Cells(i, 1)) = Trim(Me.txtCode) Then
txtName.Text = Cells(i, 2)
'unit of measurement name
txtUnitName.Text = Cells(i, 3)
txtPrice.Text = Cells(i, 4)
Exit For
End If
Next i
End Sub
If you want an exact match, you should add LookAt:=xlWhole to the find parameters.
Otherwise this should do about the same thing, without using find:
Private Sub btnSearch_Click()
Dim i As Long
Dim totalRows As Long
Dim arrData As Variant
With Worksheets("Data")
totalRows = .Cells(Rows.Count, 1).End(xlUp).Row
arrData = .Range("A1:D" & totalRows)
End With
'searching by code
If Trim(Me.txtCode.Value) = "" Then
Me.txtCode.SetFocus
MsgBox "Need item code"
Exit Sub
End If
For i = 2 To totalRows
If Trim(arrData(i, 1)) = Trim(Me.txtCode) Then
txtName.Text = arrData(i, 2)
'unit of measurement name
txtUnitName.Text = arrData(i, 3)
txtPrice.Text = arrData(i, 4)
Exit For
End If
If i = totalRows Then MsgBox "Can't find product with such code"
Next i
End Sub
Replace:
Set itemCode = ThisWorkbook.Sheets("Data").Range("A:A").Find(Me.txtCode.Value)
With:
Set itemCode = ThisWorkbook.Sheets("Data").Range("A:A").Find(Trim(Me.txtCode.Value), LookIn:=xlValues, LookAt:=xlWhole)
I have up to 6 cells with potential data coming from 6 different places. I am trying to get only the first three cells with data transferred to another sheet
Private Sub Transfer_Data()
Sheets("sheet1").Range("A1:A6").SpecialCells(xlCellTypeConstants, 23).copy
Sheets("sheet2").Range("A1:A3").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
This is what i have i know i am missing allot
This is how I would do it:
Sub Transfer_Data()
Dim i As Long, j As Long
j = 1
For i = 1 To 6
If Sheets("Sheet1").Cells(i, 1).Value <> "" Then
Sheets("Sheet2").Cells(j, 1).Value = Sheets("Sheet1").Cells(i, 1).Value
j = j + 1
End If
If j > 3 Then Exit For
Next i
End Sub
EDITED:
Sub Transfer_Data()
Dim i As Long, j As Long
j = 3
For i = 1 To 6
If Sheets("Sheet1").Cells(i, 1).Value <> "" Then
Sheets("Sheet2").Cells(j, 1).Value = Sheets("Sheet1").Cells(i, 1).Value
j = j - 1
End If
If j = 0 Then Exit For
Next i
End Sub
Untested, there may be another, more elegant way of doing this:
Private Sub TransferData()
Dim cellCount as long
Dim cell as range
Dim rangeToCopy as range
For each cell in Sheets("sheet1").Range("A1:A6").SpecialCells(xlCellTypeConstants) ' 23 is unnecessary, as you get all XlSpecialCellsValue constants by default
' See https://learn.microsoft.com/en-us/office/vba/api/excel.range.specialcells
cellCount = cellCount + cell.cells.count
If not (rangeToCopy is nothing) then
Set rangeToCopy = application.union(rangeToCopy, cell)
Else
Set rangeToCopy = cell
End if
If cellCount = 3 then exit for
Next cell
If not (rangeToCopy is nothing) then
rangeToCopy.copy
Sheets("sheet2").Range("A1").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End if
End Sub
I know this already answered, but how about a crazy one-liner?
Sub TransferData()
ThisWorkbook.Sheets("Sheet2").Range("A1:A3").Value2 = WorksheetFunction.Transpose(Split(Replace$(Join(WorksheetFunction.Transpose(ThisWorkbook.Sheets("Sheet1").Range("A1:A6").Value2), ","), ",,", ","), ","))
End Sub
I'm looking for some advise on this code. It is a UserForm with 3 comboboxes the first one filters the BLOCK (unique values), the second one the TAG (also unique) and the last it will be the ACT. After selecting all 3 we write the STATUS on the same line.
The first filter is ok, but I dont know how to go further I couldnt get Autofilter to work on the second filter... Any better solution?
Below the code I have and the table.
Thanks,
Private Sub UserForm_Initialize()
Dim v, e, lastrow
lastrow = Sheets("Plan1").Cells(Rows.Count, 1).End(xlUp).Row
With Sheets("Plan1").Range("A2:A" & lastrow)
v = .Value
End With
With CreateObject("scripting.dictionary")
.comparemode = 1
For Each e In v
If Not .exists(e) Then .Add e, Nothing
Next
If .Count Then Me.cbBloco.List = Application.Transpose(.keys)
End With
End Sub
-
BLOCK ACT TAG STATUS
M00 FAB 201-02-31
M00 MON 201-02-31
M02 FAB 201-02-32
M02 MON 201-02-32
M02 INS 201-02-32
M02 FAB 201-02-33
M02 MON 201-02-33
M02 INS 201-02-33
M02 TER 201-02-33
edited after op's detailed specs
edited 2: after OP's new specs
try this in Form's Module
Option Explicit
Dim cnts(1 To 3) As ComboBox
Dim list(1 To 3) As Variant
Dim dataRng As Range, dbRng As Range, statusRng As Range, helperRng As Range
Private Sub UserForm_Initialize()
Set dbRng = Sheets("Plan1").UsedRange
Set helperRng = dbRng.Offset(dbRng.Rows.Count + 1, dbRng.Columns.Count + 1).Cells(1, 1)
Set dataRng = dbRng.Offset(1).Resize(dbRng.Rows.Count - 1)
Set statusRng = dataRng.Columns(dbRng.Columns.Count)
With Me
Set cnts(1) = .cbBloco '<== give control its actual name
Set cnts(2) = .cbAct '<== give control its actual name
Set cnts(3) = .cbTag '<== give control its actual name
End With
Call FillComboBoxes
End Sub
Private Sub FillComboBoxes()
Dim i As Long
Application.ScreenUpdating = False
dbRng.Autofilter field:=4, Criteria1:="<>ISSUED" ' <== added, to avoid rows with "ISSUED" status
For i = 1 To UBound(cnts)
dataRng.SpecialCells(xlCellTypeVisible).Columns(i).Copy Destination:=helperRng
With helperRng.CurrentRegion
If .Rows.Count > 1 Then .RemoveDuplicates Columns:=Array(1), Header:=xlNo
With .CurrentRegion
If .Rows.Count > 1 Then
list(i) = Application.Transpose(.Cells)
Else
list(i) = Array(.Value)
End If
cnts(i).list = list(i)
.Clear
End With
End With
Next i
Application.ScreenUpdating = True
End Sub
Private Sub ResetComboBoxes()
Dim i As Long
FillComboBoxes '<== added. since you don't want "ISSUED" rows to be shown, all lists must be refilled
'For i = 1 To UBound(cnts)
' cnts(i).list = list(i)
' cnts(i).ListIndex = -1
'Next i
End Sub
Private Sub CbOK_Click()
Dim i As Long
statusRng.ClearContents
With dbRng
dbRng.Autofilter field:=4, Criteria1:="<>ISSUED" ' <== added, to avoid rows with "ISSUED" status
For i = 1 To UBound(cnts)
.Autofilter field:=i, Criteria1:=cnts(i).Value
Next i
If .SpecialCells(xlCellTypeVisible).Cells.Count > .Columns.Count Then
statusRng.SpecialCells(xlCellTypeVisible).Value = "ISSUED"
Else
MsgBox "No Match"
End If
.Autofilter
dbRng.Autofilter field:=4, Criteria1:="<>ISSUED" ' <== added, to avoid rows with "ISSUED" status
End With
End Sub
Private Sub CbReset_Click()
Call ResetComboBoxes
End Sub
Private Sub cbAct_AfterUpdate()
Call UpdateComboBoxes
End Sub
Private Sub cbBloco_AfterUpdate()
Call UpdateComboBoxes
End Sub
Private Sub cbTag_AfterUpdate()
Call UpdateComboBoxes
End Sub
Private Sub UpdateComboBoxes()
Dim i As Long
With dbRng
.Autofilter
dbRng.Autofilter field:=4, Criteria1:="<>ISSUED" ' <== added, to avoid rows with "ISSUED" status
For i = 1 To UBound(cnts)
If cnts(i).ListIndex > -1 Or cnts(i).text <> "" Then .Autofilter field:=i, Criteria1:=cnts(i).Value
Next i
If .SpecialCells(xlCellTypeVisible).Cells.Count > .Columns.Count Then
Call RefillComboBoxes
Else
Call ClearComboBoxes
End If
.Autofilter
dbRng.Autofilter field:=4, Criteria1:="<>ISSUED" ' <== added, to avoid rows with "ISSUED" status
End With
End Sub
Private Sub RefillComboBoxes()
Dim i As Long, j As Long
Dim cell As Range
Application.ScreenUpdating = False
For i = 1 To UBound(cnts)
j = 0
For Each cell In dataRng.Columns(i).SpecialCells(xlCellTypeVisible)
helperRng.Offset(j) = cell.Value
j = j + 1
Next cell
With helperRng.CurrentRegion
If .Rows.Count > 1 Then .RemoveDuplicates Columns:=Array(1), Header:=xlNo
With .CurrentRegion
If .Rows.Count > 1 Then
cnts(i).list = Application.Transpose(.Cells)
Else
cnts(i).list = Array(.Value)
End If
.Clear
End With
End With
Next i
Application.ScreenUpdating = True
End Sub
Private Sub ClearComboBoxes()
Dim i As Long
For i = 1 To UBound(cnts)
cnts(i).Clear
Next i
End Sub