How to only accept certain values inside a textbox - vb.net

I made a flashcard application where the user can change the difficulty by entering a number inside a textbox.
Sub UpdateDifficultyLevel(front As String, difficulty As Integer)
'The parameters are represented by question marks in the query
Dim sql = "UPDATE flashcards SET difficulty = ?
WHERE Front = ?"
'This using statement The Using statement makes sure that any "unmanaged resources" are released after they've been used.
Using conn As New OleDbConnection("provider=microsoft.ACE.OLEDB.12.0;Data Source=flashcard login.accdb"), 'Establish connection
cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add("#difficulty", OleDbType.Integer).Value = difficulty 'Updates database with parameters
cmd.Parameters.Add("#front", OleDbType.VarWChar).Value = front 'Updates database with parameters
conn.Open() 'Opens connection
cmd.ExecuteNonQuery() 'Executes
End Using
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
Dim difficulty As Integer 'Sets difficulty as integer
If Integer.TryParse(TxtDifficulty.Text, difficulty) Then
Dim front = txtFront.Text 'Defines front as variable which is equal to txtfront.text
UpdateDifficultyLevel(front, difficulty) 'Calls subroutine
Else
MsgBox("Please enter a number between 1 and 3") ' tells user that the difficulty must be a number
End If
End Sub
This works where the user can only enter an integer but how would I make it so they can only enter an integer between 1 and 3

You can utilize ErrorProvider to feedback to the user that the input is wrong. And reuse the validate function to get the parsed integer when used (so the logic is only in one place)
Private errorMessage As String = "Please enter a number between 1 and 3"
Private Function validateInput(ByRef difficulty As Integer) As Boolean
Return Integer.TryParse(TxtDifficulty.Text, difficulty) AndAlso difficulty >= 1 AndAlso difficulty <= 3
End Function
Private Sub TxtDifficulty_TextChanged(sender As Object, e As EventArgs) Handles TxtDifficulty.TextChanged
If Not validateInput(Nothing) Then
ErrorProvider1.SetError(TxtDifficulty, errorMessage)
TxtDifficulty.SelectAll()
Else
ErrorProvider1.SetError(TxtDifficulty, "")
End If
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
Dim difficulty As Integer 'Sets difficulty as integer
If validateInput(difficulty) Then
Dim front = txtFront.Text 'Defines front as variable which is equal to txtfront.text
UpdateDifficultyLevel(front, difficulty) 'Calls subroutine
Else
MsgBox(errorMessage) ' tells user that the difficulty must be a number
End If
End Sub
There are many other, possibly better, ways to do this however, but this sticks with your current design.

Use a NumericUpDown control instead, with its Increment set to 1, MinValue set to 1 and MaxValue set to 3. It looks just like a textbox and, bonus, you can change the number within using the arrow keys
You can also consider a MaskedTextBox, RadioButtons, ComboBox, ListBox, even 3 different buttons to start an Easy, Medium or Hard game..
A big part of effective UI design is in using tools designed for purpose and not bothering the user with an endless succession of error messages that they have to read, understand and apply corrections for. A great example of that gone wrong is a cellphone with a Symbian OS; they were renown for bothering the user with incessant messages.
If you have an opportunity to design a UI so the user simply can't get it wrong, rather than shouting at them when they do, take it; your iPhone doesn't present a Qwerty keyboard when you're dialling a number..

Related

How do I get the textbox to enable after a certain amount of text is inputted?

