Ticket printing - vb.net

I'm busy to write ticket program in Vb , everything is working perfectly
but when i'm printing things goes wrong,
the ticket is printing correctly ( in this example 3 ) the ticketnumbers are overlapping
example : 3 tickets 15200 , 15201 , 15203
3 tickets are printed but the 1520 is printed correct but on evey ticket the 1,2 a 3 are printed over each other
What the hell is going wrong ??
this is a part of the code
Private Sub PrintDocument1_PrintPage(sender As System.Object, e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim AZ As String
Dim x As Integer
Dim LB1, LB2 As Integer
AZ = TextBox12.Text
For x = 0 To AZ - 1
LB1 = Val(TextBox1.Text) + x
e.Graphics.DrawString(LB1, New Font("Microsoft Sans Serif", 10), Brushes.Black, New Point(155, 265))
next
end sub

Sorry, I misread and gave you the wrong answer.
One way I've done this in the past was to call the printdocument.print inside a loop. The only problem with this is that you get a messagebox telling you that each page is printing so that may not be ideal.
Anyway, here is a method that you might be able to work off with. It's been a while since I've used the printdocument as I find the ReportViewer/Report is easier to work with.
'Widen the scope of LB1 so it can be used in both methods
Dim LB1, LB2 As Integer 'Declared outside of any methods (Class Level)
Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
e.Graphics.DrawString(LB1.ToString, New Font("microsoft sans serif", 10), Brushes.Black, New Point(155, 265))
End Sub
Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles btnPrint.Click
Dim AZ As Integer = CInt(NumericUpDown1.Value)
For x = 0 To AZ - 1
'We can get rid of this if we use a NumericUpDown control and set it
'to ensure we are working with a number.
If Not Integer.TryParse(TextBox1.Text, LB1) Then
'notify the user with maybe a messagebox that the input is invalid
Exit Sub
End If
LB1 += x
PrintDocument1.Print()
Next
End Sub
Again, I've not worked with this for a while but I seem to remember e.HasMorePages being a way of telling the PrintDocument to move to the next page. You might google up on it and see if it's a better alternative than looping and displaying the Print messagebox for each page like this code is doing. Hopefully it's at least gives you something to work off of.
EDIT --- THIS IS THE PROPER WAY OF DOING WHAT YOU'RE WANTING TO DO ---
I decided to go ahead and look into the HasMorePages myself and It would be the better and more proper solution. You would need to change a few things but here is an example of your code using it.
Dim LB1, LB2 As Integer 'Declared outside of any methods
Dim currentTicket = 0
Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
'how many tickets to print
Dim TotalTickets As Integer = CInt(NumericUpDown1.Value)
'build the current ticket number (I would look at my previous code
'which uses TryParse instead of Val as an invalid input could cause
'your application to fail)
LB1 = Val(TextBox1.Text) + currentTicket
'Print the ticket number on the page
e.Graphics.DrawString(LB1.ToString, New Font("microsoft sans serif", 10), Brushes.Black, New Point(155, 265))
'increase the currentTicket counter
currentTicket += 1
'did we go over the total number of tickets we want to print
If currentTicket < TotalTickets Then
'if not, we need to tell the printdocument that we have more to print
e.HasMorePages = True
End If
'otherwise, we'll stop there and print the pages we produced.
End Sub
This will give you the single dialog that shows how many pages are being printed instead of a single dialog per page.

Related

Visual Basic Random Number Guessing Game

I need some help for an assignment in class. I'm trying to create a random number guessing game that must have a loop. Basically, you input a number as a guess and the program will display a message telling you whether the guess is too high, too low, or correct, and it will loop until you get the guess correct. The program also counts the number of guesses you've made.
Here is the form:
And here is the code I have so far:
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Dim decNumber As Decimal
Dim rand As New Random
Dim decGuess As Decimal
Dim intCount As Integer = 0
decGuess = CDec(txtGuess.Text)
Do
decNumber = rand.Next(1, 100)
intCount += 1
lblCount.Text = intCount.ToString
If decNumber < decGuess Then
lblResponse.Text = "Too low, try again."
ElseIf decNumber > decGuess Then
lblResponse.Text = "Too high, try again."
ElseIf decNumber = decGuess Then
lblResponse.Text = "Correct."
End If
Loop Until decGuess = decNumber
End Sub
I'm not quite sure what the error in the code is but whenever I hit "Display" the guess count is a very high number and the message shown in the label is always just "Correct.", so my question is how do I fix this and write the loop correctly?
Update:
Public Class Form1
Dim intNumber As Integer
Dim rand As New Random
Dim intGuess As Integer
Dim intCount As Integer
Private Sub btnNew_Click_1(sender As Object, e As EventArgs)
lblResponse.Text = String.Empty
txtGuess.Clear()
lblCount.Text = String.Empty
intNumber = rand.Next(1, 100)
End Sub
Private Sub btnGuess_Click(sender As Object, e As EventArgs) Handles btnGuess.Click
intGuess = CInt(txtGuess.Text)
If intNumber < intGuess Then
lblResponse.Text = "Too high, try again."
ElseIf intNumber > intGuess Then
lblResponse.Text = "Too low, try again."
ElseIf intNumber = intGuess Then
lblResponse.Text = "Correct."
End If
intCount += 1
lblCount.Text = intCount.ToString
End Sub
There are quite a few errors with your code:
1. The definition of your random number
You are generating the random number every loop, meaning that rather than there being a fixed number that you are trying to guess, the number is changing.
Even if you are defining the random number outside the loop, the number changes every time that you click the button.
You will need to define it as global variable outside the subroutines and only change it when you press the reset button
2. The definition of intcount
intcount is set to 0 every time you click the button since it is defined within the button click subroutine, which I do not think is desired.
3. The fact that you are using a loop
You do not need the loop at all. Unless you want your programme to enter an infinite loop and crash every time you press your button and your guess is incorrect, you should remove the loop and just use the code inside it.
4. Wrong data types used
decnumber should be an integer, since random.next() returns an integer value (you might also rename it to ToGuess)
decGuess = CDec(textGuess.Text)
should be
decGuess = CInt(textGuess.Text)
since if you input a decimal, you will never be able to guess the number
The reason for the programme always outputting "correct" is because rather than you changing your guess so it is the same as the random number, the computer is 'guessing' your guess by changing the random number so that it will eventually become your guess, incrementing # of guesses every time.
UPDATE:
The reason that your new button is not working is because it does not handle its click. Assuming you have called your new button btnNew, try replacing:
Private Sub btnNew_Click_1(sender As Object, e As EventArgs)
with:
Private Sub btnNew_Click_1(sender As Object, e As EventArgs) Handles btnNew.Click
Next time when adding a subroutine for a buttons click, try double clicking the button in the design view in visual studio. This will automatically generate the click subroutine.
Another problem that you have is that you have not generated your random number when your form loads. To solve this, double click on your form in designer view to generate the load subroutine, and then programmatically press the button
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
btnNew.PerformClick()
End Sub
also, thanks to jimi's comment, remember to set intCount to 0 when pressing btnNew

Displaying winner's name in picture box

Below is code for a simple voting system I am coding.
Public Class Form1
Dim winner As String
Dim maxVotes As Integer
Dim votes() As String
Dim index As String
Dim candidates As String
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
If Not isValidInput(txtNewCandidate.Text) Then
Exit Sub
End If
lstCandidates.Items.Add(txtNewCandidate.Text)
txtNewCandidate.Clear()
txtNewCandidate.Focus()
ReDim Preserve votes(index)
index += 1
End Sub
Private Function isValidInput(ByRef firstName As String) As Boolean
If IsNumeric(txtNewCandidate.Text) Or txtNewCandidate.Text = "" Then
MsgBox("Please input a valid candidate name.")
txtNewCandidate.Focus()
Return False
Else
Return True
End If
End Function
Private Sub btnTally_Click(sender As Object, e As EventArgs) Handles btnTally.Click
lstTallies.Visible = True
lblTally.Visible = True
For i = 0 To lstCandidates.Items.Count - 1
lstTallies.Items.Add(lstCandidates.Items(i).ToString & " - " & votes(i))
Next
End Sub
Private Sub lstCandidates_DoubleClick(sender As Object, e As EventArgs) Handles lstCandidates.DoubleClick
If lstCandidates.SelectedIndex = -1 Then
MsgBox("Select a candidate by double-clicking")
End If
votes(lstCandidates.SelectedIndex) += 1
MsgBox("Vote Tallied")
End Sub
Private Sub pbxWinner_Click(sender As Object, e As EventArgs) Handles pbxWinner.Click
End Sub
End Class
The voter must double click on their choice of candidate in the first list box. The user then tallies the votes by clicking on a button and a second list box will appear with the votes per candidate.
Now I need to display the winner (or winners, if there is a tie) in a picture box, pbxWinner. I am not sure how to accomplish this. Any clues?
Here is what i am trying to do, though the code below doesn't work.
Private Function candidateWinner(ByRef winner As String) As Boolean
For i As Integer = 0 To lstCandidates.SelectedIndex - 1
If votes(i) > maxVotes Then
maxVotes += 1
End If
Next
g = pbxWinner.CreateGraphics
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("Arial", 7, FontStyle.Regular), Brushes.DarkBlue, New PointF(0, 0))
Return True
End Function
Your code is actually working fine for an initial paint, but when the picture box image doesn't have its own bitmap set, a number of events can repaint its graphics behind the scenes(even as simple as minimizing/mazimizing the form, and a whole bunch of other ones), so in effect your text seems to never appear at all or disappear almost instantly when in reality it's probable getting repainted. To fix this, use a bitmap for the graphics object's reference, paint the bitmap's graphics, and then assign the bitmap to the picturebox's image property. This will make the image persistent...give this code a try in your candidateWinner function after the for loop:
Dim bmp As New Bitmap(pbxWinner.Width, pbxWinner.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("arial", 7, FontStyle.Regular), Brushes.DarkBlue, 0, 0)
pbxWinner.Image = bmp
...If you still aren't seeing text, make sure the winner string has the correct value set, I tested this code and it showed my test string correctly
Edit for Comment:
That's because of the logic you're using to calculate the winner...you are just checking to see if the currently selected candidate's vote count is higher than maxVotes and then incrementing the max by 1. If you wanted to stick with that sort of logic for picking the winner, you would want to iterate through ALL of the candidates(not just those from index 0 to the currently selected one), and if their vote count is higher than the max, then set the max EQUAL to their vote count. Then the next candidate in the loop will have their count checked against the previous max. However, tracking the winner could be done a lot easier if you just use a dictionary since you are allowing candidates to be added, and you must change your "winner" logic to actually check who has the most votes out of everyone entered. A bare bones example of that would look like this:
Dim dctTally As Dictionary(Of String, Integer)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dctTally = New Dictionary(Of String, Integer)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
dctTally.Add(txtNewCandidate.Text, 0)
lstCandidates.Items.Add(txtNewCandidate.Text)
End Sub
Private Sub lstCandidates_DoubleClick(sender As Object, e As EventArgs) Handles lstCandidates.DoubleClick
dctTally(lstCandidates.text) += 1
End Sub
Private Sub pbxWinner_Click(sender As Object, e As EventArgs) Handles pbxWinner.Click
Dim winner = dctTally.Aggregate(Function(l, r) If(l.Value > r.Value, l, r)).Key
Dim bmp As New Bitmap(pbxWinner.Width, pbxWinner.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("arial", 7, FontStyle.Regular), Brushes.DarkBlue, 0, 0)
pbxWinner.Image = bmp
End Sub
This way, the program allows as many names as you want to be added to the candidates list, and will add a vote count to their name each time their name is double-clicked on. Then, when your winner pixturebox is clicked, it will find the dictionary with the highest vote count and display their name in the winner-box.
You can try this to draw the winners:
Private Sub candidateWinner()
Dim y As Single = 0
maxVotes = votes.Select(Function(x) Convert.ToInt32(x)).Max()
For i = 0 To UBound(votes)
If votes(i) = maxVotes.ToString() Then
g = pbxWinner.CreateGraphics
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(lstCandidates.Items(i).ToString(), New Font("Arial", 7, FontStyle.Regular), Brushes.DarkBlue, New PointF(0, y))
y += 10
g.Dispose()
End If
Next
End Sub

