Panel mit Autoscroll



  • Hallo,
    ich habe eine Frage zu diesem kurzen Beispiel. In einem Panel mit Autoscroll liegt eine Picturebox. Wenn ich den Button anklicke, wird ein Bild geladen das größer als das Panel ist, und die Scrollbalken werden automatisch zentriert. Beim ersten Klick funktioniert das. Aber beim zweiten Klick werden die Scrollbalken irgendwo anders hingeschoben. Ich würde gerne verstehen warum das so ist, und wie man das verhindern kann.
    Gruß
    Michael

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                panel1.AutoScroll = true;
                pictureBox1.Location = new Point(0, 0);
                pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
                pictureBox1.Load("test.png");
    
                Point p = new Point();
                p.X = (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                p.Y = (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;
                panel1.AutoScrollPosition = p;
            }
        }
    }
    


  • Tja, das ist gemein - laß dir mal panel1.Location sowie panel1.AutoScrollPosition beim 2. Aufruf ausgeben (bzw. im Debugger anzeigen). Evtl. spiele mal vor dem 2. Click ein bißchen mit den Scrollbars. Na, kommst du auf die Lösung?

    Es sollte dir auch der Hinweis in ScrollableControl.AutoScrollPosition helfen...



  • Panel1.Location ist bei beiden Aufrufen (0,0). Dass die AutoscrollPosition beim Abfragen negativ wäre das weiss ich, aber in diesem Beispiel mache ich ja gar keine Abfrage. Die Koordinaten von Point p sind bei beiden Aufrufen identisch, und trotzdem stehen die Scrollbalken hinterher an unterschiedlichen Stellen.



  • Sorry, meinte natürlich pictureBox1.Location.



  • pictureBox1.Location ist ebenfalls bei beiden Aufrufen (0,0)



  • Das sollte aber nur so sein, wenn beide Scrollbars ganz links bzw. oben sind.
    Ansonsten sollten die Positionen der enthaltenen Child-Elemente immer relativ zur aktuellen ScrollBar-Position sein (also negativ, wenn sie links bzw. oben herausragen).

    Aber um es kurz zu machen, du mußt bei nachfolgenden Veränderungen von AutoScrollPosition immer die aktuelle Position miteinberechnen (quasi auf Null zurücksetzen):

    Point pos = panel.AutoScrollPosition;
    Point p = new Point(x, y);
    panel.AutoScrollPosition = new Point(-pos.X + p.X, -pos.Y + p.Y);
    


  • Die aktuelle Position mit einzurechnen hat leider auch nicht funktioniert. Aber ich habe jetzt einen Workaround gefunden: Ich schalte einfach bei jedem Aufruf den Autoscroll aus und wieder ein:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                panel1.AutoScroll = false;
                panel1.AutoScroll = true;         
                pictureBox1.SizeMode = PictureBoxSizeMode.Normal;            
                pictureBox1.Size = new Size(1280,1024);
                pictureBox1.Load("test.png");
               
                Point p = new Point();
                p.X = (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                p.Y = (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;
                panel1.AutoScrollPosition = p;                  }
        }
    }
    


  • Jetzt geht es auch unter Berücksichtigung der aktuellen Position. Man beachte das "+=" bei der Berechnung der Koordinaten.
    Vielen Dank für deine Hilfe!
    Michael

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                panel1.AutoScroll = true;         
                pictureBox1.SizeMode = PictureBoxSizeMode.Normal;            
                pictureBox1.Size = new Size(1280,1024);
                pictureBox1.Load("test.png");
               
                Point p = new Point();
                p.X += (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                p.Y += (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;
                panel1.AutoScrollPosition = p;                  }
        }
    }
    


  • Das += hat doch gar keinen Effekt, denn der Point()-Konstruktor initialisiert X und Y mit 0 (und 0 + x ist immer x).

    PS: Unveränderliche Zuweisungen solltest du möglichst nur einmalig im Konstruktor vornehmen (also die ersten 3 Zeilen im button1_Click).



  • @Th69 Du hat Recht, das Beispiel funktioniert nicht. Also irgendie muss man die Ist-Position berücksichtigen. Aber wie das genau gehen soll, das habe ich immer noch nicht rausgefunden.



  • So funktioniert es immer, ausgenommen beim ersten Aufruf:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                pictureBox1.SizeMode = PictureBoxSizeMode.Normal;
                pictureBox1.Size = new Size(1280, 1024);
                pictureBox1.Load("test.png");
                panel1.AutoScroll = true;   
            }
    
            private void button1_Click(object sender, EventArgs e)
            {            
                Point p = panel1.AutoScrollPosition;
                int x = (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                int y = (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;
                panel1.AutoScrollPosition = new Point(x, y);
            }
        }
    }
    


  • Und so stehen die Scrollbalken bei allen Aufrufen falsch, ausgenommen beim zweiten Aufruf:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                pictureBox1.SizeMode = PictureBoxSizeMode.Normal;
                pictureBox1.Size = new Size(1280, 1024);
                pictureBox1.Load("test.png");
                panel1.AutoScroll = true;  
            }
    
            private void button1_Click(object sender, EventArgs e)
            {            
                Point p = panel1.AutoScrollPosition;
                int x = (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                int y = (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;
                panel1.AutoScrollPosition = new Point(-p.X + x, -p.Y + y);
            }
        }
    }
    


  • Jetzt geht es. Die Ist-Position muss nicht berücksichtigt werden. Wichtig ist dass die Zeile pictureBox1.Location = new Point(0, 0); nicht in button1_Click() drinsteht.

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                pictureBox1.Location = new Point(0, 0);
                panel1.AutoScroll = true;
                pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
            }
    
            private void button1_Click(object sender, EventArgs e)
            {            
                pictureBox1.Load("test.png");
                Point p = new Point();
                p.X = (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                p.Y = (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;
                panel1.AutoScrollPosition = p;
            }
        }
    }
    


  • Ich muss doch nochmal fragen, weil da immer noch der Wurm drin ist. Das Zentrieren der Scrollbalken habe ich jetzt in die Funktion center() ausgelagert. Wenn ich diese Funktion von button1_Click() aus aufrufe, dann tut sie jedesmal was sie soll, egal wie oft ich da draufklicke. Aber wenn ich sie vom Konstruktor von Form1() aus aufrufe, dann werden die Scrollbalken nicht zentriert, obwohl center() durchlaufen wird. Wie kann das sein? Hinter InitializeComponent() sollte doch eigentlich alles initialisiert sein.

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace test2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                pictureBox1.Location = new Point(0, 0);
                panel1.AutoScroll = true;
                pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
                pictureBox1.Size = new Size(1280, 1024);
                panel1.AutoScrollMinSize = new Size(1280, 1024);
    
                center();     // Dieser Aufruf zentriert die Scrollbalken nicht!
                center();     // Dieser auch nicht!
            }
    
            public void center()
            {
                pictureBox1.Load("test.png");            
                Point p = new Point();
                p.X = (pictureBox1.Size.Width - panel1.ClientRectangle.Width) / 2;
                p.Y = (pictureBox1.Size.Height - panel1.ClientRectangle.Height) / 2;         
                panel1.AutoScrollPosition = p;          
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                center();    // Dieser Aufruf zentriert die Scrollbalken
            }
        }
    }
    


  • Vor center() bitte Show() aufrufen.



  • Danke, jetzt ist das Problem gelöst!

    Michael


Log in to reply