So my next question(i know i know ive had a lot of questions already but im learning and my teachers suck)
but I am trying to get the textbox to go to readonly after a certain amount of text has been entered. I know how to make it a read only textbox but only after Ive had one set of data entered. i need it to be readonly after 7 days of data has been entered
I've tried inputtextbox.enabled = false
'Validating if user input is a number or not
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
InputTextbox.Text = String.Empty
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
InputTextbox.Text = String.Empty
End If
InputTextbox.Enabled = False
I'm expecting it to disable after the user has entered 7 days worth of data but it only disables after one day of data is entered
Since the entries to UnitsTextbox are all done in code, this TextBox can be set to read only at design time.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
End If
'Moved this line outside of the If because it happens either way
InputTextbox.Text = String.Empty
If UnitsTextbox.Lines.Length >= 7 Then
Button2.Enabled = False
End If
End Sub
Here's some simple psuedocode
Private Sub InvalidateTextbox(sender As TextBox, e As KeyEventArgs) Handles TextBox1.KeyUp, TextBox2.KeyUp
'FOR ANY TEXTBOX YOU WANT TO CONTROL WITH THIS SUB, ADD AN ADDITIONAL HANDLE.
If Strings.Len(sender.Text) > 7 Then
'^SIMPLE CONDITIONAL, CHECKING IF THE LENGTH IS MORE THAN SEVEN CHARACTERS, MODIFY THIS TO SUIT YOUR NEEDS.
sender.Enabled = False
'^IF THE CONDITIONAL IS TRUE, DEACTIVATE THE CONTROL, IF THAT IS WHAT YOU ARE LOOKING FOR.
sender.ReadOnly = true
'^IF YOU WANT READONLY,NOT ENABLED/DISABLED.
End If
End Sub
This code will execute every time a key is pressed while the text boxes are active. What is after "Handles" defines what events will trigger the sub.
sender becomes the textbox object that triggered the sub. e holds all the event arguments for the keyboard, so you can evaluate things like which key was pressed and other neat things.
There was some confusion on if you wanted enabled/disabled or readonly, both options included.

Autofill TextBox/Checkbox from a previous TextBox' value (VB.NET Database)

