Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Go Back  Xtreme Visual Basic Talk > > > Progress bar and open file dialog VB2010


Reply
 
Thread Tools Display Modes
  #1  
Old 06-07-2011, 03:18 PM
lewist57 lewist57 is offline
Newcomer
 
Join Date: Aug 2008
Posts: 22
Default Progress bar and open file dialog VB2010


Can anyone provide suggested code snippet that would allow a progress bar to track the input of a text file? Normally I would not bother with this, but the text files are > 10,000 lines long, which is noticable even on a fast machine. The number of lines is variable, so I would assume that one would not use a fixed value to calculate when the progress bar goes 100%.
Reply With Quote
  #2  
Old 06-08-2011, 01:28 AM
passel's Avatar
passelProgress bar and open file dialog VB2010 passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

Not as familiar with .Net file I/O, and don't know how you're reading the lines, but if you know the length of the file, and can accumlate the line lengths (+2 assuming LF+CR terminates the lines) as you read the lines, then the percentage of file read would be (accumlated_value / file_length) * 100.
VB6 has the Seek function to determine byte offset of the next read, so that could be use as well to see how far into the file the read was, without having to accumlate line lengths. If VB.Net I/O has a method or property to return the current file pointer position within a file that you are reading, then (position / file_length ) * 100 would do.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #3  
Old 06-08-2011, 07:18 AM
lewist57 lewist57 is offline
Newcomer
 
Join Date: Aug 2008
Posts: 22
Default

Thanks, will check into that.
Reply With Quote
  #4  
Old 06-08-2011, 11:17 AM
AtmaWeapon's Avatar
AtmaWeaponProgress bar and open file dialog VB2010 AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

While random access will give you some idea, the only parts of it you really need are a sense of where you are in the file and how big the file is. But that's not the (perceived) hard part. The hard part is you need a thread. Let's defer that and talk about how you can figure out what your file progress is.

The standard loop for reading a text file in .NET looks something like this:
Code:
Using reader As New StreamReader(filePath)
    While Not reader.EndOfStream
        Dim line = reader.ReadLine()
        ' Do something with the line
    End While
End Using
If you look at the StreamReader API, you won't find anything that tells you where you are in the file or where the end may be; all you get is an answer to, "Am I at the end?". But look at the BaseStream property; it returns a Stream that represents the low-level stream being used to read the file. If you look at the Stream API you'll see two useful properties: Length and Position. They show you the size of the file and where you are in the file, respectively.

So you can augment the loop to get an idea of where you are in the file like so:
Code:
Using reader As New StreamReader(filePath)
    Dim totalBytes As Long = reader.BaseStream.Length
    While Not reader.EndOfStream
        Dim line = reader.ReadLine()
        ' Do something with the line
        Dim position As Long = reader.BaseStream.Position
    End While
End Using
Once position is set, you know how many bytes you've read and how many are left. That's all you need to know the amount remaining and is easy to convert to a percentage. But if you implement this as-is, you'll probably notice that the progress bar doesn't change until the file is finished. Why?

Despite putting on the appearance of doing multiple things at once, the default .NET program runs on one thread and thus can only do one thing at a time. If you're in a loop reading the file, the program can't change how the progress bar is rendered. When you finish the loop, you let go of the thread and suddenly the progress bar is updated.

To get around this, you need a way to make sure the UI thread is free to render the progress bar when it's updated. You've got two choices.

Some people will tell you to use Application.DoEvents(). I don't like it, but the reason only makes sense in larger applications. What it does is kind of interesting; it's as if it pushes the pause button on your method and tells the UI thread to do anything that's waiting on the UI thread. So if you use this appropriately, your progress bar will update and everything's shiny. It's not how I do it. But for a simple case like this it's certainly easy.

When I do it, I use a second thread to load the file. This has some tricks to look out for. Controls should only be accessed from the UI thread; if you try and use a control from another thread weird stuff can happen. So updating the progress bar requires you to make sure that you have a method that can be pushed ("marshaled") to the UI thread and executed. It's not really hard once you get the hang of it, and MS has provided a convenient class that does all the work for you.

The BackgroundWorker class has a DoWork event it raises when it's been asked to start its work. This event is raised on a worker thread. You do whatever work you need to do on that thread and use the ReportProgress() method and the Result property of the DoWorkEventArgs you get. Confused? The basic pattern for a DoWork handler looks like this:
Code:
Sub Handle_DoWork(..., ByVal e As DoWorkEventArgs)
    While someCondition
        DoSomething()
        ' Optional progress reports
        Dim progress As Integer = <calculate progress percent>
        Dim progressStatus = <more information if needed>
        ReportProgress(progress, progressStatus)
    End While

    ' Optional final result
    Dim result = <do something to determine a final result if applicable>
    e.Result = result
