Angepinnt [Sammelthread] Code-Korrektur

  • VB.NET

Es gibt 123 Antworten in diesem Thema. Der letzte Beitrag () ist von FormFollowsFunction.

    [Sammelthread] Code-Korrektur

    Da man häufiger User sieht die (funktionierenden) Code posten welcher aber leider eher schlecht als recht umgesetzt wurde, dachte ich mir mal ein Code-Korrektur-Sammel-Thread zu eröffnen. Grade als Programmieranfänger hat man es ja schwer den eigenen Code einzuschätzen - funktionieren ist eben nicht alles.

    Das soll hier möglichst kein Diskussion-Thread werden. Wenn ein Helfer Fehler macht kann man ja eine PN statt einen Post schreiben - nur so bleibt hier eine gewisse Übersicht bestehen. Wenn der Thread gut läuft hätte man irgendwann eine Art Sammlung "guter Code vs. schlechter Code" von der man wiederum viel lernen kann.

    Wie stelle ich mir das hier vor?

    Der Hilfe suchende: postet einen Code-Ausschnitt der folgende Kriterien erfüllt:
    - der Code muss Option Strict On programmiert sein - wird langweilig immer wieder zu sagen dass 'String + Double kein Integer ergibt'
    - der Code "funktioniert" aber man ist sich nicht sicher ob er auch gut umgesetzt ist
    - keine gezielte Frage zum Code, dafür ist das Forum besser geeignet!
    - ein relativ kurzer Code-Ausschnitt der ein bestimmtes Problem löst - niemand will hier Romane verbessern. Wer alles in eine 3km hohe Methode packt, dem ist nicht mehr zu helfen^^
    - Controls und Variablen sollten anständig benannt sein. Evtl das ein oder andere Kommentar setzten, damit klar wird um welche Controls es sich handelt
    - Der Code muss anständig formatiert sein! Es gibt einen Vorschau-Button um das vor dem posten zu prüfen und eine kleine Anleitung für Unwissende
    - Eine kleine Beschreibung was der Code überhaupt bezwecken soll wäre angebracht


    Der Helfende: Er und seine Antwort sollte auch ein paar Punkte erfüllen:
    - Helfer soll mehr Wissen haben als der Hilfsbedürftige - man geht schließlich auch nicht ins Cockpit um dem Piloten zu sagen wie er fliegen soll
    - möglichst keine "Einzeiler-Antworten" (außer der Code ist wirklich hoffnungslos oder fehlerfrei)
    - den bestehenden Code übernehmen und entsprechend kommentieren - was wurde gut/schlecht umgesetzt, wo sind die Fehler? Was könnte man anders machen, etc
    - vllt auch eine abgeänderte oder eigene Version posten - aber bitte mit Kommentaren UND Option Strict On
    - evtl nicht alles zu hart anpacken. Die groben Fehler raus, Kleinigkeiten ( My-Namespace statt System.IO etc ) aufzeigen.
    - wenn möglich ein paar hilfreiche Links nennen


    Beispiel


    Der 'Hilfsbedürftige' (da muss ein VBPler den Kopf für hinhalten, sry^^):

    Spoiler anzeigen
    Hallo. Der Code soll prüfen ob eine Trial-Version meines Programms abgelaufen ist. In der Data_z.cfg wird dazu beim ersten Programmstart das Ablaufdatum (also Jetzt + Gültigkeitsdauer) hinterlegt und bei jedem Programmstart mit der aktuellen Zeit vergleichen. Ist die Gültigkeitsdauer überschritten wird das Programm einfach beendet.

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.IO
    3. Public Class Form1
    4. Dim Datum_Erststart As Date = Date.Now.Date
    5. Dim Datei As String
    6. Dim Pfad As String = "C:\Users\zeus\Desktop\Neuer Ordner (8)\Data_z.cfg"
    7. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    8. Label1.Text = CStr("Aktuelles Datum: " & Datum_Erststart)
    9. 'Ermitteln ob Datei vorhanden ist,wenn ja auslesen und vergleichen mit heutigem Datum!
    10. If My.Computer.FileSystem.FileExists(Pfad) Then
    11. Datei = File.ReadAllText(Pfad)
    12. Label2.Text = CStr("Ablaufdatum: " & Datei)
    13. If Datum_Erststart > CDate(Datei) Then
    14. MsgBox("Ihre Testphase ist abgelaufen")
    15. End
    16. Else
    17. End If
    18. Else
    19. Dim Msg, Number, StartDate As String
    20. Dim Days As Double
    21. Dim SecondDate As Date = Datum_Erststart
    22. Dim IntervalType As DateInterval
    23. IntervalType = DateInterval.DayOfYear 'Monat-Tag-usw- als Interval einstellbar !
    24. StartDate = CStr(Datum_Erststart) 'Zeit bei Start
    25. SecondDate = CDate(StartDate)
    26. Number = "20" 'Zeit in Tagen die hinzugerechnet wird (( DayOfYear ))
    27. Days = Val(Number)
    28. Msg = CStr(DateAdd(IntervalType, Days, SecondDate)) 'Neues erstelltes Datum (+20Tage)
    29. 'Datei erstellen und datum reinschreiben mit +20 Tage
    30. Dim txt As String = Msg
    31. Dim fss As StreamWriter = File.CreateText(Pfad) 'Später ins Gemüse wos keiner findet !
    32. fss.Write(txt)
    33. fss.Close()
    34. 'Ermitteln ob Datei vorhanden ist,wenn ja auslesen und vergleichen mit heutigem Datum!
    35. Datei = File.ReadAllText(Pfad)
    36. If Datum_Erststart > CDate(Datei) Then
    37. End
    38. End If
    39. End If
    40. 'Restzeit bis Ablauf !
    41. Dim Differenz_Zeit As Long = DateDiff("d", Datum_Erststart, Datei)
    42. Label3.Text = CStr("Restzeit: " & Differenz_Zeit)
    43. End Sub
    44. 'Label1 und Label2 sind nicht nötig !
    45. End Class



    Der Helfer:
    Spoiler anzeigen
    Hallo PersonXYZ (am besten immer den Namen nenne damit der Bezug erhalten bleibt). Hier erstmal die Dinge dir mir an deinem Code aufgefallen sind:

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.IO
    3. Public Class Form1
    4. Dim Datum_Erststart As Date = Date.Now.Date 'könnte auch in anderen Methoden verwendung finden - ansonsten: globale deklaration unnötig
    5. Dim Datei As String 'Die Variable wird NUR in der Prüf-Methode gebraucht. Globales deklarieren ist unangebracht
    6. Dim Pfad As String = "C:\Users\zeus\Desktop\Neuer Ordner (8)\Data_z.cfg" 'ganz schlecht, besser in den Settings oder relativ zur .exe speichern
    7. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    8. Label1.Text = CStr("Aktuelles Datum: " & Datum_Erststart) 'es gibt auch eine .toString-Methode^^
    9. If My.Computer.FileSystem.FileExists(Pfad) Then 'Die IO.FileInfo kann das auch - My-Namespace ist nicht so schön
    10. Datei = File.ReadAllText(Pfad) 'Variable komisch benannt. Caste doch am besten direkt zu Date, den Dateiinhalt braucht man eh nie wieder
    11. Label2.Text = CStr("Ablaufdatum: " & Datei) 'es gibt auch eine .toString-Methode^^
    12. If Datum_Erststart > CDate(Datei) Then 'das CDate würde wegfallen.. ACHTUNG: KURIOSITÄT xD
    13. MsgBox("Ihre Testphase ist abgelaufen")
    14. End
    15. Else
    16. End If
    17. Else
    18. Dim Msg, Number, StartDate As String 'warum deklarieren aber keinen Wert zuweisen? Bei lokalen Variablen finde ich das sehr unschön
    19. Dim Days As Double 'Days soll sicher ein Integer sein?
    20. Dim SecondDate As Date = Datum_Erststart 'warum wird hier eine Variable einfach nur verdoppelt? Benutze doch weiterhin Datum_Erststart
    21. 'Der Teil ist wirklich hässlich. Mit einer Timespan ließe sich das in zwei Zeilen machen - übersichtlich und nachvollziehbar
    22. Dim IntervalType As DateInterval
    23. IntervalType = DateInterval.DayOfYear
    24. StartDate = CStr(Datum_Erststart)
    25. SecondDate = CDate(StartDate)
    26. Number = "20"
    27. Days = Val(Number) 'Cint oder .TryParse ist besser - glaube Val ist eine dieser "bösen Funktionen" aus VB6-Zeiten
    28. Msg = CStr(DateAdd(IntervalType, Days, SecondDate))
    29. Dim txt As String = Msg 'schon wieder unnötigerweise eine Variable verdoppelt. Msg könnte statt txt weiterverwendet werden, du änderst ja nichts
    30. Dim fss As StreamWriter = File.CreateText(Pfad) '[Später ins Gemüse wos keiner findet !] <= Das ich nicht lache: Programmabsturz wahrscheinlich, ILSpy oder andere Tools und man hat den Pfad definitiv!
    31. fss.Write(txt)
    32. fss.Close()
    33. Datei = File.ReadAllText(Pfad) 'relativ trivial da du vor zwei zeilen ein dir bekanntes Datum in die Datei geschrieben hast
    34. If Datum_Erststart > CDate(Datei) Then 'CDate könnte auch hier wegfallen
    35. End
    36. End If
    37. End If
    38. 'Restzeit bis Ablauf !
    39. Dim Differenz_Zeit As Long = DateDiff("d", Datum_Erststart, Datei) 'DateDiff ist untypisiert - gefällt mir nicht. Timespan sollte auch klappen.
    40. Label3.Text = CStr("Restzeit: " & Differenz_Zeit) 'es gibt auch eine .toString-Methode^^
    41. End Sub
    42. End Class


    ACHTUNG: KURIOSITÄT Wenn in der cfg-Datei 'murks' steht wird das Programm am CDate scheitern und eine Exception werfen. Lustigerweise arbeitest du im Form_Load-Event und dieses hat ein spezielles Verhalten: es ignoriert die Exception einfach. Das bedeutet: Wenn die Datei existiert und einen ungültigen Inhalt hat wird dein Programm an dieser Stelle immer aus der Methode rausspringen und die Trial-Version somit niemals ablaufen.

    Ich würde so vorgehen:


    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Public Const PFAD_ABLAUFDATUM As String = "ablaufdatum.txt" 'die bessere Alternative: ein Eintrag in den Settings. Ist aber alles unsicher.
    4. Public Const DAUER_TRIAL_TAGE As Integer = 30 'Die Trial soll 30 Tage gültg sein
    5. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    6. 'Try
    7. trialCheck() 'prüft ob die Trial-Version abgelaufen ist und beendet das Programm ggf
    8. 'Catch ex As Exception
    9. ' 'ein Fehler könnte auf manipulation hinweisen.
    10. 'End Try
    11. End Sub
    12. Public Sub trialCheck()
    13. Dim istAbgelaufen As Boolean = False
    14. Dim fi As New IO.FileInfo(PFAD_ABLAUFDATUM)
    15. Dim ablaufDatum As Date = Now + TimeSpan.FromDays(DAUER_TRIAL_TAGE)
    16. If fi.Exists Then
    17. 'Die Datei existiert
    18. Using reader As New IO.StreamReader(fi.OpenRead)
    19. Dim tmp As String = reader.ReadToEnd
    20. ablaufDatum = Date.Parse(tmp) 'TryParse wäre besser. Ist die Datei fehlerhaft könnte man auf manipulation tippen und die Trial als abgelaufen ansehen
    21. istAbgelaufen = (ablaufDatum <= Now)
    22. reader.Close()
    23. End Using
    24. Else
    25. 'Die Datei existiert nicht
    26. Using writer As New IO.StreamWriter(fi.OpenWrite)
    27. 'ablaufDatum = Now + TimeSpan.FromDays(DAUER_TRIAL_TAGE)
    28. writer.Write(ablaufDatum)
    29. writer.Flush()
    30. writer.Close()
    31. End Using
    32. End If
    33. If istAbgelaufen Then
    34. MsgBox("die Trial-Version ist abgelaufen")
    35. Me.Close()
    36. Else
    37. Dim ts As TimeSpan = ablaufDatum - Now
    38. MsgBox("die Trial ist noch " & CInt(ts.TotalDays) & " Tage gültig")
    39. End If
    40. End Sub
    41. End Class


    Der Code ist auch nicht 100% korrekt. Beispielsweise können immer noch Lese/Schreib-Fehler auftreten (z.B. wenn das Programm keine entsprechenden Rechte hat) die du abfangen solltest. Eine Textdatei ist auch nicht soo geeignet - ein Eintrag in den Settings wäre besser. Sicher ist das allerdings alles nicht - selbst ein "verstecken der Datei im Gemüse" ist unsicher und sorgt für verärgerte Nutzer wenn du ihnen das Dateisystem verhunzt^^ Um der angesprochenen Kuriosität zu entgehen ist es besser du arbeitest im Shown-Event (da fällt eine Exception nicht unter den Tisch) und/oder baust Try-Catch'es gezielt ein. TryParse-Methoden sind dem natürlich vorzuziehen.

    lg

    Links:
    [VB.NET] TryCatch ist ein heißes Eisen



    Ich hoffe der Thread wird seinen Zweck erfüllen. lg FreakJNS
    Ich finde das ist eine gute Idee und wollte es schon länger mal nutzen.
    Das hier ist einer der ersten Codes, die ich geschrieben habe und der ist an vielen Stellen mit heißer Nadel gestrickt und manche Probleme sind im Nachhinein wohl eher nicht elegant gelöst. Ich würde den Code (auch wenn er ganz solide funktioniert) ganz gerne nochmal etwas überarbeiten.

    Der Hintergrund:
    Das soll ein Programm sein, mit dem man die Merkfähikeit testen kann. Es wird eine Anordnung aus 3x3 Feldern grafisch dargestellt, eins nach dem anderen, danach soll der User sich erinnern und kann Panels anklicken und sie schwarz oder weiss machen um die Erinnerung anzugeben. Unten ist ein Bild. Zur Darstellung benutze ich Panels und ich nutze die BackColor Eigenschaft um die Farben Schwarz oder Weiss zu machen. Die Anordnugenen sollen vom User übrigens mental rotiert werden. Die Richtung wird durch einen zuvor eingeblendeten Pfeil vorgegeben. Also nochmal der Ablauf:
    1. Ein Pfeil zeigt die Richtung (links oder rechts)
    2. Mehrere 3x3 Felder werden nacheinander dargeboten
    3. Ein Response Screen erscheint wo man die Erinnerungen eingeben kann (mental rotiert)
    4. Der User bekommt ein Feedback um sein Erinnerungen mit den tatsächlichen Reizen abzugleichen
    5. Die Antworten werden gespeichert



    Ich bin nich so glücklich damit, dass ich Strings benutze um die Aufgaben zu speichern. Ich habe hier mal nur die wichtigsten Stellen aus dem Code herauskopiert. Ich hoffe der ist auch so nicht zu lang. Bin gespannt auf eure Kommentare.

    code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class SWM2
    2. Private Panelset(9) As Panel
    3. Private Responseset(36) As Panel
    4. Public WMAufgabenset(17) As String
    5. Private Rotateinfo() As Integer = {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1}
    6. Private current_task As Integer = 0
    7. Private Uebung As Boolean
    8. Private Jetzt As Date
    9. Private Const responsetime As Integer = 60000
    10. Private SWMstartzeit As String
    11. Private Points As Integer = 0
    12. 'On LoAD
    13. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    14. Panelset = New Panel() {PanelA01, PanelA02, PanelA03, PanelA04, PanelA05, PanelA06, PanelA07, PanelA08, PanelA09}
    15. WMAufgabenset(0) = "111000000"
    16. WMAufgabenset(1) = "001011001"
    17. WMAufgabenset(2) = "000011000 100100100"
    18. WMAufgabenset(3) = "011000000 001001001"
    19. WMAufgabenset(4) = "110100000"
    20. WMAufgabenset(5) = "000001110"
    21. WMAufgabenset(6) = "000101010"
    22. WMAufgabenset(7) = "111000000 001010000"
    23. WMAufgabenset(8) = "001001001 110100000"
    24. WMAufgabenset(9) = "010011010 000100110"
    25. WMAufgabenset(10) = "000001011 001001001"
    26. WMAufgabenset(11) = "000100110 000010111 100100100"
    27. WMAufgabenset(12) = "111000000 011001000 000000011"
    28. WMAufgabenset(13) = "001001001 100010000 100110100"
    29. WMAufgabenset(14) = "011000000 000001011 010100000"
    30. WMAufgabenset(15) = "001001001 011100000 000100100 110100000"
    31. WMAufgabenset(16) = "000001011 100100000 000000111 010001000"
    32. AntwortBox1.Hide()
    33. AntwortBox2.Hide()
    34. AntwortBox3.Hide()
    35. AntwortBox4.Hide()
    36. GroupBoxAufgabe.Hide()
    37. PictureBox1.Hide()
    38. lblAchtung.Hide()
    39. GroupBoxStart.Show()
    40. cmdStart.Visible = False
    41. End Sub
    42. 'Stellt die Aufgaben Grafisch dar, input ist ein String aus 1er und 0er mit Leerzeichen dazwischen. rotateinfo ist 1 oder 2 für links oder rechts.
    43. Sub Aufgabe_Auswerten(ByVal input As String, ByVal rotateinfo As Integer)
    44. Dim panelcount As Integer = 0
    45. If rotateinfo = 1 Then
    46. PictureBox1.Image = My.Resources.rotate_left_2
    47. ElseIf rotateinfo = 2 Then
    48. PictureBox1.Image = My.Resources.rotate_right_2
    49. End If
    50. GroupBoxAufgabe.Hide()
    51. PictureBox1.Show() 'erstmal rotierrichtung für 3 Sekunden anzeigen
    52. Application.DoEvents()
    53. Threading.Thread.Sleep(3000)
    54. PictureBox1.Hide()
    55. For i = 0 To 40 '40 = die maximale Länge des Input-Strings
    56. If i > input.Length - 1 Then 'Aufgabe anzeigen, wenn Input-String am Ende
    57. panelcount = 0
    58. lblAufgabe.Text = (i \ 9).ToString
    59. GroupBoxAufgabe.Show()
    60. Application.DoEvents()
    61. Threading.Thread.Sleep(4000)
    62. Exit For
    63. ElseIf input.Chars(i) = " " Then 'Aufgabe anzeigen, wenn Lücke im Input-String
    64. panelcount = 0
    65. lblAufgabe.Text = (i \ 9).ToString
    66. GroupBoxAufgabe.Show()
    67. Application.DoEvents()
    68. Threading.Thread.Sleep(4000)
    69. ElseIf input.Chars(i) = "1" Then 'Schwarz
    70. Panelset(panelcount).BackColor = Color.Black
    71. 'DirectCast(Panelset(panelcount), Panel).BackColor = Color.Black
    72. panelcount += 1
    73. ElseIf input.Chars(i) = "0" Then 'Weiss
    74. Panelset(panelcount).BackColor = Color.White
    75. 'DirectCast(Panelset(panelcount), Panel).BackColor = Color.White
    76. panelcount += 1
    77. End If
    78. Next
    79. End Sub
    80. 'Rotiert je nach Argument
    81. Function rotate(ByVal foo As String, ByVal direction As Integer) As String 'string maximal länge 9; direction 1 für links, 2 für rechts
    82. rotate = foo
    83. If direction = 1 Then 'rotate left
    84. rotate = foo.Chars(2) & foo.Chars(5) & foo.Chars(8) & foo.Chars(1) & foo.Chars(4) & foo.Chars(7) & foo.Chars(0) & foo.Chars(3) & foo.Chars(6)
    85. ElseIf direction = 2 Then 'rotate right
    86. rotate = foo.Chars(6) & foo.Chars(3) & foo.Chars(0) & foo.Chars(7) & foo.Chars(4) & foo.Chars(1) & foo.Chars(8) & foo.Chars(5) & foo.Chars(2)
    87. End If
    88. End Function
    89. 'Task Controlling Machine
    90. Sub Aufgabenmaschiene(Optional ByVal Again As Boolean = False)
    91. '1.) Achtung!
    92. Application.DoEvents()
    93. System.Threading.Thread.Sleep(250)
    94. lblAchtung.Show()
    95. Application.DoEvents()
    96. System.Threading.Thread.Sleep(500)
    97. lblAchtung.Hide()
    98. Application.DoEvents()
    99. System.Threading.Thread.Sleep(250)
    100. '2.) Aufgabe darstellen
    101. Aufgabe_Auswerten(WMAufgabenset(current_task), Rotateinfo(current_task)) 'Erstmal Aufgabe darstellen
    102. '3.) Antwortbox darstellen
    103. Select Case WMAufgabenset(current_task).Length Mod 9 'zeigt die Response-Matrizen je nach Länge der aktuellen Aufgabe
    104. Case 0
    105. Responseset = New Panel() {Panel111, Panel112, Panel113, Panel114, Panel115, Panel116, Panel117, Panel118, Panel119}
    106. For Each i In Responseset 'resettet die Farben der Responsepanels
    107. i.BackColor = Color.White
    108. Next
    109. AntwortBox1.Show()
    110. Case 1
    111. Responseset = New Panel() {Panel211, Panel212, Panel213, Panel214, Panel215, Panel216, Panel217, Panel218, Panel219, Panel221, Panel222, Panel223, Panel224, Panel225, Panel226, Panel227, Panel228, Panel229}
    112. For Each i In Responseset 'resettet die Farben der Responsepanels
    113. i.BackColor = Color.White
    114. Next
    115. AntwortBox2.Show()
    116. Case 2
    117. Responseset = New Panel() {Panel311, Panel312, Panel313, Panel314, Panel315, Panel316, Panel317, Panel318, Panel319, Panel321, Panel322, Panel323, Panel324, Panel325, Panel326, Panel327, Panel328, Panel329, Panel331, Panel332, Panel333, Panel334, Panel335, Panel336, Panel337, Panel338, Panel339}
    118. For Each i In Responseset 'resettet die Farben der Responsepanels
    119. i.BackColor = Color.White
    120. Next
    121. AntwortBox3.Show()
    122. Case 3
    123. Responseset = New Panel() {Panel411, Panel412, Panel413, Panel414, Panel415, Panel416, Panel417, Panel418, Panel419, Panel421, Panel422, Panel423, Panel424, Panel425, Panel426, Panel427, Panel428, Panel429, Panel431, Panel432, Panel433, Panel434, Panel435, Panel436, Panel437, Panel438, Panel439, Panel441, Panel442, Panel443, Panel444, Panel445, Panel446, Panel447, Panel448, Panel449}
    124. For Each i In Responseset 'resettet die Farben der Responsepanels
    125. i.BackColor = Color.White
    126. Next
    127. AntwortBox4.Show()
    128. End Select
    129. 'TIMER restriction
    130. Jetzt = DateTime.Now
    131. ProgressBar1.Value = 0
    132. ProgressBar2.Value = 0
    133. ProgressBar3.Value = 0
    134. ProgressBar4.Value = 0
    135. If current_task > 3 Then
    136. TimerRestriction.Start()
    137. End If
    138. cmdOK1.Show()
    139. GroupBoxAufgabe.Hide()
    140. End Sub


    Edit: auf Wunsch habe ich das Projekt angehängt
    Dateien
    • SWMpt.zip

      (221,78 kB, 532 mal heruntergeladen, zuletzt: )

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

    (mein gott, bin ich schlecht in dem Spiel!)
    jdfs. die codierung der Aufgaben als String findich garnicht schlecht. Irgendeine codierung muss man finden, und Strings sind wunnebar anschaulich beim Debuggen.

    Mehr Beschwerden habich mit wieviele Panels du brauchst, und dass du mit Thread.Sleep und Application.DoEvents() unterwegs bist.

    Imo müssteman das ganz anners organieieren, nämlich als Workflow - so heißt das glaubich, und gibts sogar ein Extra-Framework für - aber habich keine Ahnung von.

    Jedenfalls müssten die Aufgaben aus einer Datei eingelesen werden, und dann wird ein AblaufPlan erstellt, der bestimmt, was grad angezeigt wird. Der AblaufPlan kann per Timer voranschreiten, aber an bestimmten Punkten im Workflow auch per Ok-Button.
    Irgendwie so ungefähr.
    Ich habe neulich dieses Snippet für ein kleines Experiment gefunden und versucht damit ein Bild, das so etwa Desktopgröße besitzt, damit umzuwandeln so das es dunkler wird, jedoch musste ich feststellen, dass die Geschwindigkeit mit der das ganze abläuft mit 5 Sekunden untragbar für meine Zwecke ist. Welche anderen Methoden wären hier zu wählen für eine bessere Performance?

    VB.NET-Quellcode

    1. Function dimmcolor(ByVal parameter As Integer, ByVal down As Integer)
    2. If parameter - down < 0 Then
    3. parameter = 0
    4. ElseIf parameter - down > 255 Then
    5. parameter = 255
    6. Else
    7. parameter = parameter - down
    8. End If
    9. Return parameter
    10. End Function
    11. Function dimm(ByVal img As Bitmap, ByVal variable As Integer)
    12. Dim imgn As New Bitmap(img.Width, img.Height)
    13. Try
    14. For x As Integer = 0 To img.Width - 1
    15. For y As Integer = 0 To img.Height - 1
    16. imgn.SetPixel(x, y, Color.FromArgb(dimmcolor(img.GetPixel(x, y).R, variable), dimmcolor(img.GetPixel(x, y).G, variable), dimmcolor(img.GetPixel(x, y).B, variable)))
    17. Next
    18. Next
    19. Catch ex As Exception
    20. Me.Text = ex.ToString
    21. End Try
    22. Return imgn
    23. End Function

    8-) faxe1008 8-)
    Die Bitmap-Methoden Get/SetPixel sind sehr langsam. Hier rufst du GetPixel noch pro Pixel mehrmals auf... xD
    Schau mal hier rein: [VB 2010] Tutorial: LockBits
    Vor allem der Code von blaze würde dein Problem sehr einfach lösen, du brauchst nur eine Filter-Methode schreiben und schon läuft das Ganze^^

    Hinweis: Auch Methodenaufrufe kosten Zeit. Wenn du es noch schneller haben möchtest, dann musst du das selbst implementieren, sodass nur wenige Methodenaufrufe entstehen (also alles mehr oder weniger in einer größeren Methode passiert). Verwendest du den Code von blaze wird für jeden Pixel (mindestens) eine Methode aufgerufen.
    lg
    Ohne jz wieder herummeckern zu wollen, weise ich dich dennoch darauf hin, dass du Option Strict On aktivieren solltest :/
    @faxe1008
    Das am Anfang mit dem Parameter-Zeugs lässt sich auch sehr gut mit Math.Max und Math.Min umsetzen. Außerdem könntest du eigentlich auch das Try/Catch entfernen.
    @Gather: Das war wie gesagt das Snippet, wie ich es gefunden habe. Ich habe standardmäsig Strict auf on und verwurschtele keinerlei Trys rein.

    @FreakJNS: Danke wetde mich heute in einer freien Stunde reinarbeiten :thumbup:

    8-) faxe1008 8-)
    So, jetzt möchte ich auch mal einen Code posten, der eigentlich super funktioniert, ich aber nicht weiss, ob er sauber geschrieben ist.

    Das Programm fügt einem XML-File ein Attribute an einem bestimmten Node hinzu, oder löscht es wieder. Je nachdem, welcher Radiobutton auf der Form gewählt wurde.
    Vor dem Hinzufügen oder löschen des Attributes, wird noch ein Backup des XML-Files erstellt.

    Hier nun der Code.

    VB.NET-Quellcode

    1. '### Expand or Collapse all Lineups
    2. '### Es werden alle Lineups entweder geöffnet, oder geschlossen
    3. Imports System.Xml
    4. Imports System.IO.File
    5. Imports System.IO
    6. Imports System.Windows.Forms
    7. Public Class frmExpandCollapseLineups
    8. Dim xmlAttrib As XmlAttribute
    9. Dim RemoveAttrib As XmlAttribute
    10. Dim openfilename As String
    11. Dim a3sXml As New Xml.XmlDocument
    12. Dim startpath As String = "Mein Pfad"
    13. Dim fd As New System.Windows.Forms.OpenFileDialog
    14. Dim listofstreams As Xml.XmlNodeList = a3sXml.SelectNodes("//alternative_set")
    15. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    16. With fd
    17. .Title = "Choose A3S File"
    18. .Filter = "A3S Files (*.a3s)|*.a3s"
    19. .InitialDirectory = startpath
    20. .FileName = "A3S-Files"
    21. End With
    22. If Not fd.ShowDialog = DialogResult.OK Then
    23. Else
    24. openfilename = fd.FileName.ToString
    25. Backup()
    26. If RadioButton2.Checked Then
    27. Expand()
    28. ElseIf RadioButton1.Checked Then
    29. Collapse()
    30. End If
    31. End If
    32. End Sub
    33. Sub Collapse()
    34. a3sXml.Load(openfilename)
    35. For Each node As XmlNode In listofstreams
    36. xmlAttrib = a3sXml.CreateAttribute("open")
    37. xmlAttrib.Value = "1"
    38. node.Attributes.RemoveNamedItem("open")
    39. Next
    40. a3sXml.Save(openfilename)
    41. Application.Exit()
    42. End Sub
    43. Sub Expand()
    44. a3sXml.Load(openfilename)
    45. For Each node As XmlNode In listofstreams
    46. xmlAttrib = a3sXml.CreateAttribute("open")
    47. xmlAttrib.Value = "1"
    48. node.Attributes.Append(xmlAttrib)
    49. Next
    50. a3sXml.Save(openfilename)
    51. Application.Exit()
    52. End Sub
    53. Sub Backup()
    54. Dim FileExt As String = Path.GetExtension(openfilename)
    55. Dim SaveFileName = Path.GetFileNameWithoutExtension(openfilename) & FileExt
    56. Dim diBackup = New DirectoryInfo(Path.Combine(Path.GetDirectoryName(openfilename), "Backup"))
    57. diBackup.Create()
    58. Dim dateien = New DirectoryInfo(diBackup.ToString)
    59. Dim newfilename As String = Path.Combine(diBackup.FullName, SaveFileName)
    60. If File.Exists(newfilename) Then
    61. If File.Exists(newfilename) Then
    62. Dim fileName = Path.GetFileNameWithoutExtension(newfilename)
    63. Dim fileNumber = 0
    64. Do
    65. fileNumber += 1
    66. newfilename = Path.Combine(diBackup.FullName, String.Format("{0} ({1}){2}", fileName, fileNumber, FileExt))
    67. Loop While File.Exists(newfilename)
    68. File.Copy(openfilename, newfilename)
    69. End If
    70. Else
    71. File.Copy(openfilename, newfilename)
    72. End If
    73. End Sub
    74. End Class
    jo, hübsche aufgabe - ich find jdfs. 2 Themen daran interessant: Einmal die Xml-Verarbeitung - da kannman sich dolle dran verkünsteln. Etwa dass du da 2 mal zu 90% identischen Code hast - das kann man redundanzfreier hinkriegen.
    Und dann natürlich rumprobieren, was mit XDocument und Konsorten zu reißen ist - aber dazu müsstest du eine Beispiel-Anwendung anhängen, inklusive Datenbeispiel, weil so aus der Luft kann man höchstens bischen die Zeilen reorganisieren, aber nix neu entwickeln aus einem anneren Ansatz heraus.

    Das annere ist die Backupperei - ich hab heute glaub 3h an 15 Zeilen Code gesessen, die nun aber auch jede String-Sammlung durchchecken, und an neuen Strings dann Nümmerken dranhängen, damit der neue keine Namens-Kollision bewirkt.
    Ist offensichtlich ein gelegentlich wiederkehrendes kniffliges Problem :thumbup:

    TomWi schrieb:


    VB.NET-Quellcode

    1. Dim a3sXml As New Xml.XmlDocument
    2. Dim listofstreams As Xml.XmlNodeList = a3sXml.SelectNodes("//alternative_set")


    Hm, ich stehe gerade auf dem Schlauch wohl. Solange das Dokument nicht geöffnet wurde, ist die Liste doch "Nothing" oder? Danach wird sie nicht mehr aktualisiert.
    Warum funktioniert der Code trotzdem?
    Hallo Sonne75, auf deine Frage kann ich dir leider keine Antwort geben. Ich hoffe ein anderer User hier, kann da weiterhelfen.

    Anbei ist jetzt die Testanwendung mit Beispieldatei


    Edit by ErfinderDesRades: Executable entfernt - nichts für ungut - sowas ist nur im ShowRoom zulässig

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

    sonne75 schrieb:

    Warum funktioniert der Code trotzdem?

    Weil die Variable listofstreams sonst nirgendwo mehr im gezeigten Code auftaucht, womit es dann egal ist, ob sie Nothing ist oder nicht.

    Mir sind an dem Code einige Designsachen aufgefallen, die mir eigentlich egal wären, aber da hier explizit danach gefragt wird:

    Fast sämtliche Instanzvariablen - also Variablen auf Klassen- statt auf Funktionsebene - kann man wegwerfen und stattdessen besser lokale Variablen dafür verwenden.
    startpath kann bleiben, würde ich aber als Konstante deklarieren, und openfilename wird tatsächlich Funktionsübergreifend gebraucht, wäre hier aber vermutlich besser als Funktionsparameter zu übergeben.

    In der Zeile Dim SaveFileName = Path.GetFileNameWithoutExtension(openfilename) & FileExt würde ich eher auf IO.Path.ChangeExtension() gehen, aber das ist Makulatur.

    If File.Exists(newfilename) Then taucht exakt so zwei Mal hintereinander auf, was in der Form redundant ist. Das zweite If wird hier auf jeden Fall immer zu True aufgelöst, wenn es ausgeführt wird, kann also ersatzlos gestrichen werden.

    Und solange hier

    VB.NET-Quellcode

    1. If Not fd.ShowDialog = DialogResult.OK Then
    2. Else
    nichts zwischen steht, würde ich dann doch lieber eine Zeile If fd.ShowDialog = DialogResult.OK Then draus machen.

    Ansonsten gibt es aber meiner Meinung nach nichts zu beanstanden. Sehr penible Menschen würden vermutlich noch bemängeln, dass du dich bei den Bezeichnern nicht an die Microsoft-Designguides gehalten hast... ;)
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.

    Arby schrieb:

    Weil die Variable listofstreams sonst nirgendwo mehr im gezeigten Code auftaucht, womit es dann egal ist, ob sie Nothing ist oder nicht.

    Natürlich taucht sie auf:

    TomWi schrieb:

    VB.NET-Quellcode

    1. Sub Collapse()
    2. a3sXml.Load(openfilename)
    3. For Each node As XmlNode In listofstreams

    TomWi schrieb:

    VB.NET-Quellcode

    1. Sub Expand()
    2. a3sXml.Load(openfilename)
    3. For Each node As XmlNode In listofstreams


    Sonst hätte ich das nicht geschrieben.