Note: I'm using Visual Studio, original work was on SQL Server, moved to VB.NET
I have a Textbox "ViewStatusTxt", next to it there's a Button "ViewStatusBtn"
Below it there's a TextBox "ViewNAMETxt", another TextBox "ViewACTIVITYTxt" and then a Checkbox "ModifyStatusCB"
I'm trying to auto-fill the Checkbox AND the Textbox based on the ID input there, however I really have no clue about it since I'm new to VB.NET
Here's the code used
Private Sub IDSearch(StatusViewBtn As String)
' ADD SEARCH QUERY PARAMETERS - WITH WILDCARDS
SQL.AddParam("#StatusViewBtn", StatusViewBtn)
'RUN QUERY - SEARCH GIVES THOSE RESULTS
SQL.ExecQuery(" SELECT
aID,
Name,
Status,
Activity
FROM
[dbo].[initialTable]
WHERE
aID = #StatusViewBtn
ORDER BY
aID ASC")
End Sub
That's the function's code, which is fully working since it's a smaller version of the same one I used in a Search Page
Here's the button's function, which I'm sure is where I'm having problems, unless I need to add a specific function to the ViewNAMETxt
Private Sub StatusViewBtn_Click(sender As Object, e As EventArgs) Handles StatusViewBtn.Click
IDSearch(StatusViewBtn.Text)
ViewNAMETxt.Text = SQL.ExecQuery("SELECT
Name
FROM
initialTable
WHERE
aID = #StatusViewBtn")
End Sub
And I haven't even started on the Checkbox, viewing how the first one caused me issues. Hopefully the solution would be similar to both of them.
Thanks for reading guys, and sorry for the newbie question
1- Suppose you have a table named YourTable(int KeyColumn, string StringColumn, boolean BooleanColumn)
2- Create a form and put 2 textboxes and a checkbox and a button on it. KeyColumnTextBox, StringColumnTextBox, BooelanColumnCheckBox, SearchButton
3- In click event handler for SearchButton put the codes:
Private Sub SearchButton_Click(sender As Object, e As EventArgs) Handles SearchButton.Click
Dim connection = New SqlConnection("Your Connection string here")
Dim command = New SqlCommand("SELECT StringColumn, BooleanColumn FROM YourTable WHERE KeyColumn=#KeyColumn", connection)
command.Parameters.Add(New SqlParameter("#KeyColumn", Int32.Parse(KeyColumnTextBox.Text)))
connection.Open()
Dim reader = command.ExecuteReader()
While reader.Read()
StringColumnTextBox.Text = reader.GetString(0)
BooleanColumnCheckBox.Checked = reader.GetBoolean(1)
End While
End Sub
Don't forget to Imports System.Data.SqlClient at top of your file.

VB.net add line break after each loop

So I have been experimenting with VB.net (Windows Forms) to create a simple Ping Test app which pings the selected server and returns the elapsed time. I have declared a function to ping the address and then use a button to ping the server. The problem is that each time it pings, it only pings once and thus gives only one value. I would like to have a separate text box where the user enters the number of times they would like to ping the server for more accurate results.
Public Class Form1
Public Function Ping(ByVal server As String) As String
Dim s As New Stopwatch
s.Start()
My.Computer.Network.Ping(server)
s.Stop()
Return s.ElapsedMilliseconds.ToString
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim number As Integer = TextBox3.Text
For i = 1 To number
Try
TextBox1.Text = Ping(TextBox2.Text) & Environment.NewLine
Catch
MsgBox("Please enter a valid address", MsgBoxStyle.Critical, "Error")
End Try
Next
End Sub
End Class
I have tried using a loop to repeat the process and then return the results to a multi-line textbox for the user. Unfortunately it still only pings the address once and doesn't continue unless the ping button is clicked again, but then the first value is replaced by the next one. I believe the cause of the problem is that there should be a line break after each loop and I have tried using Enviroment.Newline but the problem persists. Any suggestions?
At the end I also would like to calculate the average ping of the results and expect to add all the ping values and divide by the number of times pinged. How would I get the results of the pings and add them?
Any help appreciated and excuse any spelling/grammatical errors.
In each loop you change the value of TextBox1 instead of appending the new value to the existing.
Optionally, you could also clear TextBox1 before starting the loop.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim number As Integer = TextBox3.Text
' Clear previous results
TextBox1.Text = String.Empty
For i = 1 To number
Try
' Append new result to existing ones
TextBox1.Text.AppendText(Ping(TextBox2.Text) & Environment.NewLine)
Catch
MsgBox("Please enter a valid address", MsgBoxStyle.Critical, "Error")
End Try
Next
End Sub

How do I pass a value from one TextBox to another TextBox in a different form?

Currently I have a TextBox on the first form called txtuserid and I want to pass the value of this to another TextBox called USERIDTextBox on a second form.
But when I try to run my code below, nothing gets passed to the TextBox on the second form. So I'm just wondering how I can pass this value from one form to another form?
Here is my code:
Private Sub cmdlogin_Click(sender As Object, e As EventArgs) Handles cmdlogin.Click
Try
If cn.State = ConnectionState.Open Then
cn.Close()
End If
cn.Open()
cmd.CommandText = "select userid,state from registration where userid= " & _
"'" & txtuserid.Text & "' and state='" & txtpw.Text & "'"
Dim dr As OleDb.OleDbDataReader
dr = cmd.ExecuteReader
If (dr.HasRows) Then
While dr.Read
' My Problem:
' This code shows the 2nd form but the USERIDTextBox value doesn't change?
Dim obj As New Sale
obj.USERIDTextBox.Text = txtuserid.Text
obj.Show()
End While
Else
MsgBox("Invalid username or PW")
End If
cn.Close()
Catch ex As Exception
End Try
End Sub
As a general rule, it's not a good idea to try accessing another object/forms controls directly. Instead, a better way to do it would be to pass the text in the 1st form's TextBox to a custom constructor on the 2nd form (the Sale one). Then the constructor on the 2nd form will be responsible for setting the value of the TextBox .
Here is an example of one way you could do this:
Sale.vb
Public Class Sale
Dim secondFormInputText As String
Public Sub New(inputTextFromFirstForm As String)
InitializeComponent()
' Set the class variable to whatever text string was passed to this form
secondFormInputText = inputTextFromFirstForm
End Sub
Private Sub Sale_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Set the textbox text using this class variable
USERIDTextBox.Text = secondFormInputText
End Sub
End Class
Login.vb
Private Sub cmdLoginExample_Click(sender As Object, e As EventArgs) Handles cmdLogin.Click
Dim obj As New Sale(txtuserid.Text)
obj.Show()
End Sub
So now instead of setting the Sale form's TextBox directly, you can pass the text on the 1st form to the constructor of the 2nd form. The constructor can then save the text it received to a class variable that the rest of the 2nd form can use.
One of the main benefits of this, is that if in the future you change your TextBox to a RichTextBox or possibly another control that might not even have a Text property, you won't have to go updating every single piece of code that tries to set the textbox value directly.
Instead you can change the TextBox to some other control, update the Sales form once with whatever changes you need to work with the new control, and none of the code on the other forms should need to be changed.
Edit:
Even though this question was specifically about how to pass a textbox value from one form to another form, you may also like to read the comments under your question. In particular, Plutonix had some very helpful advice on how you can improve your database code which might be of use to you.

Variables to list box?

taking a VB class this term and I've been stumped on a problem I'm trying to figure out. We were asked to create a price calculator for movie titles at a movie rental place. Extra credit was storing them in a list and being able to print the list. I've gotten that far and now I want to go a step further and actually add titles to that list with an attached price. I figured the easiest way to do this would probably be with arrays but I don't have much experience working with arrays.
I was thinking something along the lines of storing each title(as its added) as well as the price in a variable to give a "Movie Title - $2.93" format in every line of the list box. For the sake of this problem I'm going to just post my full source code and that might make it easier to see what I'm trying to accomplish. ANY help would be MUCH appreciated. Thanks Stack overflow community!
A screenshot of my project can be viewed here: http://puu.sh/54SgI.jpg
Public Class Form1
'globablly declared because I might use them outside of btnAdd_Click event
Const decDiscount As Double = 0.9 '1-.10 discount = .9
Const decDVD As Decimal = 2D
Const decBlueray As Decimal = 2.5D
Const decDVDNew As Decimal = 3.25D
Const decBluerayNew As Decimal = 3.5D
Dim intCount As Integer
Dim decCost, decTotal As Decimal
Dim decDayTotal As Decimal
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AcceptButton = btnAdd
End Sub
Private Sub chkDiscount_Click(sender As Object, e As EventArgs) Handles chkDiscount.Click
If chkDiscount.CheckState = 1 Then
chkDiscount.Enabled = False
End If
End Sub
Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
'Display error when no title entered
If txtAdd.Text = "" Then
MessageBox.Show("Please enter a movie title and select the appropriate item details.", "Complete details", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
listMovies.Items.Add(txtAdd.Text)
listMovies.SelectedIndex = listMovies.SelectedIndex + 1
End If
'update list
'clear txtbox
txtAdd.Text = ""
'Decision Statements to calculate correct price
If radDVD.Checked = True Then
decCost = CDec(decDVD.ToString("c"))
If chkNew.Checked = True Then
decCost = CDec(decDVDNew.ToString("c"))
End If
ElseIf radBlueray.Checked = True Then
decCost = CDec(decBlueray.ToString("c"))
If chkNew.Checked = True Then
decCost = CDec(decBlueray.ToString("c"))
End If
End If
If chkDiscount.Checked = True Then
decCost = CDec((decCost * decDiscount).ToString("c"))
End If
'display cost
txtCost.Text = CStr(CDec(decCost))
'calc total
decTotal = CDec(decTotal + decCost)
'display total
txtTotal.Text = CStr(CDec(decTotal))
'clear chkNew every item added to list
chkNew.CheckState = 0
End Sub
'Public so summary message box can access variable
Public Sub btnFinish_Click(sender As Object, e As EventArgs) Handles btnFinish.Click
'Add +1 to counter & update txtCounter
intCount = CInt(Val(intCount) + 1)
'add to day total
decDayTotal = CDec(Val(decDayTotal) + decTotal)
'Set Everything back to empty/enabled
chkDiscount.Enabled = True
chkDiscount.CheckState = 0
chkNew.CheckState = 0
txtAdd.Text = ""
txtCost.Text = ""
txtTotal.Text = ""
decTotal = 0
decCost = 0
'Instead of clearing radios each time, a more desirable result would be to have DVD always set back to the default checked radio
radDVD.Checked = True
radBlueray.Checked = False
listMovies.Items.Clear()
End Sub
Private Sub btnSummary_Click(sender As Object, e As EventArgs) Handles btnSummary.Click
If decTotal > 0 Then
MessageBox.Show("Please finish your current order before viewing a daily summary.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
MessageBox.Show(("Your total cutomer count is: " & intCount) + Environment.NewLine + ("Your total sales today is: $" & decDayTotal), "Daily Summary", MessageBoxButtons.OK)
End If
End Sub
Private Sub btnRemove_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRemove.Click
listMovies.Items.Remove(listMovies.SelectedItem)
End Sub
I wont go very far here because you need to do the work. But, I would start with a class:
Public Class Movie
Public Title As String = ""
Public Cost As Decimal
' prevents you from adding a movie without critical info
Public Sub New(ByVal t As String, ByVal c As Decimal)
Title = t
Cost = c
End Sub
End Class
This would hold the info on one movie title rental, and keep it together (and can be added to in order to print exactly as you showed) . The plan (to the extent I understand what you are after) would be to create one of these for each movie rented and add it to a List(Of Movie) this is more appropriate than a Dictionary in this case.
To create a movie:
Dim m As New Movie(theTitle, theCost)
Things I would do:
You did a good job of declaring numerics as numbers. Fix the code that converts it to string and back to numeric. (edit your post)
You can use the Movie Class to populate the "Shopping Cart" listbox alone; at which point, listMovies.Items would BE the extra credit List. But it wouldnt hurt to use/learn about List (Of T). (BTW, does 'print' mean to paper, on a printer?)
What are you doing with chkDiscount? If they check it, you disable it (and never enable). Did you mean to disable the New Releases check? In THAT case, arent they really a pair of radios too?
Either way, CheckChanged is a better event for evaluating and there is no reason to manually set the check state for the user that happens by itself.
Check out List(of T) and HTH
A good thing to think about when doing assignments like this (particularly when learning your first language) is to think of the algorithm (the step you need to get to your goal).
1st, determine all the steps you need to get to your goal.
2nd, and I think this is the more import point for your question, figure out what order the steps need to be in (or better yet, what order they are most efficient in).
In your case I think that you are kind of ice skating up hill by adding the name of the movie to the list first, and then trying to add the price to the line later. Unless that kind of functionality was requested as part of the assignment I would require the user to enter both the name AND the price before accepting either (just like you do with the name currently). Like thus:
If txtAdd.Text <> "" AND txtCost.Text <> "" Then 'requiring both fields to not be null
''add moive code
Else
''MessageBox.Show("Yadda Yadda Yadda")
End If
I agree with Plutonix that creating a class, while overkill in your case, is a good idea, as it will give you practice for when it WILL be appropriate. Once you have that a class of Movie, you can then create lists of Movie(s) like this:
Dim MovieList as new List(of Movie)
So then, each time you press the btnAdd button, you can pass the values to a movie AND add it to the list.
Dim m As Movie
Dim MovieList as new List(of Movie)
Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
'Display error when no title entered
If txtAdd.Text <> "" And txtCost.Text <> "" Then
myMovie = New Movie(txtAdd.Text, txtCost.Text)
myMovieList.Add(myMovie)
listMovies.Items.Clear()
For Each X As Movie In myMovieList
listMovies.Items.Add(X.DisplayMovie)
Next
Else
MessageBox.Show("Please enter a movie title and select the appropriate item details.", "Complete details", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
'Other Code
End Sub
Note the line ListMovies.Items.Add(X.DisplayMovie) I added a function to the class Movie (seen below) so that it will do the formatting as you suggested.
Public Function DisplayMovie()
Return Title & " - $" & Cost
End Function
This will get you much of the way. Try to extrapolate what Plutonix and myself have explained to further refine your code. For instance, try encapsulating your adjusted price calculation in its own function so you can call it from anywhere.