Alternative Process

I have 2 buttons and a DataGridView with 2 Columns (0 & 1).
The 1st button transfers a randomized cell from the Column(1) to a TextBox. Then, it stores that Cell in variable (a), plus the cell that opposites it in variable (b).
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim rnd As New Random
Dim x As Integer = rnd.Next(0, Form1.DataGridView1.Rows.Count)
Dim y As Integer = 1
Dim a As String = Form1.DataGridView1.Rows(x).Cells(y).Value
Dim b As String = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
The 2nd button, however, is supposed to compare if another TextBox's text has the same string variable (b) has as Strings. Now, if so, then it has to display a certain message and so on...
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If TextBox4.Text = b Then '<<< ISSUE HERE!
MsgBox("Correct! ^_^")
ElseIf TextBox4.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub
The problem is that the variable (b) is surely not shared across the two "private" subs. And so, there is NOTHING to compare to in the 2nd button's sub! I presume that the solution here is to split the "randomization process" into a separate function, then execute it directly when the 1st button gets activated. Furthermore, that function's variables have to be SHARED somehow, and I certainly don't know how!
Thanks for Mr. Olivier, the code has been improved significantly! Yet, I still encounter a "wrong" comparison issue, somehow!
Dim RND As New Random
Dim x As Integer
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
Private Sub btnRoll_Click(sender As Object, e As EventArgs) Handles btnRoll.Click
x = RND.Next(0, Form1.DataGridView1.Rows.Count)
tbxRoll.Text = GetCell(x, 1)
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
If tbxSubmit.Text = GetCell(x, 0) Then
MsgBox("Correct! ^_^")
ElseIf tbxSubmit.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub</code>
Well, unbelievably, I read a guide about "comparison operations" in VB.net and tried out the first yet the most primal method to compare equality - which was to use .Equals() command - and worked like a charm! Thank God, everything works just fine now. ^_^
If tbxSubmit.Text.Equals(GetCell(x, 0)) Then
Alright now... This is going to sound weird! But, following Mr. Olivier's advise to investigate "debug" the code, I rapped the string I'm trying to compare with brackets and realized that it's been outputted after a break-line space! So, I used the following function to remove the "white-space" from both of the comparison strings! And it bloody worked! This time for sure, though. ^_^
Function RemoveWhitespace(fullString As String) As String
Return New String(fullString.Where(Function(x) Not Char.IsWhiteSpace(x)).ToArray())
End Function
If RemoveWhitespace(tbxSubmit.Text) = RemoveWhitespace(GetCell(x, 0)) Then
Turn the local variables into class fields.
Dim rnd As New Random
Dim x As Integer
Dim y As Integer
Dim a As String
Dim b As String
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
x = rnd.Next(0, Form1.DataGridView1.Rows.Count)
y = 1
a = Form1.DataGridView1.Rows(x).Cells(y).Value
b = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
These fields can now be accessed from every Sub, Function and Property.
Of course Button3_Click must be called before Button2_Click because the fields are initialized in the first method. If this is not the case then you should consider another approach.
Create a function for the Cell access
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) _
As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
And then compare
If TextBox4.Text = GetCell(x, y - 1) Then
...
And don't store the values in a and b anymore. If y is always 1 then use the numbers directly.
If TextBox4.Text = GetCell(x, 0) Then
...
One more thing: give speaking names to your buttons in the properties grid before creating the Click event handlers (like e.g. btnRandomize). Then you will get speaking names for those routines as well (e.g. btnRandomize_Click).
See:
- VB.NET Class Examples
- Visual Basic .NET/Classes: Fields

