How to use SpinButton in a condition - vba

I have a spin button and a two list boxes. i have set the min and max of spin button. I already have a button which moves data from list box1 to listbox2.But i want to set a limit for moving the data based on spin button.
example:
if value in spin button is 2, then only 2 items can be added to listbox2
note:i have linked the spin button to a textbox

Declare a variable and then every time you move an item, increment the value of the variable by 1. So next time when you click the button to move the item, simply compare the value of the variable with the SpinButton's Value. For example (Untested)
Dim nMoved As Long
Private Sub CommandButton1_Click()
If nMoved < (VAL(TextBox1.Text) + 1)
'
'~~> Code to move items from LB1 to LB2
'
nMoved = nMoved + 1
Else
MsgBox "Max items that can be moved from LB1 to LB2 reached."
End If
End Sub
FollowUp from Comments
You need to use .ListCount in your case only if you are matching the items count in the LB against the TB. What I understood from your post is a user shouldn't be able to move more items into the LB than what is specified in the TB. Anyways, it seems that your query is sorted.
Regarding your 2nd comment.
You need to loop through the LB items using the code below and then exit the loop if the counter is equal to the TB value. For example
For i = 0 To (ListBox1.ListCount - 1)
If i = (Val(TextBox1.Text) - 1) Then Exit For
'
'~~> Code to move items from LB1 to LB2
'
End If
Next i

Thanks you all.. finally i got the answer
Dim ct As Integer
Dim ictr As Long
Dim jctr As Integer
jctr = CInt(Me.TextBox1.Value)
If jctr = ListBox2.ListCount Then
MsgBox "Maximum limit has been reached. You cannot add more players"
Exit Sub
End If
For ictr = jctr To 1 Step -1
Me.ListBox2.AddItem Me.ListBox1.List(ictr)
Me.ListBox1.RemoveItem ictr
Next ictr

Related

Listbox.List(i) error - Method or Data Member not Found

