VB.NET: Passing variable between forms, error - vb.net

I want to pass the value of an exact variable to another form...
To be more precise I'm building a game in which a player answer a few questions so I want to pass the variable that contains the correct answer to another form which works as the end game window and displays the score... I'm using this kind of code in the end game window:
Public Class Form2
Public Property CCount As Integer
Private Sub Form5_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = CCcount
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CCount = 0
Form1.Show()
Me.Close()
End Sub
End class
And this in the main form:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Lines of code
Form2.CCount +=1
'Lines of code
'Me.Hide()
'Form2.Show()
EndSub
The first time that I'm "playing the game" everything works fine, but if try to replay it the displaying scores never changes... It remains the same as the first run..
Any ideas how I can fix this out?

You assign value of CCount to the Label only ones when form was loaded.
Load event raised only one time.
Put label updating code inside CCount Property Setter
Private _CCount As Integer
Public Property CCount As Integer
Get
Return _CCount
End Get
Set (value As Integer)
If _CCount = value Then Exit Property
_CCount = value
Me.Label1.Text = _CCount.ToString()
End Set
End Property

Related

Having trouble with a lottery software

sorry to come in here like this looking for answers, but im actually really stumped. Im supposed to make an application using 2 forms, one to generate its own array and store user entered numbers into another array, and then display them on the second form and tell you how many of the numbers are in common
I cant get the numbers to show up on the second form at all, and I also cant really understand how to get how many numbers are matching, but I will when I can reference them properly in form 2. I got the arrays set up perfectly, but I cant even call the numbers from them to form 2. I need help calling the arrays from the first form to display on the next
Form 1 code
Public Class Form1
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Shared random As New Random()
Dim UserArray(4) As String
Dim LotteryArray(4) As String
Public Sub btnCheck_Click(sender As Object, e As EventArgs) Handles btnCheck.Click
If txtNumbers.Text <> "" Then
For i As Integer = 0 To 4
If UserArray(i) = "" Then
UserArray(i) = txtNumbers.Text
End If
Next
End If
For n As Integer = 0 To 9
Dim RandomNumber As Integer = CInt(Int(Rnd() * 5) + 1)
LotteryArray(4) = CStr(RandomNumber)
Next
End Sub
End Class
Form 2 Code
Public Class Form2
Public Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
lblUser1.Text = Form1.UserArray(0)
lblUser2.Text = Form1.UserArray(1)
lblUser3.Text = Form1.UserArray(2)
lblUser4.Text = Form1.UserArray(3)
lblUser5.Text = Form1.UserArray(4)
lblRand1.Text = Form1.LotteryArray(0)
lblRand2.Text = Form1.LotteryArray(1)
lblRand3.Text = Form1.LotteryArray(2)
lblRand4.Text = Form1.LotteryArray(3)
lblRand5.Text = Form1.LotteryArray(4)
If Form1.LotteryArray(4) = Form1.UserArray(4) Then
MessageBox("CONGRATULATIONS!", "You Are The GRAND PRIZE WINNER!")
End If
Me.Close()
End Sub
End Class
I will address your first question. How to get your numbers into your second form.
You main problem is the Access modifier you used for your arrays. Dim is the equivalent of Private which means that the variable is only visible within the class. Friend is visible anywhere in the assembly. See https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/access-levels for more information. Don't change your event procedure Access to Public.
You have to let the user fill in another guess. The first loop in the Check button will only enter the same input 5 times. You need one entry on every click but you need to keep track of where you are in the array. Private NumberOfGuesses As Integer Note that this variable is Private. It doesn't need to be seen outside of the Form1 class.
We don't need to refill the LotteryArray on every click so I did it once in the Form.Load You were trying to use the Random class the way you use the old vb6 Random. The .net class is much easier.
To display the arrays on Form2, I used list boxes and loops. Saved a bit of typing.
If you still have a question about part 2 of your problem post another question. Show what you have tried.
Public Class Form1
Private random As New Random()
Friend UserArray(4) As Integer
Friend LotteryArray(9) As Integer
Private NumberOfGuesses As Integer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For n As Integer = 0 To 9
Dim RandomNumber As Integer = random.Next(0, 10)
LotteryArray(n) = RandomNumber
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If NumberOfGuesses > 4 Then
MessageBox.Show("You have used up your guesses")
Form2.Show()
Me.Close()
End If
If TextBox1.Text <> "" Then
UserArray(NumberOfGuesses) = CInt(TextBox1.Text)
NumberOfGuesses += 1
TextBox1.Clear()
TextBox1.Focus()
End If
End Sub
End Class
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each number In Form1.UserArray
ListBox1.Items.Add(number)
Next
For Each number In Form1.LotteryArray
ListBox2.Items.Add(number)
Next
End Sub
End Class

