Question Displaying information on a windows form.

Pianoman

Member
Joined
Jul 22, 2013
Messages
7
Programming Experience
Beginner
I always thought that a program read and executed instructions in the order in which they were written; but I'm finding that in my current experimental program it reads all of the code in a procedure and then does the execution. Let me explain: I have a windows form on which there are quite a number of textboxes. The variables are populated from txtfiles. What I wanted was for, say, the first five textboxes to be populated and then another five, and so on. The reason being that because there are so many, and the txtfiles are quite large, it's a slow-ish read and I didn't want the user looking at a blank screen thinking it had crashed whilst the data was being pulled in. I coded in this way, but no matter how I code, none of the textboxes get populated until the whole procedural code has been read. First question - is this normal or have I missed a step?

I put a label on the form saying "Getting data - please wait"; designing it to be visible during the loading process; but all that happens is that I get the outline of the label rather than the label itself. Why?
 
is this normal
Yes
have I missed a step?
Yes

Put very simply, you have blocked the UI Thread due to all the processing required to read your files. The UI Thread is the “User Interface” thread and is basically the pen that draws everything to the screen and if you use all the processing power allocated to the UI Thread to do other things (like reading files) then nothing gets drawn to the screen until that work is completed. It’s gets a lot more technical than this but that is the very basics.

The way you get round this is to use another Thread to read the files and then pass the necessary information to the UI thread as and when a portion of work gets completed. There are various ways to do this but the one I would recommend that you learn first is the BackgroundWorker.

Have a read of all this and keep at it until it all sinks in:-

BackgroundWorker Class

A couple of the elements that are paramount for you to solve your problem are the ReportProgress Method and ProgressChanged Event.
 
Wow. Thanks for the info. I've read through it all and at the moment it makes no sense as to where I'd fit it into my program; but I'll keep going!!! Thanks again
 
One of the things you have to realize about object oriented programming is that while yes the code still executes in the order it's written the time that blocks of code can run in different sequences.
For example: Events, it's code that only runs when the event happens, so your code inside the button click event sub will execute in the order it's written but that block only runs when called (the button is clicked).
While my example above actually explains your data loading/displaying issue let me add more detail, you have a thread-busy sub that's loading the data and assigning the variable values to the textboxes is it goes, you're assigning the value vie the Text property, which causes the control to have a "refresh" event happen that actually displays the new value, which it will do so once the thread isn't busy, which would be when you're done loading the data. Now there's two ways to handle this situation, you could (though not recommended) force your data execution to allow the form & it's controls to "refresh", ie process the event queue, every so often, or as mentioned already you could use threading. You can do threading yourself if you wish, but it does get a bit messy pretty quickly, or as suggested you can use the BackgroundWorker component in which you have a DoWork event that runs code on a different thread which is where you would want your data loading code to be and you use the BackgroundWorker.ReportProgress() call to have it's ProgressChanged event on the form's thread fire where you can update the Label(s) appropriately and the user will see the data update on the form in real time.
You could set a Label to say "data loading" or whatever then start the background worker and of course when the RunWorkerCompleted fires you know the data is done loading so you can hide the loading data label and enable the buttons and toolbar stuff for the user to now use the form.
 
