Hello I have a sheet listed as ThisWorkBook.Sheets("Dash Board") or sheet1. That sheet contain a listbox that show data table from sheet2 with name "Data Barang". I tried to create a delete row command button from shape and assigned it with the function at sheet1 where my dash board displayed, but every time I click on, it shows nothing and when I click other assigned button such as update data button (it works perfectly fine before I clicked delete button) it got an error
run time error '-214702882 (8007000e)': it says not enough memory.
this is the code that I used on my delete button in module
Sub DeleteRow(ByVal row As Long)
ThisWorkbook.Sheets("Data Barang").Range("A2").Offset(row).EntireRow.Delete
End Sub
and then I call the function and assign it to my shape
this is the code at sheet1
Sub hapus()
Call DeleteRow(Sheet1.DataBarang.ListIndex)
End Sub
can any body help me? my intention is to delete a row that I have selected in the list box that displayed data from table in other sheet (sheet2)
this is the listfillrange of my listbox
Sub loaddata()
Dim listdata As Object
Set listdata = Sheet1.DataBarang ' this is my listbox name in sheet1
Dim tabeldata As Object
Set tabeldata = Sheet2.ListObjects("DataBarang") 'this is my data table in sheet 2. it have a same name with my listbox name in sheet1
With listdata
.AutoLoad = True
.ColumnHeads = True
.ColumnCount = 12
.ListFillRange = tabeldata.DataBodyRange.Address(External:=True)
End With
End Sub
and then i recall it in this code
Private Sub Workbook_Open()
Call loaddata
Call locktextbox
End Sub
Remove the ListFillRange before you delete the row and then re-apply it.
Option Explicit
Private Sub btnDelete_Click()
Dim i As Long
i = Sheet1.DataBarang.ListIndex
With Sheet2.ListObjects("DataBarang")
If i >= 0 And .ListRows.Count > 0 Then
Sheet1.DataBarang.ListFillRange = ""
.ListRows(i + 1).Delete
Call loaddata
End If
End With
End Sub
Sub loaddata()
Dim tbl As ListObject, rng As Range
Set tbl = Sheet2.ListObjects("DataBarang")
With Sheet1.DataBarang ' ListBox
.AutoLoad = True
.ColumnHeads = True
.ColumnCount = 12
.ListFillRange = ""
If tbl.ListRows.Count = 0 Then
Set rng = tbl.Range.Rows(2)
Else
Set rng = tbl.DataBodyRange
End If
.ListFillRange = rng.Address(external:=True)
End With
End Sub
Related
I have a worksheet where there is a list of car parts pending delivery from the factory. I need to populate column I with a checkbox in each cell.
I created a button called "CREATE CHECKBOXES" that looks at how many rows of data exists then populates each cell of column I with ActiveX checkboxes from CheckBox1 up to CheckboxN (n = number of rows containing data). That part is already figured out.
Next when the user checks any of the checkboxes, it must pop up a userform with 2 data field inputs that will be inserted on column J and K in the same row of the checked checkbox. Where I got stuck in the code is the event that triggers the userform to pop when any of the checkboxes is checked.
I saw Event triggered by ANY checkbox click), but now due to the code counting the checkboxes as shapes, I can't add any sort of button to add a macro to it.
I had to delete the "CREATE CHECKBOXES" button, otherwise the code from the linked post won't work.
How can I make this userform trigger event happen when any of the checkboxes are checked and maintain the shape buttons?
A few things must happen after that, but I think I can handle it.
I created a class module, named ChkClass, with this code:
' put all this code in class a module and name the class module "ChkClass"
Option Explicit
Public WithEvents ChkBoxGroup As MSForms.CheckBox
Private Sub ChkBoxGroup_Change()
Debug.Print "ChkBoxGroup_Change"
End Sub
Then pasted this in the sheet code:
' this goes into sheet code
Private Sub Worksheet_Activate()
activateCheckBoxes
End Sub
After that, I created a module and it was slightly adapted from the linked post:
' this code goes into a module
Option Explicit
Dim CheckBoxes() As New ChkClass
Sub doCheckBoxes()
makeCheckBoxes
activateCheckBoxes
End Sub
Sub makeCheckBoxes()
Sheets(2).Select
Dim c As Range
Dim ultlinha As Integer
ultlinha = Range("A2").End(xlDown).Row
Range(Cells(2, 9), Cells(ultlinha, 9)).Select
For Each c In Selection
With ActiveSheet.OLEObjects.Add(ClassType:="Forms.CheckBox.1", Left:=c.Left, Top:=c.Top, Width:=c.Width, Height:=c.Height)
DoEvents
.Object.Caption = "FATURADO"
.LinkedCell = c.Offset(0, 3).Address
.Object.Value = 0 'sets checkbox to false
.Object.Font.Name = "Calibri"
.Object.Font.Size = 9
.Object.Font.Italic = True
.Object.BackStyle = fmBackStyleTransparent
End With
Next
Range("a1").Select
End Sub
Sub activateCheckBoxes() ' assigns all checkBoxes on worksheet to ChkClass.ChkBoxGroup
Dim sht As Worksheet
Set sht = ActiveSheet
ReDim CheckBoxes(1 To 1)
Dim i As Integer
For i = 1 To sht.Shapes.Count
ReDim Preserve CheckBoxes(1 To i)
Set CheckBoxes(i).ChkBoxGroup = sht.Shapes(i).OLEFormat.Object.Object
Next i
End Sub
The problem lies in this line:
Set CheckBoxes(i).ChkBoxGroup = sht.Shapes(i).OLEFormat.Object.Object
If there is no other button or shape in the sheet, it runs correctly. If I add a single button or form to add the macro to it, it doesn't work.
If you only want to "activate" the checkboxes then you can loop over the sheet's OLEObjects collection and only capture the checkboxes.
Sub activateCheckBoxes()
Dim sht As Worksheet, obj As OLEObject, n As Long
Set sht = ActiveSheet
ReDim CheckBoxes(1 To 1)
Dim i As Integer
For Each obj In sht.OLEObjects
If TypeName(obj.Object) = "CheckBox" Then 'is a checkbox?
n = n + 1
If n > 1 Then ReDim Preserve CheckBoxes(1 To n)
Set CheckBoxes(n).ChkBoxGroup = obj.Object
End If
Next obj
End Sub
hello i tried to populate my listbox at my excel sheet but i had a hard time to put a right code in VBA.
as you can see in this picture the box that marked is my list box. and i have the data table in other sheet called "Data Barang" (sheet2) and i tried to show the data table to the listbox and when i double click the data at the listbox it will pull the selected data row to those text boxes above the listbox. The listbox name and the table name are same which is "DataBarang".
anyone have reference what code can work for my listbox?
there's the code i have tried
Private Sub Workbook_Open()
With Sheet1.DataBarang
.ColumnHeads = True
.ColumnCount = 14
.ListFillRange = Sheet2.ListObjects("DataBarang").Range.Select
End With
End Sub
-----------------------------------EDITED-----------------------------------
I have success to populate my listbox but it seems cannot filled the column heads. can anybody help me to fill those column heads?
here is my code that i used
Sub loaddata()
Dim listdata As Object
Set listdata = Sheet1.DataBarang
Dim tabeldata As Range
Set tabeldata = Sheet2.Range("DataBarang")
With listdata
.AutoLoad = True
.ColumnHeads = True
.ColumnCount = 14
.List = tabeldata.CurrentRegion.Value
End With
End Sub
You don't neeed to select the range - but have to pass the adress of the range as string (it always helps to read the documentation: https://learn.microsoft.com/en-us/office/vba/api/excel.controlformat.listfillrange
Private Sub Workbook_Open()
With Sheet1.DataBarang
.ColumnHeads = True
.ColumnCount = 14
.ListFillRange = Sheet2.ListObjects("DataBarang").DataBodyRange.Address(False, False, xlA1, True)
End With
End Sub
I create listbox in excel with VBA userform. Its values are obtained from the Sheet in Excel.
How can I delete the values in the sheet "database" while deleting the box list item?
please help me.
Private Sub UserForm_Initialize()
Dim ws As Worksheet
Dim rng As Range
Dim MyArray
Set ws = Sheets("Database")
Set rng = ws.Range("K2:L" & ws.Range("K" & ws.Rows.Count).End(xlUp).Row)
With Me.ListBox1
.Clear
.ColumnHeads = False
.ColumnCount = rng.Columns.Count
MyArray = rng
.List = MyArray
.ColumnWidths = "90;90"
.TopIndex = 0
End With
End Sub
Private Sub CommandButton2_Click()
For lItem = Me.ListBox1.ListCount - 1 To 0 Step -1
If ListBox1.Selected(lItem) Then
ListBox1.RemoveItem lItem
If Me.ListBox1.MultiSelect = fmMultiSelectSingle Then
Exit For
End If
End If
Next
End Sub
How do I delete the values in the sheet "database"?
As you assign database items via the array method (not using ControlSource), you want to know how to synchronize listbox items with your data base after manual deletion.
Approach A) - Write the entire Listbox1.List
If you want a mirror image of the listbox items after the For- Next loop, you could simply write these items back to a given range (of course you should clear 'surplus rows', too) via the following one liner
rng.Resize(Me.ListBox1.ListCount, 2) = Me.ListBox1.List
Instead of reduplicating the data range declaration in CommandButton2_Click, I'd suggest to declare it ONCE in the declaration head of the Userform code module (and omit it in Userform_Initialize):
Thus the complete code would be as follows:
â–ºAdditional notes due to comment
Insert these two code lines on top of your UserForm code module (and before any procedures).
Option Explicit is strictly recommended in any code to force the declaration of variable types (but you can't use this statement within a Sub as you did). The declaration Dim rng As Range OUTSIDE the other procedures (i.e. on top) allows that any procedure within this code module knows the rng variable.
Option Explicit ' declaration head of the UserForm module
Dim rng as Range ' ONE database declaration only!
' << OUTSIDE of following procedures
' << Start of regular procedures
Private Sub UserForm_Initialize()
Dim ws As Worksheet
' Dim rng As Range ' << not needed here, see top declaration
Dim MyArray
Set ws = Sheets("Database")
Set rng = ws.Range("K2:L" & ws.Range("K" & ws.Rows.Count).End(xlUp).Row)
With Me.ListBox1
.Clear
.ColumnHeads = False
.ColumnCount = rng.Columns.Count
MyArray = rng
.List = MyArray
.ColumnWidths = "90;90"
.TopIndex = 0
End With
End Sub
Private Sub CommandButton3_Click()
Dim lItem&
For lItem = Me.ListBox1.ListCount - 1 To 0 Step -1
If ListBox1.Selected(lItem) Then
ListBox1.RemoveItem lItem ' remove item from listbox
If Me.ListBox1.MultiSelect = fmMultiSelectSingle Then
Exit For
End If
End If
Next
rng.Offset(Me.ListBox1.ListCount, 0).Resize(rng.Rows.Count, 2) = "" ' clear rows
rng.Resize(Me.ListBox1.ListCount, 2) = Me.ListBox1.List ' write list back
End Sub
Note that no rows are deleted physically, the resulting listbox items in the two target columns K:L are shifted up only (approach B allows to delete entire rows as well).
Approach B) - Help procedure within main loop
Using the same data range declaration in the declaration head of the UserForm â–º as shown above (i.e. OUTSIDE the procedures as Subs or Functions), you could use a help procedure DelData allowing to distinguish between two principal cases:
[1] Shift up deleted cells in your database
[2] Delete the entire row
Event procedure CommandButton2_Click
Private Sub CommandButton2_Click()
' Purpose: delete items both from database and listbox
Dim lItem&
For lItem = Me.ListBox1.ListCount - 1 To 0 Step -1
If ListBox1.Selected(lItem) Then
DelData lItem, True ' [1] True=delete items and shift up
'DelData lItem, False ' [2] False=delete entire row
ListBox1.RemoveItem lItem ' remove item from listbox
If Me.ListBox1.MultiSelect = fmMultiSelectSingle Then
Exit For ' do it once in single select case
End If
End If
Next
End Sub
Help procedure DelData
Sub DelData(ByVal indx&, Optional ByVal bShiftUp As Boolean = True)
' Purpose: delete indicated row items in database
' Note: data set in OP includes header
If bShiftUp Then ' [1] bShiftUp = True: delete row items and shift up
rng.Offset(indx).Resize(1, rng.Columns.Count).Delete xlShiftUp
Else ' [2] bShiftUp = False: delete entire row of indicated items
rng.Offset(indx).Resize(1, rng.Columns.Count).EntireRow.Delete
End If
End Sub
Side note
It's recommended to fully qualify range references to avoid getting data from wrong workbooks, so I'd suggest the following statement in your UserForm_Initialize procedure:
Set ws = ThisWorkbook.Worksheets("Database")
Enjoy it :-)
Before removing the item from the ListBox you need to use the located value at the ListBox.Selected to find and remove the item from your "database".
Something like this:
Private Sub CommandButton2_Click()
For lItem = Me.ListBox1.ListCount - 1 To 0 Step -1
If ListBox1.Selected(lItem) Then
DeleteItemFromDatabase ListBox1.Selected(lItem).Value
ListBox1.RemoveItem lItem
If Me.ListBox1.MultiSelect = fmMultiSelectSingle Then
Exit For
End If
End If
Next
End Sub
Then your Sub DeleteItemFromDatabase(ByVal itemToDelete As [type]) would find itemToDelete in your "database" and remove it.
As an additional note, you may want to consider using Access as your database since it's actually designed to be one. I realize this isn't always possible, but thought I'd throw it out there as a thought for you.
I have to know, is this possible that the single combo box that had a lists from 2 different sheets by using option buttons. this works well. but the vlookup function is working for sheet 1 only not sheet 2.
explanation:
in my userform,
1 combobox = cmbbx1
2 option buttons = 1.hq 2.whs
2 textboxes = 1.txtbx1 2.txtbx2
When I click on the option button hq the list of sheet1 is shown in combobox. then another 2 textboxes already coded with Application.WorksheetFunction.Vlookup, so they're showing the given cell value.
but i can't make it work when i click on the option button whs. in this time combobox is showing the list from sheet2 but vlookup not working here.
here is the code what i get from another source for vlookup function.
Private Sub CmbBX1_AfterUpdate()
'Check to see if value exists
If WorksheetFunction.CountIf(Sheet2.Range("B:B"), Me.CmbBX1.Value) = 0 Then
MsgBox "Employee Not Registered"
Me.CmbBX1.Value = ""
Exit Sub
End If
'Lookup values based on control
With Me
.TxBx1 = Application.WorksheetFunction.VLookup(Me.CmbBX1, Sheet2.Range("Emp_ltl"), 2, 0)
.TxBx2 = Application.WorksheetFunction.VLookup(Me.CmbBX1, Sheet2.Range("Emp_ltl"), 3, 0)
End With
End Sub
This is the code I used for the Option buttons:
Option Explicit
Public myList As Variant
Private Sub hq_Click()
myList = ThisWorkbook.Worksheets("LTL").Range("Emp_ltl").Value
Me.CmbBX1.List = myList
End Sub
Private Sub whs_Click()
myList = ThisWorkbook.Worksheets("LTS").Range("Emp_ltS").Value
Me.CmbBX1.List = myList
End Sub
I believe something like the following will do it:
Private Sub CmbBX1_AfterUpdate()
If hq.Value = True Then 'check if hq is selected
Dim ws As Worksheets: Set ws = Worksheets("LTL") 'declare your worksheet and your range
Dim rng As Range: Set rng = ws.Range("Emp_ltl")
myList = ThisWorkbook.Worksheets("LTL").Range("Emp_ltl").Value
Me.CmbBX1.List = myList
ElseIf whs.Value = True Then 'if whs is selected
Dim ws As Worksheets: Set ws = Worksheets("LTS") 'declare and set your worksheet and range
Dim rng As Range: Set rng = ws.Range("Emp_ltS")
myList = ThisWorkbook.Worksheets("LTS").Range("Emp_ltS").Value
Me.CmbBX1.List = myLis
Else
MsgBox "No Option has been selected"
Exit Sub
End If
'Check to see if value exists
If WorksheetFunction.CountIf(ws.Range("B:B"), Me.CmbBX1.Value) = 0 Then
MsgBox "Employee Not Registered"
Me.CmbBX1.Value = ""
Exit Sub
End If
'Lookup values based on control
With Me
.TxBx1 = Application.WorksheetFunction.VLookup(Me.CmbBX1, rng, 2, 0)
.TxBx2 = Application.WorksheetFunction.VLookup(Me.CmbBX1, rng, 3, 0)
End With
End Sub
The idea was to create a variable that would save the changes made to it from previous use of the macro. I have a userform that pulls values from a range and populates unique values in a listbox. I then want to be able to add selected values to my dictionary/collection and save the change. Once all necessary changes have been made, the macro should use the dictionary variable as criteria for an autofilter.
My question is two fold, what class should I use to accomplish this? How can a use this variable to autofilter my worksheet? Userform code is below:
The First bit of code is for the "Add" command button. It is supposed to take the selected value(s) in the listbox and add them to the dictionary titled "Market". The code after that pulls the values from a recently opened excel workbook an displays unique values in the listbox. Listbox2 holds all previous values from past uses of the macro. I want to add a "Delete" button to the userform to tidy up the list if necessary. The two public variables below are actually located on the main macro module, this would allow me to store the values in the dictionary after the userform has stopped running.
Private Sub CommandButton1_Click()
Dim i As Long
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) = True Then
Market.Add ListBox1.List(i)
Set Market = New Collection
End If
Next
End Sub
Private Sub UserForm_Initialize()
Dim myList As Collection
Dim myRange As Range
Dim ws As Worksheet
Dim myVal As Variant
Dim Col As Integer
Set ws = ActiveWorkbook.Sheets("Daily Unconfirmed")
Col = WorksheetFunction.Match("Marketer", ws.Range("3:3"), 0)
Set myRange = ws.Range(Cells(4, Col), Cells(4, Col).End(xlDown))
Set myList = New Collection
On Error Resume Next
For Each mycell In myRange.Cells
myList.Add mycell.Value, CStr(mycell.Value)
Next mycell
On Error GoTo 0
For Each myVal In myList
Me.ListBox1.AddItem myVal
Next myVal
Public item As Variant
Public Market As Collection
Market.Add "Al D"
Market.Add "B Collins"
Market.Add "B G"
Market.Add "C Huter"
For Each item In Market
Me.ListBox2.AddItem item
Next item
End Sub
Since AutoFilter runs from an array, I would build the array dynamically and use it in a filtering sub:
Dim ary()
Sub MAIN()
Call BuildDynamicArray
Call FilterMyData
End Sub
Sub BuildDynamicArray()
Dim inString As String
i = 1
While 1 = 1
x = Application.InputBox(Prompt:="Enter a value", Type:=2)
If x = False Then GoTo out
ReDim Preserve ary(1 To i)
ary(i) = x
i = i + 1
Wend
out:
End Sub
Sub FilterMyData()
ActiveSheet.Range("$A$1:$A$10").AutoFilter Field:=1, Criteria1:=ary, Operator:=xlFilterValues
End Sub