I'm trying to use a multi-select listbox so users can select cleaning tasks they have completed and mark them as done. While looping through the list I want to see if the item is selected and create a record if so. When I try to use the .List method to return the data from a specific row, I keep getting the method not found error.
I originally did not have the forms 2.0 library loaded so I thought that was the issue, but that did not resolve the problem. I've also compacted and repaired thinking it might just be an odd fluke, but that did not help either.
'loop through values in listbox since its a multi-select
For i = 0 To listCleaningTasks.ListCount - 1
If listCleaningTasks.Selected(i) Then
'add entry to cleaning log
Set rsCleaning = CurrentDb.OpenRecordset("SELECT * FROM cleaning_log;")
With rsCleaning
.AddNew
.Fields("cleaning_task_id") = Form_frmCleaning.listCleaningTasks.List(i)
.Fields("employee_id") = Me.cmbUser
.Fields("cleanroom_id") = Me.cmbCleanroom
.Fields("cleaning_time") = Now()
.Update
.Close
End With
End If
Next i
Any ideas?
Use .listCleaningTasks.ItemData(r) to pull bound column value from row specified by index.
Use .listCleaningTasks.Column(c, r) to pull value specified by column and row indices.
Open and close recordset only one time, outside loop.
Really just need to loop through selected items, not the entire list.
Dim varItem As Variant
If Me.listCleaningTasks.ItemsSelected.Count <> 0 Then
Set rsCleaning = CurrentDb.OpenRecordset("SELECT * FROM cleaning_log")
With rsCleaning
For Each varItem In Me.listCleaningTasks.ItemsSelected
`your code to create record
...
.Fields("cleaning_task_ID") = Me.listCleaningTasks.ItemData(varItem)
...
Next
.Close
End With
Else
MsgBox "No items selected.", vbInformation
End If
Of course the solution of June7 is correct. If you need to store the selected items and then later recall and re-select the list box items, consider to get the selected items comma delimited using this function
Public Function GetSelectedItems(combo As ListBox) As String
Dim result As String, varItem As Variant
For Each varItem In combo.ItemsSelected
result = result & "," & combo.ItemData(varItem)
Next
GetSelectedItems = Mid(result, 2)
End Function
Store it into one column of a table and after reading it back pass it to this sub:
Public Sub CreateComboBoxSelections(combo As ListBox, selections As String)
Dim N As Integer, i As Integer
Dim selectionsArray() As String
selectionsArray = Split(selections, ",")
For i = LBound(selectionsArray) To UBound(selectionsArray)
With combo
For N = .ListCount - 1 To 0 Step -1
If .ItemData(N) = selectionsArray(i) Then
.Selected(N) = True
Exit For
End If
Next N
End With
Next i
End Sub
This will select items in your ListBox as they were before.

DataGridView looping from bottom up

When I run code below, the selected row returned is always from the bottom up. How can I get it to loop from the top of the Data Grid table each time?
'Find the selected customer by code. Display closest match in grid.
Dim targetString As String = txtAccountCode.Text
For Each row As DataGridViewRow In frmCustomerLookUp.GSCUSTDataGridView.Rows
If row.Cells(0).Value.ToString().StartsWith(targetString) Then
frmCustomerLookUp.GSCUSTDataGridView.ClearSelection()
frmCustomerLookUp.GSCUSTDataGridView.Rows(row.Index).Selected = True
frmCustomerLookUp.GSCUSTDataGridView.FirstDisplayedScrollingRowIndex = frmCustomerLookUp.GSCUSTDataGridView.SelectedRows(0).Index
Dim selectedIndex = frmCustomerLookUp.GSCUSTDataGridView.SelectedRows(0).Index
frmCustomerLookUp.GSCUSTDataGridView.Rows(selectedIndex).Selected = True
frmCustomerLookUp.GSCUSTDataGridView.Rows(selectedIndex).Cells(0).Selected = True
Exit Sub
End If
Next
Use a For...Next loop, starting at the last row and stepping -1
For index As Integer = frmCustomerLookUp.GSCUSTDataGridView.Rows.Count - 1 To 0 Step -1 ' Or Count -2
If frmCustomerLookUp.GSCUSTDataGridView.Rows(index).Cells(0).Value.ToString().StartsWith(targetString) Then
As the other person said. (Just a bit shorter)
For x=frmCustomerLookUp.GSCUSTDataGridView.Rows.Count - 1 To 0 Step -1
if frmCustomerLookUp.GSCUSTDataGridView(0,x).ToString().StartsWith(targetString) then
'something
end if
next

vba excel If condition error on final iteration

I'm having the code takes the input from my checkboxes and grab data from the related worksheet. I ran it line by line and found out that it always gets a runtime error at the If statement on the final loop. Is there something wrong in my code?
Option Explicit
Private Sub UserForm_Initialize()
Dim counter As Long
Dim chkBox As MSForms.CheckBox
''''Add checkboxes based on total sheet count
For counter = 1 To Sheets.count - 2
Set chkBox = Me.Frame1.Controls.Add("Forms.CheckBox.1", "CheckBox" & counter)
chkBox.Caption = Sheets(counter + 2).Name
chkBox.Left = 10
chkBox.Top = 5 + ((counter - 1) * 20)
Next
End Sub
Private Sub cmdContinue_Click()
Dim Series As Object
Dim counter As Long
'''Clear old series
For Each Series In Sheets(2).SeriesCollection
Sheets(2).SeriesCollection(1).Delete
Next
''Cycle through checkboxes
For counter = 1 To Sheets.count - 2
''If the box is checked then
If Me.Frame1.Controls(counter).Value = True Then ''Error here on 4th iteration
''Add new series
With Sheets(2).SeriesCollection.NewSeries
.Name = Sheets(counter + 2).Range("$A$1")
.XValues = Sheets(counter + 2).Range("$A$12:$A$25")
.Values = Sheets(counter + 2).Range("$B$12:$B$25")
End With
End If
Next counter
Me.Hide
End Sub
Also, a second problem is it always run on the wrong loop. If i check box 2 it'll run data for the box 1 sheet, 3 run for 2, 4 run for 3, and 1 run for 4. Can anyone explain the reason behind this?
EDIT: So as VincentG point out below, adding an explicit name "checkbox" in there did the trick (i didn't know you could do that). Index 1 was probably taken by one of the buttons or the frame in the user form, causing it to get off set.
I guess your main problem comes from the fact that the controls have to be accessed starting from index 0. So to loop over all controls, you would do something like
For counter = 0 To Me.Frame1.Controls.Count - 1
Debug.Print counter; Me.Frame1.Controls(counter).Name
Next counter
So, when you stick to you code, I assume you have to change the if-statement to
If Me.Frame1.Controls(counter-1).Value = True Then

How do I loop through a DataGridView where RowCount / Rows.Count changes

I have a VB.Net Form with a DataGridView where I wish to change between a Detailed View and a General View.
The DataGridView shows the Distance and Estimated Time between places - called the Route Leg Data and is termed the General View
I have implemented a CheckBox to select between the general and detailed view. When the CheckBox is Checked, I am trying to loop through all of the Route Leg entries and insert the Route Steps which is the Detailed information about the Leg entries.
I have tried various loop options: For..Next, For Each...Next, While...End While, and only the first row (Route Leg) gets processed, even if I have 5 more Route Leg entries.
Important: Keep in mind that when the Detail View is selected, the DataGridView row count increments for every new Route Step entry that gets inserted.
I tried to use both dgv.RowCount and dgv.Rows.Count but I keep getting the same result.
I have added some code to show what I am trying to achieve. Any help or guidance will be much appreciated.
'Show / Hide Route Step Data
Private Sub chkShowRouteStep_CheckedChanged(sender As Object, e As EventArgs) Handles chkShowRouteStep.CheckedChanged
Try
If chkShowRouteStep.Checked Then
'Show Route Steps
For i As Integer = 0 To dgvQuote.RowCount - 1
txtRowCount.Text = i
If dgvQuote.Rows(i).Cells(0).Value.ToString <> "" Then
For j As Integer = 1 To 5
i += 1
dgvQuote.Rows.Insert(i, "Step")
'dgvQuote.Rows.Insert(j + i, "Step")
Next
End If
Next
Else
'Hide Route Steps - WORKS GREAT
For i As Integer = dgvQuote.RowCount - 1 To 0 Step -1
If dgvQuote.Rows(i).Cells(0).Value.ToString = "Step" Then
dgvQuote.Rows.RemoveAt(i)
End If
Next
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
My impatience, as well as a refocus, provided me with the answer.
My focus was always on the DataGridView and the feedback from it with regards to the number of rows contained in the control.
However, the execution of a loop took a snapshot of the number of rows at the start of the loop execution and did NOT update the number of rows every time rows were added to the DataGridView.
I took a different approach where I compared my current loop number (i += 1) with the current number of rows in the DataGridView (dgv.Rows.Count - 1) thereby forcing a recheck on the number of rows. This means that any new rows added to the DataGridView will now be counted in.
I added a trigger (True/False) to be set to true if the last row in the DataGridView was reach and the While...End While loop was exited.
'Show / Hide Route Step Data
Private Sub chkShowRouteStep_CheckedChanged(sender As Object, e As EventArgs) Handles chkShowRouteStep.CheckedChanged
Try
Dim lastRow As Boolean = False 'This will get set when we have reached the last row in the DGV
Dim i As Integer = 0
If chkShowRouteStep.Checked Then
'Show Route Steps
While lastRow <> True
txtRowCount.Text = i
If dgvQuote.Rows(i).Cells(0).Value.ToString <> "" Then
For j As Integer = 1 To 2
'i += 1
dgvQuote.Rows.Insert(i + j, "", "Step")
Next
End If
'Check to see if we have reached the last row, set lastRow to TRUE if it is the last row
If i = dgvQuote.Rows.Count - 1 Then
lastRow = True
End If
i += 1
End While
Else
'Hide Route Steps - WORKS GREAT
For x As Integer = dgvQuote.RowCount - 1 To 0 Step -1
If dgvQuote.Rows(x).Cells(1).Value.ToString = "Step" Then
dgvQuote.Rows.RemoveAt(x)
End If
Next
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
The result is as follows and error free:
Before
After
Since the comment in the code says you want to hide route steps, why not do just that? Instead of removing and inserting rows, populate the grid with everything and then use the checkbox to set the rows .Visible property?

Index out of range in listbox VB.NET

Consider the following code :
Private Sub DelButton_Click(sender As Object, e As EventArgs) Handles DelButton.Click
If OrderListBox.Text = "" = False Then
For i As Integer = OrderListBox.SelectedIndex To arr.Count - 1
arr.RemoveAt(i)
Next
OrderListBox.Items.Remove(OrderListBox.SelectedItem)
End If
calculate()
End Sub
The program crashes at arr.RemoveAt(i) and displays the following error:
Index was out of range. Must be non-negative and less than the size
of the collection.
First of all, please note that in VB.NET and C#, FOR loops are implemented differently!
In VB.NET, it works like this:
BEFORE the loop starts, you are determining start and end of the loop:
Start = OrderListBox.SelectedIndex
End = arr.Count-1
Then, the loop starts.
It is important to know, that in VB.NET, the end of the loop is NOT calculated again anymore. This is an important difference to C#. In C#, the end of the loop is calculated before each single loop.
And now, in the loop, you are DELETING records from the array.
Therefore, the count of records in the array is DECREASING.
However, your loop is going on, since you have calculated the count of records in the array before the loop started.
Therefore, you are going beyond the range of the array.
You could rewrite your code as follows:
Dim i as Integer
i = OrderListBox.SelectedIndex
while i < arr.Count
arr.RemoveAt(i)
Next
This article covers details about the for loop in VB.NET, especially the section "Technical Implementation": https://msdn.microsoft.com/en-us/library/5z06z1kb.aspx
This error will be thrown when you try to remove an item at an index greater than the size of the collection. i.e when i is greater than arr.Count - 1.
You should make sure that OrderListBox.SelectedIndex is not greater than arr.Count - 1. Because if it does, you remove an item that, well, does not exists.
This code is actually displayed in the MSDN docs. As stated, you should do something like this:
Private Sub RemoveTopItems()
' Determine if the currently selected item in the ListBox
' is the item displayed at the top in the ListBox.
If listBox1.TopIndex <> listBox1.SelectedIndex Then
' Make the currently selected item the top item in the ListBox.
listBox1.TopIndex = listBox1.SelectedIndex
End If
' Remove all items before the top item in the ListBox.
Dim x As Integer
For x = listBox1.SelectedIndex - 1 To 0 Step -1
listBox1.Items.RemoveAt(x)
Next x
' Clear all selections in the ListBox.
listBox1.ClearSelected()
End Sub 'RemoveTopItems
ListBox.SelectedIndex will return a value of negative one (-1) is returned if no item is selected.
You didn't check it in your code.
Change your code to this:
If OrderListBox.SelectedIndex >= 0 And OrderListBox.Text = "" = False Then
EDIT
Your code is this:
For i As Integer = OrderListBox.SelectedIndex To arr.Count - 1
arr.RemoveAt(i)
Next
Let's say your OrderListBox contains 3 items : [A, B, C] and the SelectedIndex is 0
Then your code will:
Remove (0) ===> [B, C]
Remove (1) ===> [B]
Remove (2) ===> Exception!
You need to reverse the loop
For i As Integer = arr.Count - 1 To OrderListBox.SelectedIndex Step -1
arr.RemoveAt(i)
Next