Scroll Bar Handling

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Scroll Bar Handling

    Hi,

    ich habe eine ScrollBar HSegmentScrollBar.

    Mit diesem Schieberegler befülle ich eine TextBox txtCurrentSegment

    In der Ereignisprozedur txtCurrentSegment_TextChanged soll dann das ausgewählte Segment verarbeitet werden.

    Da die Verarbeitung sehr aufwendig ist, darf das erst ausgelöst werden, wenn die ScrollBar nicht mehr angeklickt ist. Deshalb gibt es ein Flag blnDisaTextChanged mit dem man die Routine temporär ausschalten kann. So habe ich das versucht:

    VB.NET-Quellcode

    1. Private Sub HSegmentScrollBar_KeyPress(sender As Object, e As KeyPressEventArgs) Handles HSegmentScrollBar.KeyPress
    2. blnDisaTextChanged = True 'does not fire
    3. End Sub
    4. Private Sub HSegmentScrollBar_KeyUp(sender As Object, e As KeyEventArgs) Handles HSegmentScrollBar.KeyUp
    5. blnDisaTextChanged = False 'does not fire
    6. End Sub
    7. Private Sub HSegmentScrollBar_MouseDown(sender As Object, e As MouseEventArgs) Handles HSegmentScrollBar.MouseDown
    8. blnDisaTextChanged = True 'does not fire
    9. End Sub
    10. Private Sub HSegmentScrollBar_MouseUp(sender As Object, e As MouseEventArgs) Handles HSegmentScrollBar.MouseUp
    11. blnDisaTextChanged = False 'does not fire
    12. End Sub
    13. Private Sub HSegmentScrollBar_ValueChanged(sender As Object, e As EventArgs) Handles HSegmentScrollBar.ValueChanged
    14. txtCurrentSegment.Text = HSegmentScrollBar.Value.ToString("n0") & " " 'Accept new value, append an additional space
    15. End Sub
    16. Private Sub HSegmentScrollBar_MouseEnter(sender As Object, e As EventArgs) Handles HSegmentScrollBar.MouseEnter
    17. blnDisaTextChanged = True 'Disable routine
    18. End Sub
    19. Private Sub HSegmentScrollBar_MouseLeave(sender As Object, e As EventArgs) Handles HSegmentScrollBar.MouseLeave
    20. blnDisaTextChanged = False 'Reenable routine
    21. txtCurrentSegment.Text = txtCurrentSegment.Text.Trim() 'Remove addition space to trigger TextChanged event
    22. End Sub
    23. Dim blnDisaTextChanged As Boolean = True
    24. Private Sub txtCurrentSegment_TextChanged(sender As Object, e As EventArgs) Handles txtCurrentSegment.TextChanged
    25. If blnDisaTextChanged Then Exit Sub
    26. MessageBox.Show(txtCurrentSegment.Text)
    27. End Sub


    Die Ereignisroutinen KeyPress, KeyUp, MouseDown, MouseUp werden nicht ausgelöst ! Die sind also für die Katz ! Warum auch immer !

    Allein die Routinen

    VB.NET-Quellcode

    1. MouseEnter, MouseLeave
    feuern wie erwartet.

    Damit wird der aktuelle Wert der ScrollBar korrekt im Feld txtCurrentSegement abgebildet.

    Aber die Aktion (in diesem Fall testhalber nur Messagebox.Show(...) ) wird erst ausgelöst, wenn der MouseCursor das Control verlässt. Das ist ein bissl "gewöhnungsgedürftig" und nicht gerade user friendly !

    Außerdem muss ich einen "müden Trick" verwenden, um die Aktion txtCurrentSegement_TextChanged auszulösen. Ich hänge an die Textbox immer ein Blank an und das entferne ich dann mit .Trim um das Changed Event zu erhalten.

    Das sieht mir nicht gerade nach einer optimalen Handhabung aus. Deshalb meine Fragen:

    Wie erreiche ich, dass meine Routine bereits beim MouseUp aktiviert wird ?

    Ist mein Trick mit dem angehängten Blank Stand der Technik oder geht das eleganter ?

    Mein Problem wird wohl nicht ganz so neu sein. Ich bin mir sicher dass jemand weiß, wie man solche Aufgaben besser löst ! :)

    LG
    Peter
    Bilder
    • s 2018-09-30 13-34-132.jpg

      3,24 kB, 322×71, 90 mal angesehen

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

    Peter329 schrieb:

    Die Ereignisroutinen KeyPress, KeyUp, MouseDown, MouseUp werden nicht ausgelöst ! Die sind also für die Katz ! Warum auch immer !


    Hier findest du hier altervativen, schau dir mal die ScrollEventType's an. Mal fleissig überall auf der Scrollbar klicksen und Thumb verschieben etc...
    Wenn bei Tastendruck kein SmallDecrement oder SmallIncrement kommt, setze TabStop der ScrollBar auf True. So kann sie den Focus bekommen.

    VB.NET-Quellcode

    1. Private Sub HSegmentScrollBar_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles HSegmentScrollBar.Scroll
    2. Debug.WriteLine(e.Type.ToString())
    3. End Sub


    Peter329 schrieb:

    Außerdem muss ich einen "müden Trick" verwenden, um die Aktion txtCurrentSegement_TextChanged auszulösen.


    Musst du nicht ;) Du kannst die Sub auch selbst callen.

    VB.NET-Quellcode

    1. txtCurrentSegement_TextChanged(Nothing, Nothing)
    2. 'oder
    3. txtCurrentSegment_TextChanged(Me, New EventArgs())

    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „NoIde“ ()

    Uff ... jetzt habe ich herausgefunden wie das Control tickt !

    Wenn das Interval des Schiebereglers etwa den Bereich 0 - 9 umfasst, dann kann man mit dem Schieberegler keine Werte einstellen. Der Schieberegeler ist maximal ausgedehnt und kann NICHT bewegt werden. Insbesondere kann man so den Value des Regelers nicht verändern. Aber wenn man den Regler anklickt, dann feuern die Routinen MouseDown und MouseUp !

    Quellcode

    1. HSegmentScrollBar_MouseEnter
    2. HSegmentScrollBar_MouseDown
    3. txtCurrentSegment_TextChanged
    4. HSegmentScrollBar_MouseUp
    5. txtCurrentSegment_TextChanged
    6. HSegmentScrollBar_MouseLeave


    Wenn der Bereich des Schiebereglers mindestens 0 - 10 (oder mehr umfasst), dann wird der Schieberregler beweglich und man kann damit den Value des Reglers verändern. Aber jetzt feuern die Routinen MouseDown und MouseUp NICHT mehr !

    Quellcode

    1. HSegmentScrollBar_MouseEnter
    2. HSegmentScrollBar_MouseLeave
    3. HSegmentScrollBar_MouseEnter
    4. HSegmentScrollBar_ValueChanged
    5. txtCurrentSegment_TextChanged
    6. HSegmentScrollBar_MouseLeave
    7. txtCurrentSegment_TextChanged


    grrrrrrrrrrrrrrrrrrrrrrrrr !

    Vielleicht gibt es einen Grund für dieses merkwürdige Verhalten. Für mich ist das Control damit nicht brauchbar ... es sei denn jemand kann mir das (nachsichtig) erklären und mir sagen, wie man damit umgeht !

    LG
    Peter

    Peter329 schrieb:

    Wenn der Bereich des Schiebereglers mindestens 0 - 10 (oder mehr umfasst), dann wird der Schieberregler beweglich und man kann damit den Value des Reglers verändern. Aber jetzt feuern die Routinen MouseDown und MouseUp NICHT mehr !


    Ich denke was du brauchst kannste hier finden. EndScroll kommt z.B. bei Mouse up und KeyUp(keyup bei Pfeiltasten)

    VB.NET-Quellcode

    1. Private Sub HSegmentScrollBar_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles HSegmentScrollBar.Scroll
    2. Debug.WriteLine(e.Type.ToString())
    3. End Sub


    Mach dir doch einfach eine eigene Scrollbar welche von Control erbt. Da hast du die volle Kontrolle.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

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

    warum sollernu ein eigenes Control basteln, sowas ist doch üblicherweise immer sonstwie aufwändig, unflexibel anfällig, und leistet nicht, was das Original längst kann.
    Du hast ihm doch das richtige Event genannt - damit kanner sein Problem doch höchstwahrscheinlich sauber lösen - muss halt ScrollEventArgs.Type auswerten.

    @Peter329: Allenfalls wäre zu überlegen, ob eine Trackbar nicht das Control der Wahl ist - mittm SchieberVerhalten einer Scrollbar scheinste ja so nicht brauchen zu können.
    War vllt. ein wenig übertrieben. Aber wenn er es so nicht hinbekommt, hätte er genau die Events die er haben möchte um das auf seine Art zu lösen. Ein grosser Aufwand ist eine Scrollbar nicht, habe mal eine vertikale gemacht. Gerade mal geschaut wie viele Zeilen es waren, inkl. leerzeilen nur 225. Ist vllt. nicht so umfangreich wie die des FWs aber sieht besser aus. Auch wenn nur das nötigste drin ist, verrichtet sie treue Dienste.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Also erst einmal ganz herzlichen Dank, dass ihr euch so eingehend mit meinem Problem befasst habt.

    Ich habe mir eure Anregungen angeschaut und versucht, das bestmöglich umzusetzen.

    Eine eigene Control schreiben wollte ich nicht. Denn - wie vereinzelt angemerkt - schafft man damit möglicherweise mehr Probleme als man vorher hatte ... :)

    Ich verwende jetzt doch die ScrollBar ... und zwar als "prozentuale Auswahl", also im Bereich von 0 bis 100. Da gibt es zwar auch einige Hakeligkeiten (denn die 100 Prozent erreicht man nicht so ohne weiteres, man muss 110 Prozent zulassen und dann abschneiden :) ) ... aber auf diese Weise ist das Verhalten der Scroll Bar von der Größe der Datei unabhängig ...

    Ansonsten muss man die Auswahl der Scroll Bar bestätigen, es sei denn, man wählt das nächste oder vorhergehende Segement aus. Das ist ein etwas ungewöhnliches Verhalten ... aber es ist für meinen Geschmack recht "User friendly". Die Scroll Bar dient zur groben Justierung ... "Left" und "Right" Buttons dienen zur Feinjustierung ... wenn man die Tasten gedrückt hält, werden sie "wiederholt" (Repeat Function). Damit kann man auch in großen Dateien sehr bequem navigieren.

    Da ich jetzt nur noch ein Segment (35 Zeilen) in die Datagrid View lade, geht das Ganze ratz fatz.

    Ich kann jetzt einen bis zu 2GB großen File mit Ladezeiten unter einer Sekunde editieren ! Für Files mit mehr als 2 GB streikt die ReadAllBytes Methode ... aber das ist ja auch nicht unbedingt das, was ich jeden Tag tun will. :)

    Anbei ein Display von meiner HexEdit Anwendung ...

    Herzlichen Dank für eure Ratschläge ... ihr habt mir wieder einmal sehr geholfen, indem ihr mich auf die "richtige" Spur gesetzt habt.

    LG
    Peter
    Bilder
    • s 2018-10-01 14-23-520.jpg

      223,06 kB, 931×925, 63 mal angesehen

    Peter329 schrieb:

    Für Files mit mehr als 2 GB streikt die ReadAllBytes Methode


    Arbeite mit Streams, dann ist auch das machbar.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Peter329 schrieb:

    Ich verwende jetzt doch die ScrollBar ... und zwar als "prozentuale Auswahl", also im Bereich von 0 bis 100. Da gibt es zwar auch einige Hakeligkeiten
    Mir scheint, du verstehst das Scrollbar-Konzept noch nicht richtig, daher erscheint dir einiges als "Hakeligkeit", was in Wirklichkeit überaus sinnvoll ist.

    Also eine Scrollbar ist ein visuelles Modell eines Fensters, was einen Ausschnitt aus einem grossen Datenbestand anzeigt, Ausschnitt deshalb, weil der Datenbestand halt zu gross ist, um komplett im Fenster angezeigt zu werden.
    Nun kannste das Fenster rauf und runter-schieben, und so eben doch alle Daten angugge, obwohls eiglich fürs Fenster viel zu viele sind.
    zum visuellen Modell:
    Die Scrollbar als Ganze symbolisiert den Datenbestand, und der Thumb (das Ding, woran man zieht) symbolisiert das Fenster. Deshalb ist der Thumb auch verschieden gross, also wenn das Fenster die Hälfte der Daten anzeigen kann, dann nimmt der Thumb die hälfte der Scrollbar ein. Ist die Relation kleiner, wird der Thumb auch entsprechend kleiner (bis hin zu einer fixen Minimal-Grösse).

    Betrachten wir einen Datenbestand mit 100 Zeilen, und ein Fenster, was 10 Zeilen anzeigen kann.
    Dann muss man Scrollbar Maximum auf 100 setzen, und Scrollbar.LargeScroll (das FensterGröen-Äquivalent) auf 10.
    Und Scrollbar.Value bedeutet immer die erste Zeile im angezeigten Fenster. Also logisch wird Scrollbar.Value nicht das Maximum erreichen, weil ja bereits bei .Value=90 das Ende der Daten im Fenster sichtbar ist, und darüberhinaus will man ja nicht scrollen.

    Scrollbar und ein Daten-Fenster synchronisiert man also so:
    Gesamt-Datenlänge -> .Maximum
    Fenster-Grösse -> .LargeScroll
    1.Zeile im Fenster <-> .Value

    Oder anners: Wann immer Datenmenge oder Fenster-Grösse sich ändern musste die Scrollbar anpassen.
    Und die Topline des Fensters ist bidirektional mitte .Value-Eigenschaft zu synchronisieren.

    Übrigens Textbox/Richtextbox haben ja eingebaute Scrollbars, die dir das ganze Theater komplett abnehmen - wieso scheidet das in diesem Falle aus?
    @Peter329 Gefunden. :thumbsup:
    Wieso verwendest Du eine H-Bar?
    Dein Buld erinnert mich sehr an den Hex-View von meinem Salamander (ein Norton-Commander-Clon):

    Da hast Du eine intuitive V-Bar von Anfang bis Ende.
    Wenn Du die Größe Deines Fensters so einrichtest, dass nur vollständige Zeilen dargestellt werden und dass immer n * 16 Byte pro Zeile dargestellt werden, ist Deine Arithmetik und Verriegelung nicht erforderlich.
    Ich habe das Gefühl, dass Du all den Schnick-Schnack aufgenommen hast, weil Du beim Proggen an eine Grenze gestoßen bist.
    Fang mit einer klaren Aufgabenstellung an, sieh Die einen anderen Viewer / Editor an und überleg, was Du von dem brauchen könntest und lass "bremsende Elemente" erst gar nicht zu.
    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!

    ErfinderDesRades schrieb:

    Zitat von Peter329: „Ich verwende jetzt doch die ScrollBar ... und zwar als 'prozentuale Auswahl', also im Bereich von 0 bis 100. Da gibt es zwar auch einige Hakeligkeiten“

    Mir scheint, du verstehst das Scrollbar-Konzept noch nicht richtig, daher…


    Doch, doch ... ich hab das jetzt schon verstanden denke ich. Und mir ist auch klar, dass ich die ScrollBar in diesem Fall ein bissl "vergewaltige" ... Für meine Zwecke der Positionierung innerhalb einer Datei ist das Dingens nicht geschaffen, aber der Zweck heiligt die Mittel ... Wie du weißt, bin ich sehr pragmatisch veranlagt. Und kein bissl dogmatisch. Solange die Bedienung "user friendly" und "intuitiv" ist und das Ganze sauber läuft. :)

    RodFromGermany schrieb:

    Dein Buld erinnert mich sehr an den Hex-View von meinem Salamander (ein Norton-Commander-Clon):


    Ich bin ein "Hostie" ... und da habe ich schon im Jahr 1980 einen HexEditor im MVS Umfeld mit diesem "Look and Feel" verwendet. Das hab ich jetzt im .Net nachgebaut ... und eigentlich bin ich damit sehr zufrieden.

    NoIde schrieb:

    Peter329 schrieb:

    Für Files mit mehr als 2 GB streikt die ReadAllBytes Methode


    Arbeite mit Streams, dann ist auch das machbar.


    Dem würde ich jetzt gern noch nachgehen. NIcht dass ich wirklich vorhabe ein Windows ISO-Image mit 3 GB hexadezimal zu bearbeiten. Einfach um der reinen Lehre willen. :)

    D.h. ich müsste einen Byte StreamReader definieren und dann alle Bytes in einen Array einlesen ? Na, mal sehen ob ich das (performant) hinbekomme ... oder gibt's ein Code Beispiel ... :)

    LG
    Peter

    Peter329 schrieb:

    und dann alle Bytes in einen Array einlesen ?
    Ich dachte, Du hältst alle Deine Bytes in einem Array, das Du mit .ReadAllBytes(DATEI) einliest.
    Dass Dein Editor nur sinnvoll große Dateien behandelt, setze ich voraus.
    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:

    Peter329 schrieb:

    und dann alle Bytes in einen Array einlesen ?
    Ich dachte, Du hältst alle Deine Bytes in einem Array, das Du mit .ReadAllBytes(DATEI) einliest.


    Genau so mache ich das ... Aber diese Methode liest nur Files bis 2 GB Größe ein !

    Und deshalb die Idee von @Nolde einen Stream Reader zu verwenden um auch größere Files einlesen zu können. :)
    Bilder
    • s 2018-10-01 17-26-194.jpg

      9,44 kB, 494×160, 62 mal angesehen
    @Peter329 Was willst Du denn in solch großen Dateien editieren?
    Ist das sinnvoll?
    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:

    @Peter329 Was willst Du denn in solch großen Dateien editieren?
    Ist das sinnvoll?


    Peter329 schrieb:

    NIcht dass ich wirklich vorhabe ein Windows ISO-Image mit 3 GB hexadezimal zu bearbeiten. Einfach um der reinen Lehre willen.


    Wenn ich das mit dem Stream Reader nicht ohne großen Aufwand hinbekomme, dann frage ich die FileSize vorher ab ... und beende die Aktion, wenn das Dingens zu groß ist !

    LG
    Peter
    @Peter329 Du kannst natürlich Deine Bytes auch auf mehrere Blöcke (á 1 GB z.B.) aufteilen und bist damit ggf. etwas flexibler.
    Nur die Suche über eine Grenze hinweg ist etwas tricky.
    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!
    Nö, genau das mache ich nicht ! Ich lese die Daten komplett in den Speicher. So machen das übrigens auch die Editoren im MVS. Und offensichtlich funktioniert auch Notepad und Konsorten auf diese Weise.

    Suchen und Ersetzen sind zentrale Funktionen von diesem Editor. Sonst ist das Dinges nämlich unbrauchbar. Und das kann man m.E. nur sinnvoll und performant abwickeln, indem man ALLE Daten im Speicher hält. So mache ich das zur Zeit.

    Die angezeigten Daten ermöglichen ein direktes Editieren. Ich bilde eben die am Bildschirm geänderten Daten auf den Byte Array ab ... wie schon gesagt: führend ist der Array und nicht die DataGridView ...

    LG
    Peter
    @Peter329 OK.
    Allerdings hast Du in jedem Fall eine Grenze, die des Betriebssystems.
    Probier die mal aus, wenn Du das Programm als 32- bzw. als 64-Bit-Variante erstellst. 8o
    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!

    Peter329 schrieb:

    Und deshalb die Idee von @Nolde einen Stream Reader zu verwenden um auch größere Files einlesen zu können.
    Das ist eine schöne Idee, aber dann muss man Daten-Virtualisierung fürs DGV implementieren, und dassis ziemlich tricky.
    Am besten du suchst im INet nach einer Beispiel-Source dazu, etwa auf CodeProject.