Dynamically moving a control for each character in a Textbox

Basically I'm trying to make a CheckBox move to the right using:
chk_ShowPassword.Location = New Point(X, Y)
Now the way I'm trying to do this is by checking for each character in the textbox and depending on the amount of characters there is, the checkbox will move to the right. I'm using:
For Each chr As Char In tb1.Text
chk_ShowPassword.Location = New Point(++85, 95)
Next
I need help with 2 things, I'm not sure why but it seems to be not moving to the right. It's meant to be moving to the right by 85 for each character. The other thing is that is 85 a good increment method for each character, is it too much, too little,
Can someone help me with this. Please if it's not clear you can ask me where to expand on and I'll do my best.
I think its important to save the starting point and do the movements from there. "Orgchk_ShowPasswordLocation"
So you can always go back to the starting point.
Do a count for the chars and then use "Orgchk_ShowPasswordLocation.X + Count * 10"
Then it will move forward or backwards if you add or delete chars in the text box.
Dim Orgchk_ShowPasswordLocation As Point
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Orgchk_ShowPasswordLocation = chk_ShowPassword.Location
End Sub
Dim cby As Integer
Dim cbx As Integer
Dim Count As Integer
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles tb1.TextChanged
cby = chk_ShowPassword.Location.Y
cbx = chk_ShowPassword.Location.X
Count = Nothing
For Each chr As Char In tb1.Text
Count = Count + 1
Next
cbx = Orgchk_ShowPasswordLocation.X + Count * 10
chk_ShowPassword.Location = New Point(cbx, cby)
End Sub