End Sub
Since DoWork is on the worker thread you cannot touch controls from that event handler. If you need to update a control, it is appropriate to do so one of two ways. You can use marshaling or you can use the optional Object parameter of ReportProgress() to send information needed to update the control. This raises a ProgressChanged event on the UI thread where it is safe to update the control. Think of it like the DoWork handler is a bank vault and ReportProgress() and e.Result are the only doors that lead out. Add more doors and the vault is compromised. When DoWork is finished, the worker raises its RunWorkerCompleted event on the UI thread. If you set e.Result in DoWork, the RunWorkerCompletedEventArgs parameter to RunWorkerCompleted will have that object.

Enough theory. Let's talk application. I've attached a program that uses both techniques even though I don't like Application.DoEvents().

In both cases, I introduce a 50ms delay between reading each line to make the file seem bigger. Note that if you're reading a big file, you need to throttle your progress reports. If you're calling DoEvents() or raising ProgressChanged 10 times a second your form's going to appear unresponsive because it's so busy updating the progress bar it can't do anything else. When I don't incorporate sleeps (which you shouldn't use) I throttle like this:
Code:
Dim lines As New List(Of Lines)()
While not reader.EndOfStream
    lines.Add(reader.ReadLine)

    If lines.Count = 100 Then
        Dim sentLines() As String = lines.ToArray()
        < report progress with the lines >
        lines.Clear()
    End If
End While

If lines.Count > 0 Then
    Dim sentLines() As String = lines.ToArray()
    < report progress with the lines >
End If
It's important to send a copy of the list, not the list itself. See if you can figure out why.

You may notice the progress bar doesn't seem to update much; it goes through only 3 or 4 steps. It turns out the StreamReader reads 1KB blocks from the file at a time and buffers them. So until you've read 1KB of data the position is at 1024; after that it moves to 2048. It's apparent in this file but not for a much larger file. If it really bugged you, you'd need to quit using StreamReader and use FileStream directly; that's a major pain and not really worth it.
Attached Files
File Type: zip LoadFileDemo.zip (12.7 KB, 24 views)
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #5  
Old 06-09-2011, 01:01 PM
passel's Avatar
passelProgress bar and open file dialog VB2010 passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

Quote:
Originally Posted by AtmaWeapon View Post
.... But if you implement this as-is, you'll probably notice that the progress bar doesn't change until the file is finished. Why?

Despite putting on the appearance of doing multiple things at once, the default .NET program runs on one thread and thus can only do one thing at a time. If you're in a loop reading the file, the program can't change how the progress bar is rendered. When you finish the loop, you let go of the thread and suddenly the progress bar is updated.
...
Being relatively new to VB.net, I'm trying to develop a feel for what VB.net does and doesn't do, especially in regards to how things used to be done in VB6 and how they should now be properly done in VB.net.
So, using your code I commented out the DoEvents to verify that the progress bar didn't update until the file read was finished.
(The main reason for doing this was because I assumed there might be a third option, which would be to provide a call to pbProgress.Refresh instead of DoEvents, when we wanted to update the progress bar. I was guessing the .Refresh might be handled immediately, rather than deferred).
But, surprisingly, without the DoEvents the progress bar still updated as the file was read. So, I thought, perhaps the System.Threading.Thread.Sleep(50) call might be allowing the UI thread to process the update, so I commented that out.
The progress bar still updated as the file was read.
I then thought, well you're update txtFileContents as well, and that is part of the GUI, so maybe that causes events to be processed. Commented that out, changed the MakeFile Sub to create a larger file, and gave it another shot.
The progress bar still updated as the file was read.
A little more thought and I realized that the reason for the progress bar updating was because of the Debug.WriteLine in the UpdateProcess Sub and running in the IDE.
Commenting out the Debug.WriteLine finally got the behavior you describe.
I then added a static past history to the LoadWithDoEvents
Static LastValue As Integer

and in place of the DoEvents added.
Code:
'
        If LastValue <> pbProgress.Value Then
          pbProgress.Refresh()
          LastValue = pbProgress.Value
        End If
Since .Value is an integer, it will only change a maximum of 100 times regardless of the size of the file so gives us good resolution on the progress bar updates, without much tax on the file reading process.

Of course, I'm not saying this is better than a background thread. A background thread will allow the whole GUI to refresh when needed, not just the progress bar, but it is an alternative to using DoEvents(), if all you want to do is periodically update the status bar.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010 Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
 
Progress bar and open file dialog VB2010
Progress bar and open file dialog VB2010
 
-->