Scrollbarwerte berechnen



  • Hallo,

    ich verusuche ein einges Control zu erstellen. Auf dem Control wird ein Kalender angezeigt. Das Control soll horizontale und vertikale Scrollbalken haben. Um mein Problem darzustellen, habe ich ein kleineres Beispiel gemacht. Es zeigt eine beliebige Anzahl an Spalten an.
    Vorneweg: die Verwendug von einem ScrollableControl nützt mir nichts, weil ich auf der linken Seite eine fixe Spalte habe,
    die jetzt in dem Beispiel weggelassen wurde.

    Mein Problem ist das ich nicht weiß wie man die Werte für SmallChange und LargeChange richtig berechnet.
    Wenn der Bereich der nicht angezeigt wird (also der Bereich außerhalb des Fensters/Form) kleiner ist als mein SmallChange, kann ich nicht nach rechts scrollen und somit nicht alles anzeigen.
    Am Besten sieht man es wenn man das Fenster ganz groß macht, so das alle 10 Spalten zu sehen sind.
    Macht man dann das Fenster einwenig kleiner, erscheint zwar die Scrollbar, aber der SmallChange ist zu groß um nach rechts scrollen zu können.
    Ich hab auch versucht den SmallChange kleiner zu machen, aber nichts hat wirklich funktioniert und die gleiche Funktionalität gezeigt wie ein normales Windows-Fenster.

    Weiß jemand wie man die SmallChange und LargeChange-Werte korrekt berechnet?

    Hier das Control, das einfach auf einer Form (mit Dock=Fill) plaziert werden muss:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Diagnostics;
    using System.Windows.Forms;
    
    namespace scrolltest2
    {
        public partial class CustomControl1 : Control
        {
    
            public int breite = 100;
            public int anzahlSpalten = 10;
    
            public CustomControl1()
            {
                InitializeComponent();
                this.Controls.Add(hScrollBar1);
                SetzteHorizontalBarWerte();
                this.MinimumSize = new Size(breite, 300);
            }
    
            protected override void OnPaintBackground(PaintEventArgs pevent)
            {
                //base.OnPaintBackground(pevent);
            }
    
            protected override void OnPaint(PaintEventArgs pe)
            {
                Debug.WriteLine("Zeiche neu...");
                pe.Graphics.Clear(Color.Beige);
                Rectangle ursprung = this.ClientRectangle;
    
                pe.Graphics.SetClip(ursprung);
                for (int i = 0; i < anzahlSpalten; i++)
                {
                    Rectangle pos = ursprung;
                    int horWert = hScrollBar1.Value;
                    pos.X = ursprung.X + (breite * i) - horWert;
                    pos.Width = breite;
                    pos.Height = 250;
                    pe.Graphics.DrawRectangle(Pens.Black, pos);
                    string ausgabe = Convert.ToString(i + 1);
                    pe.Graphics.DrawString(ausgabe, new Font("Arial", 15), Brushes.Black, new Point(pos.X, pos.Y));
                }
    
                base.OnPaint(pe);
            }
    
            public string output()
            {
                string txt = "";
                txt += "Min         : " + this.hScrollBar1.Minimum + Environment.NewLine;
                txt += "Max         : " + this.hScrollBar1.Maximum + Environment.NewLine;
                txt += "SmallChange : " + this.hScrollBar1.SmallChange + Environment.NewLine;
                txt += "LargeChange : " + this.hScrollBar1.LargeChange + Environment.NewLine;
                txt += "Position    : " + this.hScrollBar1.Value + Environment.NewLine;
                return txt;
            }
    
            public void SetzteHorizontalBarWerte()
            {
                int breite_NichtAngezeigterBereich = (anzahlSpalten * breite) - this.Width;
    
                //Wird die Scrollbar benötigt?
                if (breite_NichtAngezeigterBereich > 0)
                {
                    hScrollBar1.Visible = true;
                    hScrollBar1.Value = 0;
                    hScrollBar1.Minimum = 0;
                    hScrollBar1.SmallChange = breite;
                    hScrollBar1.LargeChange = breite * 2;
                    hScrollBar1.Maximum = breite_NichtAngezeigterBereich;
                    //Da: Maximal erreichbarer Wert von Value : Maximum - LargeChange + 1
                    hScrollBar1.Maximum += hScrollBar1.LargeChange;
                }
                else
                {
                    hScrollBar1.Visible = false;
                    hScrollBar1.Value = 0;
                }
                Debug.WriteLine(this.output());
            }
    
            protected override void OnSizeChanged(EventArgs e)
            {
                base.OnSizeChanged(e);
                SetzteHorizontalBarWerte();
                Invalidate();
            }
    
            private void hScrollBar1_ValueChanged(object sender, EventArgs e)
            {
                Invalidate();
            }
        }
    }
    

    Designer:

    namespace scrolltest2
    {
        partial class CustomControl1
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Component Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify 
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.hScrollBar1 = new System.Windows.Forms.HScrollBar();
                this.SuspendLayout();
                // 
                // hScrollBar1
                // 
                this.hScrollBar1.Dock = System.Windows.Forms.DockStyle.Bottom;
                this.hScrollBar1.Location = new System.Drawing.Point(0, 0);
                this.hScrollBar1.Name = "hScrollBar1";
                this.hScrollBar1.Size = new System.Drawing.Size(80, 16);
                this.hScrollBar1.TabIndex = 0;
                this.hScrollBar1.ValueChanged += new System.EventHandler(this.hScrollBar1_ValueChanged);
                this.ResumeLayout(false);
    
            }
    
            #endregion
    
            private System.Windows.Forms.HScrollBar hScrollBar1;
        }
    }
    

    MfG Barracuda



  • Moin!

    Die folgenden Ausführungen erheben keinen Anspruch auf Vollständigkeit, sie kratzen nur an der Oberfläche.

    Zu Deinem Problem: Wenn Du selber zeichnest hast Du einen sichtbaren Bereich.
    Sagen wir mal 600 Pixel breit und 400 Pixel hoch. Der kann sich natürlich ändern, wenn der User, die Maske vergrößtert oder verkleinert. Wenn er kleinere oder größere Schriftarten als die Windows Standard Schriftgröße gewählt hat usw.
    Also Dein (public int breite = 100; public int anzahlSpalten = 10;) geht nicht!
    Das ist also der variable sichtbare Bereich, den Du bei deinem Programmstart erstmalig auslesen und berechnen muß und zwar auf den Pixel genau und natürlich bei jeder Aktion des Users neu berechnen muß. Ich nehme mal an, dass Dein Promm verschieden Schriftarten oder Bitmaps als Hintergründe anbietet.

    Dann hast Du etwas, was Du in dem sichtbaren Bereich darstellen möchtest - deine Daten. Der darzustellende Bereich kann größer oder kleiner oder gleich dem sichtbaren Bereich sein. Wenn Du also einen Kalender zeichnen willst, mußt Du wissen, wenn ich eine Zeile zeichne, habe ich z. B. 30 Pixel in der Höhe und 250 Pixel in Breite in Abhängig vom sichbaren Bereich verbraucht.

    Also der aktuell sichbare Bereich ist 600 x 400
    Zeilenhöhe einer Zeile deines Kalenders ist 30
    Zeilenbreite einer Zeile deines Kalenders ist 250

    Nehmen wir mal an: Du brauchst 30 Zeilen um einen Jahreskalender vollständig zu zeichnen. Dir fehlen also 300 Pixel für die vollständige Darstellung bei dem aktuell sichtbaren Bereich von 600 x 400. Es muß also ein Scrollbar her. Und jetzt muß du wieder neu rechnen zwischen dem sichtbaren Breich und dem was der User noch sehen kann. Er sieht also z. B. nur die ersten 9 Monate. Will er also die nichtzusehenden Monate sehen (300Pixel) muß er scrollen. Ein Click auf die Scrollbar bedeutet, das Du 30 x 250 neu zeichnen mußt und 30 x 250 des sichtbren Bereichs verwerfen muß. Das einzige was fix ist Dein Kalender pro Zeile und Spalte (30x250) der sichtbare und darzustellende Bereich ist immer nur im aktuellen Kontext der Anwendung fix. Alles andere kann sich durch die Aktionen des Users und Deine Kalenderfunktionen (Bitmaps unterschiedliche Schriftarten etc) jeder Zeit ändern.

    HTH und Grüsse - Kalle


Anmelden zum Antworten