Visual Basic Avg. Temp Calculator

Ok, so I am super new to visual basic and was not planning on taking it as a class either until they made it a requirement for me to get my technicians certificate at my community college. Literally understand the chapters I have read so far to a T, and then first homework assignment comes up and for the past few days I have been scratching my head as to why on earth it is not working. Here is what the Prof is asking.
Write a program that calculates average daily temperatures and summary statistics. The user will be prompted to enter a Fahrenheit temperature as a value with one decimal place and to select the name of the technician entering the temperature. The user will have the option to see the Celsius equivalent of the entered Fahrenheit temperature. The program will display the average temperature of all entered temperatures. The results are displayed when the user hits ENTER, uses the access key or clicks the Calculate button. The user will be given the opportunity to enter another temperature when the user hits ESC (Clear is the Cancel Button), uses the access key or clicks the Clear button. The user will exit the program by clicking the Exit button or using its access key. The Exit button will also display the summary statistics: 1) the number of temperatures entered by each technician and 2) the average temperature of all entered temperatures. Calculations should only be done if a numeric value between 32.0 and 80.0 (inclusive) degrees for temperature is entered and a technician has been selected.
The graphical side is a breeze with dragging and dropping, then naming the labels, radio buttons, etc... But now that I have assembled my code. Nothing is working. I'm frustrated, confused, and let down. I had no idea this class would be this hard. Here is what I came up with so far code wise. No error messages at all, just not getting any output pretty much.
Option Strict On
Option Strict On
Public Class Form1
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
'Clear App
txtTemp.Clear()
lblAverageTemp.Text = String.Empty
lblCelsius.Text = String.Empty
radDave.Checked = False
radJoe.Checked = False
chkCelsiusTemp.Checked = False
'New Temp Focus
txtTemp.Focus()
End Sub
Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click
'End app with display
MessageBox.Show("Dave entered intEntriesDave entries." & ControlChars.CrLf & "Joe entered intEntriesJoe entries." & _
ControlChars.CrLf & "The average temperature is _.", "Status")
Me.Close()
End Sub
Public Sub chkCelsiusTemp_CheckedChanged(sender As Object, e As EventArgs) Handles chkCelsiusTemp.CheckedChanged
'Convert entered Fahrenheit temp to Celsius
Dim dblCelsius As Double
dblCelsius = (CDbl(txtTemp.Text) - 32) * 5 / 9
lblCelsius.Text = CStr(dblCelsius)
End Sub
Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
Dim intEntriesDave As Integer = 0
Dim intEntriesJoe As Integer = 0
If radDave.Checked = True Then
intEntriesDave = +1
End If
If radJoe.Checked = True Then
intEntriesJoe = +1
End If
Dim dblAvg As Double
dblAvg = CDbl(txtTemp.Text) / intEntriesDave + intEntriesJoe
lblAverageTemp.Text = CStr(dblAvg)
End Sub
End Class
Hope I figure this out or I can get some help with it. I procrastinated of course, like the idiot I am, and it is due in 11 hours :\
Thanks in advance!
I would use a dictionary to store names along with temperatures.
Place a numericupdown control on your form for the temperature input (numTemp) and a textbox for names tbName and a label lblCelsius for output:
Public Class Form1
Dim temps As New Dictionary(Of String, List(Of Double))
Private Sub btnEnter_Click(sender As Object, e As EventArgs) Handles btnEnter.Click
If numTemp.Value < 32 OrElse numTemp.Value > 80 OrElse tbName.Text = "" Then Exit Sub 'Invalid input
If temps.ContainsKey(tbName.Text) = False Then 'Name is new, create a new list entry
temps.Add(tbName.Text, New List(Of Double))
End If
temps(tbName.Text).Add(numTemp.Value) 'Append the entered temperature
lblCelsius.Text = "In celsius: " & CStr(numTemp.Value - 32) * 5 / 9 'Output the Celsius value
End Sub
Private Sub btnStats_Click(sender As Object, e As EventArgs) Handles btnStats.Click
Dim sb As New System.Text.StringBuilder 'Create the output
For Each k As String In temps.Keys
sb.AppendLine(k & ": " & temps(k).Average)
Next
lblCelsius.Text = sb.ToString
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
temps.Clear() 'Clear the database
End Sub
End Class
Basically everytime you click btnEnter you check your dictionary if the name already entered a value. If not a new entry is created with a new list and the new temperature is just added to the list.
Creating the output is then straightforward with the .Average method of the list.