ProgressBar zur Dateigröße einer Image Datei

  • VB.NET
  • .NET (FX) 1.0–2.0

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von diylab.

    ProgressBar zur Dateigröße einer Image Datei

    Hallo Leute,
    ich hab noch nicht so die Erfahrung mit VB2010 und bräuchte mit einer ProgressBar etwas hilfe.

    Ich lasse derzeit mit diesem Code ein Image einer Diskette erstellen:

    Quellcode

    1. oProcess = System.Diagnostics.Process.Start(My.Application.Info.DirectoryPath + "\rawwritewin.exe", "--read " + Chr(34) + My.Application.Info.DirectoryPath + "\Disk2.ima" + Chr(34))
    2. oProcess.WaitForExit()


    Dazu würde ich gerne eine ProgressBar haben die den Fortschritt anzeigt.
    Es müsste also irgend wie die Datei größe abgefragt werden, ob die 1440 KB schon erreicht wurden, und das irgend wie mit der ProgressBar verknüpft werden.

    Ich hoffe ihr könnt mir da weiter helfen.
    Mfg, Aod

    Aod schrieb:

    und das irgend wie mit der ProgressBar verknüpft werden.
    Ich bin mir nicht sicher, ob die Länge ühaupt ausgelesen werden kann.
    Wenn ja:
    Lies sie in einer Timer.Tick-Prozedur aus und zeige sie an.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also ich habe es jetzt so probiert:

    Quellcode

    1. Dim WithEvents oTimer As Timer
    2. Dim DateiTick As String = ""
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. oProcess = System.Diagnostics.Process.Start(My.Application.Info.DirectoryPath + "\rawwritewin.exe", "--read " + Chr(34) + My.Application.Info.DirectoryPath + "\Disk2.ima" + Chr(34))
    5. DateiTick = My.Application.Info.DirectoryPath + "\Disk2.ima"
    6. oTimer = New Timer
    7. oTimer.Interval = 50
    8. oTimer.Start()
    9. oProcess.WaitForExit()
    10. MsgBox("Auslesen abgeschlossen")
    11. End Sub
    12. Private Sub oTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles oTimer.Tick
    13. ProgressBar1.Minimum = 0
    14. ProgressBar1.Maximum = 1474560
    15. If IO.File.Exists(DateiTick) = True Then
    16. Dim infoReader As System.IO.FileInfo
    17. infoReader = My.Computer.FileSystem.GetFileInfo(DateiTick)
    18. ProgressBar1.Value = CInt(infoReader.Length)
    19. End If
    20. End Sub



    Ich denke mal sauber gelöst ist was anderes?
    Denn auf der Form bewegt sich die Progressbar nur, wenn ich oProcess.WaitForExit() raus lasse. Allerdings brauch ich das wait ?(

    Aod schrieb:

    bewegt sich die Progressbar nur
    Dann musst Du einen anderen Timer verwenden, der in einem anderen Thread arbeitet: System.Threading.Timer Gugst Du hier.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hmm,
    also wenn ich es richtig sehe habe ich den Timer so in einem anderen Thread:

    Quellcode

    1. Imports System
    2. Imports System.Threading
    3. Private demoThread As Thread = Nothing
    4. Dim DateiTick As String = ""
    5. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    6. oProcess = System.Diagnostics.Process.Start(My.Application.Info.DirectoryPath + "\rawwritewin.exe", "--read " + Chr(34) + My.Application.Info.DirectoryPath + "\Disk2.ima" + Chr(34))
    7. DateiTick = My.Application.Info.DirectoryPath + "\Disk2.ima"
    8. ProgressBar1.Minimum = 0
    9. ProgressBar1.Maximum = 1474560
    10. Me.alarm = New Threading.Timer(AddressOf Tick, Nothing, 0, 0)
    11. Me.alarm.Change(1, 1)
    12. oProcess.WaitForExit()
    13. Me.alarm.Change(Timeout.Infinite, Timeout.Infinite)
    14. MsgBox("Auslesen abgeschlossen")
    15. ProgressBar1.Value = 0
    16. End Sub
    17. Private Sub Tick(ByVal state As Object)
    18. Me.demoThread = New Thread(New ThreadStart(AddressOf Me.Test123))
    19. Me.demoThread.Start()
    20. End Sub
    21. Public Sub Test123()
    22. If IO.File.Exists(DateiTick) = True Then
    23. Dim infoReader As System.IO.FileInfo
    24. infoReader = My.Computer.FileSystem.GetFileInfo(DateiTick)
    25. ProgressBar1.Value = CInt(infoReader.Length)
    26. End If
    27. End Sub


    Allerdings bekomme ich nun diese Fehlermeldung bei ProgressBar1.Value:

    Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement ProgressBar1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.


    Und ich verstehe nicht wie ich es anders aufrufen könnte .


    NACHTRAG:
    Ich habe die eine Sub nun so mit invoke hoffentlich richtig geändert:

    Quellcode

    1. Public Sub Test123()
    2. If Me.InvokeRequired Then
    3. Me.Invoke(New MethodInvoker(AddressOf Test123))
    4. Else
    5. ProgressBar1.Minimum = 0
    6. ProgressBar1.Maximum = 1474560
    7. If IO.File.Exists(DateiTick) = True Then
    8. Dim infoReader As System.IO.FileInfo
    9. infoReader = My.Computer.FileSystem.GetFileInfo(DateiTick)
    10. ProgressBar1.Value = CInt(infoReader.Length)
    11. End If
    12. End If
    13. End Sub


    Das Problem ist aber nun wieder das alte, die Progressbar bewegt sich nicht während der "oProcess" noch läuft.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Aod“ ()

    Aod schrieb:

    hoffentlich richtig
    Nö.
    Nicht der Prozess soll invoked werden, sondern lediglich die Anzeige.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.Threading
    3. Public Class Form1
    4. Private demoThread As Threading.Timer
    5. Private DateiTick As String = ""
    6. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    7. DateiTick = My.Application.Info.DirectoryPath + "\Disk2.ima"
    8. Dim oProcess As New Process
    9. oProcess.StartInfo.FileName = My.Application.Info.DirectoryPath & "\rawwritewin.exe"
    10. oProcess.StartInfo.Arguments = "--read """ & DateiTick & """"
    11. oProcess.Start()
    12. ProgressBar1.Minimum = 0
    13. ProgressBar1.Maximum = 1474560
    14. Me.demoThread = New Threading.Timer(AddressOf Test123)
    15. Me.demoThread.Change(0, 500)
    16. oProcess.WaitForExit()
    17. MsgBox("Auslesen abgeschlossen")
    18. Me.SetProgress(0)
    19. Me.demoThread.Change(Timeout.Infinite, Timeout.Infinite)
    20. End Sub
    21. Public Sub Test123(xx As Object)
    22. Dim fi As New System.IO.FileInfo(DateiTick)
    23. If fi.Exists Then
    24. Me.Invoke(Sub() Me.SetProgress(CInt(fi.Length)))
    25. End If
    26. End Sub
    27. Private Sub SetProgress(value As Integer)
    28. ProgressBar1.Value = value
    29. ProgressBar1.Update()
    30. End Sub
    31. End Class
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Erstmal danke für den Code, habe beim Invoken total den überblick verloren.

    Nun zu der schlechten Nachricht, die Progressbar fängt leider immernoch erst an, wenn oProcess.WaitForExit() vorbei ist.
    Ich verstehe es auch nicht...

    Wenn ich einen Haltepunkt setze und dann Einzelschritte mache, kann ich sehen das die Subs für die Progressbar erst abgearbeitet werden, wenn der Schritt oProcess.WaitForExit() abgearbeitet wurde. Es scheint also nicht Parallel zu laufen, aber warum?


    NACHTRAG:
    Ok, hab es schon so halb hinbekommen. Es liegt am WaitforExit:
    waitforexit stroppt form beim laden
    vb-paradise.de/index.php/Thread/?postID=143674#post143674

    NACHTRAG2:
    Spoiler anzeigen

    Quellcode

    1. Imports System
    2. Imports System.Threading
    3. Public Class Form1
    4. Private demoThread As Threading.Timer
    5. Private DateiTick As String = ""
    6. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    7. DateiTick = My.Application.Info.DirectoryPath + "\Disk2.ima"
    8. ProgressBar1.Minimum = 0
    9. ProgressBar1.Maximum = 1474560
    10. Me.demoThread = New Threading.Timer(AddressOf Test123)
    11. Me.demoThread.Change(0, 500)
    12. Dim oProcess As New Process
    13. oProcess.StartInfo.FileName = My.Application.Info.DirectoryPath + "\Vorlagen\Diskette\rawwritewin.exe"
    14. oProcess.StartInfo.Arguments = "--read """ & DateiTick & """"
    15. oProcess.EnableRaisingEvents = True
    16. AddHandler oProcess.Exited, AddressOf processExited
    17. oProcess.Start()
    18. End Sub
    19. Private Sub processExited(ByVal sender As Object, ByVal e As EventArgs)
    20. MsgBox("Auslesen abgeschlossen")
    21. Me.SetProgress(0)
    22. Me.demoThread.Change(Timeout.Infinite, Timeout.Infinite)
    23. End Sub
    24. Public Sub Test123(xx As Object)
    25. Dim fi As New System.IO.FileInfo(DateiTick)
    26. If fi.Exists Then
    27. Me.Invoke(Sub() Me.SetProgress(CInt(fi.Length)))
    28. End If
    29. End Sub
    30. Private Sub SetProgress(value As Integer)
    31. ProgressBar1.Value = value
    32. ProgressBar1.Update()
    33. End Sub
    34. End Class


    Jetzt bekomme ich nur wieder das Problem mit "Ungültiger threadübergreifender Vorgang"

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Aod“ ()

    Aod schrieb:

    "Ungültiger threadübergreifender Vorgang"
    Dann lies mal die Posts oben richtig durch.
    Ansonsten pack das Process-Handling in einen separaten Thread, BackgroundWorker dürfte reichen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Aod schrieb:

    Jetzt bekomme ich nur wieder das Problem mit "Ungültiger threadübergreifender Vorgang"

    Hallo @Aod,
    da mich das Thema auch ein bisschen interessiert hat, möchte ich Dir noch einen leicht anderen Ansatz geben - mit BackgroundWorkern.
    So ein BackgroundWorker ist eine altbewährte Möglichkeit, solche einfachen Sachen leicht umzusetzen, da jeder Worker nicht nur einen Arbeitsthread, sondern auch zwei Andere hat, wo z.B. der aktuelle Status threadsicher abgegriffen werden kann und der Worker meldet auch, wenn er fertig ist - das kann man auch gut gebrauchen.

    Anbei ein ganzes Testprojekt als Anhang, dort kannst Du das mal ausprobieren.
    Für die Image-Erstellung habe ich eine Simulation benutzt, dort würde dann Dein externes Programm laufen.

    Ich benutze zwei dieser BackgroundWorker - dadurch friert auch die Form nicht ein.
    Der eine Worker kümmert sich um das Schreiben des Images, der Andere um das Lesen der Image-Größe.

    Das Programm ist in C#, aber Du kannst es mühelos in VB konvertieren (Konverter sind in meiner Signatur).
    Auf der Form selbst ist nur eine ProgressBar und ein Button - also kein Problem.
    Das Programm ist schnell entstanden, ist also vielleicht nicht unbedingt der Stein der Weisen ;) ..

    Hier der C# Code:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.ComponentModel;
    3. using System.IO;
    4. using System.Threading;
    5. using System.Windows.Forms;
    6. namespace DiskImageProgress
    7. {
    8. public partial class frmMain : Form
    9. {
    10. private BackgroundWorker bwWrite = new BackgroundWorker();
    11. private BackgroundWorker bwRead = new BackgroundWorker();
    12. public frmMain()
    13. {
    14. InitializeComponent();
    15. // BackGroundWorker (Image)
    16. bwWrite.WorkerSupportsCancellation = false;
    17. bwWrite.WorkerReportsProgress = false;
    18. bwWrite.DoWork += new DoWorkEventHandler(bwWrite_DoWork);
    19. bwWrite.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwWrite_RunWorkerCompleted);
    20. // BackGroundWorker (Image-Größe)
    21. bwRead.WorkerSupportsCancellation = false;
    22. bwRead.WorkerReportsProgress = true;
    23. bwRead.DoWork += new DoWorkEventHandler(bwRead_DoWork);
    24. bwRead.ProgressChanged += new ProgressChangedEventHandler(bwRead_ProcessChanged);
    25. bwRead.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwRead_RunWorkerCompleted);
    26. }
    27. /// <summary>
    28. /// Arbeitsthread zum Erstellen eines Disketten-Images.
    29. /// Dadurch friert die Form nicht ein.
    30. /// </summary>
    31. /// <param name="sender"></param>
    32. /// <param name="e"></param>
    33. private void bwWrite_DoWork(object sender, DoWorkEventArgs e)
    34. {
    35. // Simulation zum Erstellen eines Disketten-Images mit 1,44MB (1440 Blöcke mit 1024 Byte))
    36. // 'Thread.Sleep' ist wichtig, damit der Vorgang nicht zu schnell geht
    37. using (StreamWriter sw = File.CreateText(Application.StartupPath + @"\diskimage.img"))
    38. {
    39. string buffer = string.Empty.PadRight(1024, '*');
    40. for (int i = 0; i < 1440; i++)
    41. {
    42. sw.Write(buffer);
    43. sw.Flush();
    44. Thread.Sleep(1);
    45. }
    46. }
    47. // Dem Image-Größe Thread ein bisschen Zeit geben,
    48. // damit der Status und die ProgressBar den richtigen Wert anzeigen
    49. Thread.Sleep(500);
    50. }
    51. /// <summary>
    52. /// Thread zum Image Erstellen ist fertig
    53. /// </summary>
    54. /// <param name="sender"></param>
    55. /// <param name="e"></param>
    56. private void bwWrite_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    57. {
    58. // Der Thread zum Erstellen des Images ist komplett - mach hier etwas bei Bedarf..
    59. }
    60. /// <summary>
    61. /// Image-Größe Arbeitsthread
    62. /// </summary>
    63. /// <param name="sender"></param>
    64. /// <param name="e"></param>
    65. private void bwRead_DoWork(object sender, DoWorkEventArgs e)
    66. {
    67. BackgroundWorker worker = sender as BackgroundWorker;
    68. FileInfo fi;
    69. int loopCounter = 0;
    70. while (bwWrite.IsBusy)
    71. {
    72. fi = new FileInfo(Application.StartupPath + @"\diskimage.img");
    73. Thread.Sleep(10);
    74. loopCounter++;
    75. if (loopCounter % 10 == 0)
    76. worker.ReportProgress((int)fi.Length);
    77. }
    78. }
    79. /// <summary>
    80. /// Status des Image-Größe-Threads
    81. /// </summary>
    82. /// <param name="sender"></param>
    83. /// <param name="e"></param>
    84. private void bwRead_ProcessChanged(object sender, ProgressChangedEventArgs e)
    85. {
    86. // Schreibt den aktuellen Status in den Form-Kopf
    87. this.Text = e.ProgressPercentage.ToString("N0") + " Bytes erstellt..";
    88. // Zeigt den aktuellen Status in der ProgressBar
    89. progressBarWriteImage.Value = ((int)((e.ProgressPercentage) * 100 / 1474560));
    90. }
    91. /// <summary>
    92. /// Thread zum Anzeigen der Image-Größe ist fertig
    93. /// </summary>
    94. /// <param name="sender"></param>
    95. /// <param name="e"></param>
    96. private void bwRead_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    97. {
    98. // Der Thread zum Anzeigen der Image-Größe ist komplett - mach hier etwas bei Bedarf..
    99. // this.Text = "Das Image wurde komplett erstellt!";
    100. }
    101. /// <summary>
    102. /// Button 'Image Erstellen'
    103. /// </summary>
    104. /// <param name="sender"></param>
    105. /// <param name="e"></param>
    106. private void btnWriteImage_Click(object sender, EventArgs e)
    107. {
    108. if (!bwWrite.IsBusy || !bwRead.IsBusy)
    109. {
    110. bwWrite.RunWorkerAsync();
    111. bwRead.RunWorkerAsync();
    112. }
    113. else
    114. {
    115. MessageBox.Show("Mindestens ein Thread ist noch nicht fertig.");
    116. }
    117. }
    118. }
    119. }



    Das sieht dann so aus:


    Es funktioniert einwandfrei - nur falls jetzt Jemand der Meinung ist "geht nicht bei mir.." ^^
    Vielleicht siehst Du es als Anregung und entwickelst es weiter?
    Falls Du Fragen zu oben gezeigtem Code hast, nenne die Zeilennummer(n) und frag nach.

    LG und viel Spaß beim Tüfteln,
    Bruno
    Dateien

    ErfinderDesRades schrieb:

    Das scheint mir absurd, zum Lesen einen Extra-BW zu bemühen, der nix anneres liest, als was man grad geschrieben hat.
    Also was man grad geschrieben hat, braucht man doch nicht wieder einzulesen - das weiß man doch so.


    Der TE hat ein externes Programm, dass keinen Status zurück gibt!
    Darum möchte er den aktuellen Status der Datei wissen (wozu auch immer, aber sieht nett aus 8-) ).
    In meinem Programm wird das Schreiben der Image-Datei lediglich simuliert und muss an dieser Stelle durch sein Teil ersetzt werden.

    Jetzt verstanden?
    ja - bisserl langsam, und auch weil das Thema nu shcon bischen länglich ist - sorry. :saint:

    Edit: Aber um alle 300ms eine Dateigröße auszulesen braucht man doch keinen BW!
    Da nimmt man doch einen Timer!

    Und auch um ein externes Proggi zu starten braucht man kein BW. Das startet man halt, und dann läuft das ja per se in einem anneren Thread - es ist ja ein unabhängiges Proggi.

    Also null BW, einfach das Proggi starten, und mittm Timer nachgucken, obs Fortschritte macht.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    diylab schrieb:

    einen Impuls setzen
    indem Du die Hausaufgaben von @Aod machst?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    indem Du die Hausaufgaben von @Aod machst?

    Weißt Du, wenn ich im Internet irgend etwas suche, finde ich zu 90% so ein Müll, wo 9x kluge User dem TE entweder auf die Forum- oder Internetsuche verweisen oder ihn so lange versuchen zu belehren, bis der Thread so durcheinander ist, bis niemand mehr durchsieht.
    Meistens sind solche Threads dann auch noch gespickt mit Kommentaren von Usern, die zu jedem Pups Ihren Senf dazugeben müssen - egal ob hilfreich oder nicht.

    Da ist es doch schon besser, INHALTE zu finden - oder?
    Jeder der lernen möchte, wird dies auch tun und jeder der eine schnelle Lösung braucht, wird eher unwillig lernen und sich über Lösungen freuen.

    Also überlass das mir, wie ich wem helfe - bin schon groß.
    Ok?
    Hallo Leute,
    erstmal danke für die ganzen Posts. Ich denke ich werde wieder zum Timer zurück kehren. Damit sollte es jetzt gehen, da ich ja nicht mehr WaitforExit sondern nun
    oProcess.EnableRaisingEvents = True
    AddHandler oProcess.Exited, AddressOf processExited
    benutze. Ich bin noch nicht zum ausprobieren gekommen, aber das hole ich noch nach.

    @diylab,
    danke für deine mühe mit dem Beispiel Program, ich werd es mir mal genauer angucken ob ich da noch was raus lernen kann.

    @RodFromGermany,
    Ein bisschen hatte ich mich letztens schon mit dem Background worker rumgeschlagen, aber es hatte nicht geklappt. Hatte mich einfach zu sehr auf das waitforexit festgefahren. Hätte nicht gedacht das waitforexit wirklich alles anhält, egal ob etwas in einem anderen thread läuft oder nicht.

    @Allgemeinheit ^^
    Ich verstehe RodFromGermanys ansicht, das es besser ist jemandem zu zeigen wie man etwas rausfindt, da so der lern effeckt größer ist, und man so beim nächsten problem besser weiß wie man die lösung findet.
    Aber auch diylabs antwort finde ich gut, denn so kann man besser erkennen wie etwas funktioniert. Also danke an euch beide.

    Ich probier dann mal noch ein paar sachen aus, ob es nun klappt.
    Wenn ich nicht weiter komme melde ich mich wieder ;)

    ErfinderDesRades schrieb:

    Edit: Aber um alle 300ms eine Dateigröße auszulesen braucht man doch keinen BW!
    Da nimmt man doch einen Timer!

    "man" hat mich noch nie interessiert.
    Viele Wege führen nach Rom, aber meiner kommt bis jetzt an - der Rest waren nur Tipps und Blasen (bis jetzt!) :D .
    Ich könnte Dir noch min. 20 andere Wege zum Ziel zeigen, aber darum geht es garnicht.
    Meine Version benutzt halt BackgroundWorker und vielleicht ist es in einem anderen Kontext für Suchende ja interessant.
    Der TE kann Timer nehmen bis die Uhr glüht - wie er halt möchte.
    tja, ich sehe halt immer nach guten und besseren Lösungen. Klar führen viele Wege nach Rom, aber als Programmierer nimmt man immer den kürzesten.
    Also nach meinem Verständnis kann man (anders als in vielen anneren Bereichen des Lebens) beim Programmieren Lösungen i.a. ziemlich klar in eine Rangordnung von besser und schlechter bringen.
    Und anzuwenden ist logisch immer das Beste, was eim grad bekannt ist.

    (ach ein komplett offtopic mussich noch loswerden: Deine "vogonische Dichtkunst" von heut morgen war für mich bereits das Highlight des Tages :thumbsup: )