Interact with form while working in the background

The goal is that the form should still be clickable while the code runs (mainly to be able to break the code) AND keeps getting updated by the running code at the same time. First part works, not the second part.
Public Class FormMain
Public PleaseStopAll As Boolean
Private Sub BreakCode_Click(sender As Object, e As EventArgs) Handles BreakCode.Click
PleaseStopAll = True
End Sub
Private Sub Testeur_Click(sender As Object, e As EventArgs) Handles Testeur.Click
PleaseStopAll = False
ThreadPool.QueueUserWorkItem(AddressOf LaunchTask, 0)
End Sub
Sub LaunchTask(o As Object)
TheTask(Me)
End Sub
Public Sub ShowSomeMessage(msg As String
Me.Displayer.text = msg
End Sub
End Class
Module TaskDoer
Sub TheTask(MyMenu As FormMain)
For i As Integer = 0 To 42
whatever() 'some tasks that cannot be interrupted safely
MyMenu.ShowSomeMessage("task #" & CStr(i) & " over") ' Here is the error
If MyMenu.PleaseStopAll Then Exit For
Next
End Sub
End Module
The "status update" line tells that this task cannot interact with its parent task.
If I remove this line, the code runs just fine : code breaks when I ask to, and form remains clickable.
I tried with BackgroundWorker, but it needs actual progression to report something with ReportProgress (in increasing %) do I cannot just give a status (as string)
Pass anything else via a variable or structure
BackgroundWorker1.WorkerReportsProgress = True '<Make sure this is set
BackgroundWorker1.RunWorkerAsync()
Private SomeStatus As String
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
SomeStatus = "Hello"
BackgroundWorker1.ReportProgress(0)
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ShowSOmeMEssage(SomeStatus)
End Sub
FYI: The progress thing is only so you can call a routine on the main UI thread. You can set as many thread-safe variables as you want on the form from within the backgroundworker. It's just updating the UI that's bothersome, though there is a workaround for that too.

Custom Textbox Zoom - Return text to active datagridview cell?

I have 2 Datagridview controls in same form. Each Datagrid has some columns where user will write long texts, so I designed form with RichTextBox that opens when user double-clicks these columns to enlarge text-entry. Code works, but I want to use same form for both Datagrids, so I should somehow return text to active datagridview cell. Here is my code (for Datagridview1):
TextZoomForm:
Public Class TextZoomForm
Public OpenedForm1 As New Form1
Private Sub RichTextBox1_DoubleClick(sender As Object, e As EventArgs) Handles RichTextBox1.DoubleClick
OpenedForm1.DataGridView1.CurrentCell.Value = RichTextBox1.Text
OpenedForm1.Label24.Focus()
Me.Close()
End Sub
Private Sub TextZoom_Load(sender As Object, e As EventArgs) Handles Me.Load
RichTextBox1.Text = OpenedForm1.DataGridView1.CurrentCell.Value
End Sub
End Class
DataGridView1_CellMouseDoubleClick in Form1:
Private Sub DataGridView1_CellMouseDoubleClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
If e.ColumnIndex = 1 Then
Dim cp = Cursor.Position
cp.Y += CInt(Cursor.Size.Height * (-0.5))
cp.X += CInt(Cursor.Size.Width * 0.8)
Dim f As New TextZoomForm()
f.OpenedForm1 = Me
f.Show()
f.Location = New Point(cp)
End If
End Sub
Any ideas on how to return text to active datagridview cell?
Change your zoomed form so that it doesn't know where its data comes from. Instead the control using it will pass the data.
Public Class TextZoomForm
Public Property ZoomedText As String
Get
Return RichTextBox1.Text
End Get
Set(value As String)
RichTextBox1.Text = value
End Set
End Property
Private Sub RichTextBox1_DoubleClick(sender As Object, e As EventArgs) Handles RichTextBox1.DoubleClick
Me.Close()
End Sub
End Class
To call the form change your code to the following:
Private Sub DataGridView1_CellMouseDoubleClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
...
Dim f As New TextZoomForm()
f.ZoomedText = DataGridView1.CurrentCell.Value
f.ShowDialog()
'Great breakpoint location.
DataGridView1.CurrentCell.Value = f.ZoomedText
Label24.Focus()
....
End Sub
Using ShowDialog prevents the user from changing the current cell part way through your call.
If you need it modeless then you should:
store the cell that the user has selected
handle the FormClosing event.
Test the DialogResult to make sure the user pressed ok
write the data back to the stored cell.

textbox on form within form not updating

I'm trying to understand more about VB.NET and Multiple forms so I can make my code better.
I have a SQL database table that holds the live data for all 14 processes, the monitor program updates a form showing the progress of all the processes. Years ago in MS Access I would have simply used a rolling subform to show the contents of the table.
However, my first attempt in VB.NET is to have "many" textboxes, basically 14 lines of textboxes and my code has 14 very similar parts updating all the textboxes. There has to be a better way :(
For Example:
txtProcessID1.Text TxtStatus1.Text ProgressBar1 ......
txtProcessID2.Text TxtStatus2.Text ProgressBar2 ......
txtProcessID3.Text TxtStatus3.Text ProgressBar3 ......
So, I'm trying to come up with a code where I create a SubForm that looks like one controller line, then create 14 instances of this subform on my mainform.
My test code seems to work but the textboxes on the subforms are not updating the contents on screen!! Even though when I call back the contents of .text it is what I expect.
Why does this example code not work, and is my solution the best way to complete this?
Public Class MainForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SubForm.SetText = Me.TextBox1.Text ' Try to change contents of a TextBox on the SubForm
Me.TextBox2.Text = SubForm.SetText ' Data comes back as expected, but the subform textbox remains unchanged.
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim objSubForm As New SubForm()
objSubForm.TopLevel = False
Me.Panel1.Controls.Add(objSubForm)
objSubForm.Show()
End Sub
End Class
Public Class SubForm
Public Property SetText() As String
Get
SetText = TextBox1.Text
End Get
Set(ByVal Value As String)
Me.TextBox1.Text = Value ' Control is not updated of the SubForm.
Debug.Print("Value = " & Value) ' The Value is Passed Correctly.
Debug.Print("Text = " & TextBox1.Text) ' And the property of the control has been updated.
End Set
End Property
End Class
Many Thanks
Kev
In your button click you are referencing the class name SubForm, this in VB.NET is called as the default automatic instance of a form, but this is not the same instance that you display in your Form_Load. Here you create a different instance called objSubForm and this is the instance that you display.
To fix you need to keep the objSubForm as a global instance and refer to this global when you click
Public Class MainForm
Dim objSubForm As SubForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
objSubForm.SetText = Me.TextBox1.Text ' Try to change contents of a TextBox on the SubForm
Me.TextBox2.Text = objSubForm.SetText ' Data comes back as expected, but the subform textbox remains unchanged.
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
objSubForm = New SubForm()
objSubForm.TopLevel = False
Me.Panel1.Controls.Add(objSubForm)
objSubForm.Show()
End Sub
End Class
Keep in mind that after this change you are responsible to effectively close and dispose the global instance.
Private Sub Form1_FormClosed(sender as Object, e as FormClosedEventArgs) _
Handles Form1.FormClosed
if objSubForm IsNot Nothing
objSubForm.Close
End If
objSubForm = Nothing
End Sub
Thanks Steve, I applied the new code in just half an hour based on your fix.
Here's a basic example of my code that gives me 14 subforms I can update.
I've moved away from creating a property in the subform in favour of directly updating the TextBox control.
The solution has given me "MUCH" less code and now I can add another detail to the one subform and show that for all processes.
Thanks Again!
Kev
Public Class MainForm
Dim objSubForm(14) As SubForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Update the 14 forms
For n = 0 To 13
objSubForm(n).TextBox1.Text = Me.TextBox1.Text & " " & n
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' create 14 subforms
For n = 0 To 13
objSubForm(n) = New SubForm()
objSubForm(n).TopLevel = False
Me.Panel1.Controls.Add(objSubForm(n))
objSubForm(n).Location = New Point(0, 20 * n)
objSubForm(n).Show()
Next
End Sub
Private Sub MainForm_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
' CLear up
If objSubForm IsNot Nothing Then
For n = 0 To 13
objSubForm(n).Close()
Next
End If
For n = 0 To 13
objSubForm(n) = Nothing
Next
End Sub
End Class

How to return selected item on listbox on the second form to the main form in visual basic?

So basically you have a main form that shows only a label (lblTotalPrice) and a button that when you click it, it opens a second form that contains a listbox with different prices packages (lstPackages). How do do you select an item from lstPackages that is on the second form and return it to lblTotalPrice, which is located on the main form?
I attempted this code using a function (thought it would be useful for calculations), but it seems like it didn't work:
On my second form, I populated the lstPackages with it's name using parallel arrays:
Dim strPackages As String = {"Package 1", "Package 2", "Package 3", "Package 4", "Package 5"}
Dim decPrice As String = {100D, 200D, 300D, 400D, 500D}
Private Sub SecondForm_Activated(sender As Object, e As EventArgs) Handles MyBase.Activate
Dim frmMain as New
Dim i As Integer
For i = 0 To strPackages.Length - 1
lstPackages.Items.Add(strPackages(i))
Next
End Sub
After I tried to select a value on lstPackages, but I just was not too sure if I was using the right code to select the item and return it to the main form:
Function CalcPackage()
Dim decPackages As Decimal = 0D
If lstPackages.SelectedIndex = -1 Then
MessageBox.Show("Select a package")
Else
For i = 0 To lstPackages.SelectedItem - 1
decPackages = lstPackages.SelectedItem(i)
Next i
End If
Return decPackages
End Function
When I have selected the item in the lstPackages, I tried to send the selected item back to the main form, but ran into a problem here:
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
Dim frmMainForm As New MainForm
Dim decTotal As Decimal
decTotal = CalcPackage()
'I was stuck in this part and wasn't sure how to return it to lblTotalPrice (and also close the second form too)
frmMainForm.lblTotalPrice.Text = decTotal.ToString("c")
frmMainForm.Show()
Me.Close()
End Sub
So yea sorry if my code is weird, but I'm hoping to get help on how to return the value of the item to lblTotalPrice on the main form, thanks guys
Part of your problem is that you are newing up an instance of the main form in the button exit click event handler of the second form, as shown in this code posted:
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
Dim frmMainForm As New MainForm
Dim decTotal As Decimal
decTotal = CalcPackage()
'I was stuck in this part and wasn't sure how to return it to lblTotalPrice (and also close the second form too)
frmMainForm.lblTotalPrice.Text = decTotal.ToString("c")
frmMainForm.Show()
Me.Close()
End Sub
Instead pass an instance of the main form to the second form via its constructor, like this:
Public Class SecondForm Inherits Form
Dim theMainForm As MainForm
Public Sub New(mainForm As MainForm)
theMainForm = mainForm
End Sub
End Class
Now you can reference the lblTotalPrice in the MainForm class via the theMainForm variable, like this:
theMainForm.lblTotalPrice.Text = lstPackages.SelectedItem
The theMainForm.lblTotalPrice.Text should only be updated in response to an item being selected from lstPackages not when the second form is closed; so handle the updating of the main form's label in the SelectedIndexChanged event of lstPackages, like this:
Protected Sub lstPackages_IndexChanged(sender As Object, e As EventArgs)
Dim decTotal As Decimal
decTotal = CalcPackage()
theMainForm.lblTotalPrice.Text = decTotal.ToString("c")
End Sub
All the exit button click event handler should do is to show the main form and close the second form, like this:
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
theMainForm.Show()
Me.Close()
End Sub
Just display SecondForm with ShowDialog(), then retrieve the value with the reference to it that you already have:
Public Class MainForm
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim sf As New SecondForm
If sf.ShowDialog = Windows.Forms.DialogResult.OK Then
lblTotalPrice.Text = sf.TotalPrice
End If
End Sub
End Class
Over in SecondForm:
Public Class SecondForm
Private _TotalPrice As Decimal
Public ReadOnly Property TotalPrice As Decimal
Get
Return _TotalPrice
End Get
End Property
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnClose.Click
If lstPackages.SelectedIndex = -1 Then
MessageBox.Show("Select a package")
Else
_TotalPrice = lstPackages.SelectedItem(0)
Me.DialogResult = Windows.Forms.DialogResult.OK
End If
End Sub
End Class