So This is the code I have for when the user clicks a button on the form (sorry; it's a bit long-winded). Where would I place the code for the BackgroundWorker ?

 Private Sub btnPrice_Click(sender As Object, e As EventArgs) Handles btnPrice.Click

        Dim eGraphics As Graphics = Me.CreateGraphics
        Dim myPen As Pen = New Pen(Drawing.Color.Black, 1)
        MyTend.read1()


        tbAAH.Text = Tender.AAH(a)
        tbCol.Text = Tender.COL(a)
        tbDE.Text = Tender.DE(a)
        tbLex.Text = Tender.LEX(a)
        tbUni.Text = Tender.UNI(a)


        'Populate temp textboxes for DTB ranking
        TextBox1.Text = tbAAH.Text
        TextBox2.Text = tbCol.Text
        TextBox3.Text = tbDE.Text
        TextBox4.Text = tbLex.Text
        TextBox5.Text = tbUni.Text


        'Populate DTW tender details
        MyTend.read2()
        tbAct.Text = Tender.ACT(a)
        tbBWay.Text = Tender.BWay(a)
        tbBrist.Text = Tender.BRI(a)
        tbCST.Text = Tender.CST(a)
        tbDex.Text = Tender.DEX(a)
        tbEth.Text = Tender.ETH(a)
        tbMaw.Text = Tender.MAW(a)
        tbMedh.Text = Tender.MEDh(a)
        tbMedw.Text = Tender.MEDw(a)
        tbMyl.Text = Tender.MYL(a)
        tbOTC.Text = Tender.OTC(a)
        tbPri.Text = Tender.PRI(a)
        tbTev.Text = Tender.TEV(a)
        tbTri.Text = Tender.TRI(a)
        tbWay.Text = Tender.WAY(a)




        'Find DTB minimum value and highlight in green the cheapest DTB tenders
        Dim textBoxes() As TextBox = {tbAAH, tbCol, tbDE, tbLex, tbUni} 'make an array of textboxes for DTB companies
        Dim Bnumbers As New List(Of Double)
        Dim minNumberB As Double
        Dim o As Integer
        For Each tb As TextBox In textBoxes
            If Double.TryParse(tb.Text, o) Then
                Bnumbers.Add(tb.Text) 'if the textbox contains a number, add it to the list
            End If
        Next
        If Bnumbers.Count > 0 Then
            'at least one textbox contains number
            minNumberB = Bnumbers.Min
            tbDTBmin.Text = minNumberB
        End If
        For Each tb As TextBox In textBoxes
            If tb.Text = tbDTBmin.Text Then
                tb.BackColor = Color.LawnGreen
            End If
            If tb.Text <> "~" Then
                tb.Text = FormatCurrency(tb.Text, 2)
            End If
        Next
        '
        'Rank the DTB tenders
        Dim lb As New ListBox
        Dim Ascendinglb As New List(Of Decimal)
        Dim ItemToAdd As Decimal
        For x As Integer = 1 To 5
            Dim tb = Me.Controls("TextBox" & x)
            If Decimal.TryParse(tb.Text, ItemToAdd) Then
                lb.Items.Add(ItemToAdd)
                tb.Text = ""
            End If
        Next
        If lb.Items.Count > 1 Then
            Ascendinglb.Clear()
            For i = 0 To lb.Items.Count - 1
                Ascendinglb.Add(CDbl(lb.Items(i)))
            Next
            Ascendinglb.Sort()
            lb.Items.Clear()
            For i = 0 To Ascendinglb.Count - 1
                Dim tb = Me.Controls("TextBox" & i + 1)
                tb.Text = Ascendinglb(i).ToString
                tb.Text = FormatCurrency(tb.Text, 2)
            Next
        End If
        ''
        If tbRk3.Text = "1" Or tbRk6.Text = "1" Then
            If tbAAH.Text <> "~" Then
                If tbAAH.Text = TextBox1.Text Then
                    tbRk1.Text = 2
                End If
                If tbAAH.Text = TextBox2.Text Then
                    tbRk1.Text = 3
                End If
                If tbAAH.Text = TextBox3.Text Then
                    tbRk1.Text = 4
                End If
                If tbAAH.Text = TextBox4.Text Then
                    tbRk1.Text = 5
                End If
                If tbAAH.Text = TextBox5.Text Then
                    tbRk1.Text = 6
                End If
            End If
            If tbCol.Text <> "~" Then
                If tbCol.Text = TextBox1.Text Then
                    tbRk2.Text = 2
                End If
                If tbCol.Text = TextBox2.Text Then
                    tbRk2.Text = 3
                End If
                If tbCol.Text = TextBox3.Text Then
                    tbRk2.Text = 4
                End If
                If tbCol.Text = TextBox4.Text Then
                    tbRk2.Text = 5
                End If
                If tbCol.Text = TextBox5.Text Then
                    tbRk2.Text = 6
                End If
            End If
            If tbDE.Text <> "~" Then
                If tbDE.Text = TextBox1.Text Then
                    tbRk3.Text = 2
                End If
                If tbDE.Text = TextBox2.Text Then
                    tbRk3.Text = 3
                End If
                If tbDE.Text = TextBox3.Text Then
                    tbRk3.Text = 4
                End If
                If tbDE.Text = TextBox4.Text Then
                    tbRk3.Text = 5
                End If
                If tbDE.Text = TextBox5.Text Then
                    tbRk3.Text = 6
                End If
            End If
            If tbLex.Text <> "~" Then
                If tbLex.Text = TextBox1.Text Then
                    tbRk4.Text = 2
                End If
                If tbLex.Text = TextBox2.Text Then
                    tbRk4.Text = 3
                End If
                If tbLex.Text = TextBox3.Text Then
                    tbRk4.Text = 4
                End If
                If tbLex.Text = TextBox4.Text Then
                    tbRk4.Text = 5
                End If
                If tbLex.Text = TextBox5.Text Then
                    tbRk4.Text = 6
                End If
            End If
            If tbUni.Text <> "~" Then
                If tbUni.Text = TextBox1.Text Then
                    tbRk5.Text = 2
                End If
                If tbUni.Text = TextBox2.Text Then
                    tbRk5.Text = 3
                End If
                If tbUni.Text = TextBox3.Text Then
                    tbRk5.Text = 4
                End If
                If tbUni.Text = TextBox4.Text Then
                    tbRk5.Text = 5
                End If
                If tbUni.Text = TextBox5.Text Then
                    tbRk5.Text = 6
                End If
            End If


        Else
            If tbAAH.Text <> "~" Then
                If tbAAH.Text = TextBox1.Text Then
                    tbRk1.Text = 1
                End If
                If tbAAH.Text = TextBox2.Text Then
                    tbRk1.Text = 2
                End If
                If tbAAH.Text = TextBox3.Text Then
                    tbRk1.Text = 3
                End If
                If tbAAH.Text = TextBox4.Text Then
                    tbRk1.Text = 4
                End If
                If tbAAH.Text = TextBox5.Text Then
                    tbRk1.Text = 5
                End If
            End If
            If tbCol.Text <> "~" Then
                If tbCol.Text = TextBox1.Text Then
                    tbRk2.Text = 1
                End If
                If tbCol.Text = TextBox2.Text Then
                    tbRk2.Text = 2
                End If
                If tbCol.Text = TextBox3.Text Then
                    tbRk2.Text = 3
                End If
                If tbCol.Text = TextBox4.Text Then
                    tbRk2.Text = 4
                End If
                If tbCol.Text = TextBox5.Text Then
                    tbRk2.Text = 5
                End If
            End If
            If tbDE.Text <> "~" Then
                If tbDE.Text = TextBox1.Text Then
                    tbRk3.Text = 1
                End If
                If tbDE.Text = TextBox2.Text Then
                    tbRk3.Text = 2
                End If
                If tbDE.Text = TextBox3.Text Then
                    tbRk3.Text = 3
                End If
                If tbDE.Text = TextBox4.Text Then
                    tbRk3.Text = 4
                End If
                If tbDE.Text = TextBox5.Text Then
                    tbRk3.Text = 5
                End If
            End If
            If tbLex.Text <> "~" Then
                If tbLex.Text = TextBox1.Text Then
                    tbRk4.Text = 1
                End If
                If tbLex.Text = TextBox2.Text Then
                    tbRk4.Text = 2
                End If
                If tbLex.Text = TextBox3.Text Then
                    tbRk4.Text = 3
                End If
                If tbLex.Text = TextBox4.Text Then
                    tbRk4.Text = 4
                End If
                If tbLex.Text = TextBox5.Text Then
                    tbRk4.Text = 5
                End If
            End If
            If tbUni.Text <> "~" Then
                If tbUni.Text = TextBox1.Text Then
                    tbRk5.Text = 1
                End If
                If tbUni.Text = TextBox2.Text Then
                    tbRk5.Text = 2
                End If
                If tbUni.Text = TextBox3.Text Then
                    tbRk5.Text = 3
                End If
                If tbUni.Text = TextBox4.Text Then
                    tbRk5.Text = 4
                End If
                If tbUni.Text = TextBox5.Text Then
                    tbRk5.Text = 5
                End If
            End If


        End If
        'Find DTW minimum value
        Dim textBoxesW() As TextBox = {tbAct, tbBWay, tbBrist, tbCST, tbDex, tbEth, tbMaw, tbMedh, tbMedw, tbMyl, tbOTC, tbTev, tbTri, tbWay} 'make an array of textboxes for DTW companies
        Dim Wnumbers As New List(Of Double)
        Dim minNumberW As Double
        For Each tb As TextBox In textBoxesW


            If Double.TryParse(tb.Text, o) Then
                Wnumbers.Add(tb.Text)
            End If
        Next
        If Wnumbers.Count > 0 Then
            minNumberW = Wnumbers.Min
            tbDTWmin.Text = minNumberW
        End If
        For Each tb As TextBox In textBoxesW
            If tb.Text = tbDTWmin.Text Then
                tb.BackColor = Color.LawnGreen
            End If
            If tb.Text <> "~" Then
                tb.Text = FormatCurrency(tb.Text, 2)
            End If
        Next


        'Allocate CRW and NP8 in Ranking (tbRk6 is for Chester Rd and tbRk3 is for DE)
        If tbCRW.Text = "Yes" Or tbCRW.Text = "Y" Then
            tbRk6.Text = "1"
        End If
        If tbNP8.Text = "Y" Or tbNP8.Text = "Yes" Then
            lblNP8.Visible = True
            tbRk3.Text = "1"
        End If


        'Display full drug family based on GRPNo
        MyDetails.read2()
        MyTend.read3()
        eGraphics.DrawRectangle(myPen, 418, 215, 190, 620)
        Dim cte As Long = 0
        For i = 0 To 39999
            If DetRead.GRPNo(i) = tbGrpNo.Text And tbGrpNo.Text <> "~" Then
                cte = cte + 1
                a = i
                If DetRead.GRPNo(i) = tbGrpNo.Text And DetRead.BGP(i) = "P" Then


                    tbPAAH.Visible = True
                    tbPCol.Visible = True
                    tbPDE.Visible = True
                    tbPLex.Visible = True
                    tbPUni.Visible = True
                    tbPMaw.Visible = True
                    tbPMed.Visible = True
                    tbPShak.Visible = True
                    tbPTri.Visible = True
                    tbPWay.Visible = True


                    tbPAAH.Text = Tender.PAAH(i)
                    tbPCol.Text = Tender.PCOL(i)
                    tbPCST.Text = Tender.PCST(i)
                    tbPDE.Text = Tender.PDE(i)
                    tbPLex.Text = Tender.PLEX(i)
                    tbPUni.Text = Tender.PUNI(i)
                    tbPMaw.Text = Tender.PMAW(i)
                    tbPMed.Text = Tender.PMED(i)
                    tbPShak.Text = Tender.PSHA(i)
                    tbPTri.Text = Tender.PTRI(i)
                    tbPWay.Text = Tender.PWAY(i)
                End If
                If cte = 1 Then
                    lblFam.Visible = True
                    tbFam1.Visible = True
                    tbFam1.Text = ReadWrite.Prods(i)
                End If
                If cte = 2 Then
                    tbFam2.Visible = True
                    tbFam2.Text = ReadWrite.Prods(i)
                End If
                If cte = 3 Then
                    tbFam3.Visible = True
                    tbFam3.Text = ReadWrite.Prods(i)
                End If
                If cte = 4 Then
                    tbFam4.Visible = True
                    tbFam4.Text = ReadWrite.Prods(i)
                End If
                If cte = 5 Then
                    tbFam5.Visible = True
                    tbFam5.Text = ReadWrite.Prods(i)
                End If
                If cte = 6 Then
                    tbFam6.Visible = True
                    tbFam6.Text = ReadWrite.Prods(i)
                End If
                If cte = 7 Then
                    tbFam7.Visible = True
                    tbFam7.Text = ReadWrite.Prods(i)
                End If
                If cte = 8 Then
                    tbFam8.Visible = True
                    tbFam8.Text = ReadWrite.Prods(i)
                End If
                If cte = 9 Then
                    tbFam9.Visible = True
                    tbFam9.Text = ReadWrite.Prods(i)
                End If
                If cte = 10 Then
                    tbFam10.Visible = True
                    tbFam10.Text = ReadWrite.Prods(i)
                End If
                If cte = 11 Then
                    tbFam11.Visible = True
                    tbFam11.Text = ReadWrite.Prods(i)
                End If
                If cte = 12 Then
                    tbFam12.Visible = True
                    tbFam12.Text = ReadWrite.Prods(i)
                End If
                If cte = 13 Then
                    tbFam13.Visible = True
                    tbFam13.Text = ReadWrite.Prods(i)
                End If
                If cte = 14 Then
                    tbFam14.Visible = True
                    tbFam14.Text = ReadWrite.Prods(i)
                End If
                eGraphics.DrawRectangle(myPen, 608, 215, 245, 620)
            End If
        Next


        'Find minimum PI tender price


        Dim textBoxesPI() As TextBox = {tbPAAH, tbPLex, tbPCol, tbPDE, tbPUni, tbPCST, tbPMaw, tbPShak, tbPMed, tbPTri, tbPWay} 'make an array of your textboxes for PI products
        Dim PInumbers As New List(Of Double)
        Dim minNumberPI As Double
        For Each tb As TextBox In textBoxesPI
            If Double.TryParse(tb.Text, o) Then
                PInumbers.Add(tb.Text) 'if the textbox contains a number, add it to the list
            End If
        Next


        If PInumbers.Count > 0 Then
            'at least one textbox contains number
            minNumberPI = PInumbers.Min
            tbPImin.Text = minNumberPI
        End If
        For Each tb As TextBox In textBoxesPI
            If tb.Text = tbPImin.Text Then
                tb.BackColor = Color.LawnGreen
            End If
            If tb.Text <> "~" Then
                tb.Text = FormatCurrency(tb.Text, 2)
            End If
        Next








        eGraphics.DrawRectangle(myPen, 8, 215, 225, 275)




        eGraphics.DrawRectangle(myPen, 233, 215, 185, 620)
    End Sub
 
Last edited by a moderator:
The first thing to note is that you need to remember to wrap you code in Code Tags and not Quote Tags to make things easier to read but 10 out of 10 for trying.

As to your code, I am not even going to try to read it and figure out where you need to place the BacgroundWorker. The only thing I will repeat is to keep going over the link I supplied until in really does sink in. Forget your current program and write the example programs given in the link to fully realise why things are working the way they do. You will only realise the full potential of Multi-Threading by experimentation and experience.

Go for it.
 
Cor. That's quite a block of code. Tell you what, for this iteration of the program don't bother with the background worker, just put this at the start of your FOR loop that does 4000 things:

VB.NET:
If i Mod 10 = 0 Then Application.DoEvents()

viz:

VB.NET:
    For i = 0 To 39999
           If i Mod 10 = 0 Then Application.DoEvents()

           If DetRead.GRPNo(i) = tbGrpNo.Text And tbGrpNo.Text <> "~" Then

Yes, it's dirty but.. erm.. so are a lot of the other things in there :D

"We'll solve em in the rewrite"

Oh, and if those drawrectangle() calls are supposed to be some sort of progress bar, put Application.DoEvents() after those too (but in the loop, mod it by 10 or more, as per above)
 
Ok Guys. I know the code is messy, but I'm completely new to vb programming so tend to write things down as I want them to happen. No doubt when everything works I'll get down to re-writing and simplifying the code. In the meantime I've worked out how to make the BackgroundWorker do its job. It now handles the time consuming process of reading text files into variables; however, the one thing I haven't figured out is how to make a ProgressBar work. Any help on that would be appreciated. Incidentally the DrawRectangle codes are nothing to do with Progress bar; simply a way of drawing rectangles around blocks of textboxes on the form to make the form clearer to read.
 
the one thing I haven't figured out is how to make a ProgressBar work.
As is always the case, if you want to report absolute progress then you have to be able to calculate it. It's up to you how you do that, e.g. simply divide the number of files processed by the total number and multiply by 100 to get a percentage. You then call the ReportProgress method of the BackgroundWorker in the DoWork event handler each time you want to update the progress and you actually update the UI with the progress in the ProgressChanged event handler. Here's one I prepared earlier:

Using the BackgroundWorker Component
 
Back
Top