Swing JScrollPane und Scroll-Geschwindigkeit

  • Themenstarter Themenstarter Camino
  • Beginndatum Beginndatum
C

Camino

Gast
Hallo,

ich hab eine etwas umfangreichere Swing-Anwendung erstellt, bei der im Hauptframe ein MainPanel in den CENTER-Bereich hinzugefügt wird. Dieses MainPanel wiederum ist ein JTabbedPane und kann mehrere Tabs (JPanel) hinzufügen, welche wieder um CardLayout haben und zwischen mehreren (ziemlich umfangreichen) Formularen hin- und herschalten können. Das funktioniert auch soweit. Diese Formulare werden in eine JScrollPane gelegt und diese JScrollPane dann dem CardLayout hinzugefügt. Nun ist mir aufgefallen, dass die Scrollgeschwindigkeit (wenn der Frame kleiner wie das Formular ist) ziemlich langsam ist. Warum ist das so? Zuerst dachte ich, das liegt evtl. an den umfangreichen Formularen (JPanel mit GridBagLayout und ziemlich vielen Komponenten). Dann hab ich mir aber zum Testen nochmal eine kleinere Anwendung erstellt, mit einem leeren JPanel in einem CardLayout. Dieses JPanel habe ich mit setPreferredSize grösser als den Frame gemacht, damit die Scrollbalken auftauchen. Und auch da bewegt sich mein Panel sehr langsam, wenn ich mit dem Mausrad rauf oder runter scrolle. Hab ich beim hinzufügen des Panels zum Scrollpane was falsch gemacht? Oder kann jemand sonst einen Fehler entdecken und mir weiterhelfen?

Hier kommt mal das Testprogramm (die zwei weiteren Panel im CardLayout sind nur zu Testzwecken angelegt und können nicht angezeigt werden, da es mir erst mal nur um die Scrollgeschwindigkeit geht):
Java:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;


public class Test
extends JFrame {


	public Test() {

		setTitle("Test");

		setSize(600, 400);
		
		// Frame auf dem Bildschirm zentrieren
		setLocationRelativeTo(getParent());

		add( BorderLayout.CENTER, new TestPanel() );

		setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		
		setVisible( true );

	}


	public static void main(String[] args) {
		new Test();
	}

	
	
	class TestPanel
	extends JPanel {

		CardLayout card;
		    
		public TestPanel() {
		    	
			card = new CardLayout();
		 
			this.setLayout(card);
		    	
			JPanel panel1 = new JPanel();
			JScrollPane scroll1 = new JScrollPane(panel1);
			panel1.setPreferredSize(new Dimension(800, 600));
		    	
			JPanel panel2 = new JPanel();
			JPanel panel3 = new JPanel();
		    	
			panel1.setBackground(Color.YELLOW);
			panel2.setBackground(Color.RED);
			panel3.setBackground(Color.BLUE);
		    	
			add(scroll1, "1");
			add(panel2, "2");
			add(panel3, "3");

		}
		 
		public void showPanel(String panel) {
			card.show(this, panel); 
		}
		
	}
	
}

Ergänzung: Eigentlich ist das mit dem CardLayout sogar egal. Wenn ich es einfach dem CENTER-Bereich des Frames hinzufüge, hab ich das gleiche. Das Panel lässt sich mit dem Mausrad nur sehr langsam scrollen. Also vermutlich hab ich da einen Fehler beim Zuweisen des Panels ins ScrollPane?
Java:
...
		TestPanel testPanel = new TestPanel();
		testPanel.setPreferredSize(new Dimension(800, 600));
		JScrollPane scroll1 = new JScrollPane(testPanel);

		add( BorderLayout.CENTER, scroll1 );
...
 
Zuletzt bearbeitet von einem Moderator:
Java:
JScrollPane.getVerticalScrollBar().setUnitIncrement(15);

Setzt die Scrollgeschwindigkeit der ScrollBar 😉
 
Java:
JScrollPane.getVerticalScrollBar().setUnitIncrement(15);

Setzt die Scrollgeschwindigkeit der ScrollBar 😉

Hey cool, das funktioniert tatsächlich. Ich frag mich aber trotzdem, warum das standardmäßig so langsam scrollt. Ich bin mir auch nicht sicher, aber ich dachte, ich hätte schonmal Scrollpanes in einem Programm gehabt, die auch von alleine "normal schnell" gescrollt haben. Trotzdem danke für deine Hilfe und den Tipp.

Camino
 
Je nachdem, um was es da genau geht, kann man auch die GUI-Componente, die gescrollt werden soll, "Scrollable" implementieren lassen.

Mit einem JPanel nicht so sinnvoll, nur als schnell hingehacktes Beispiel
Java:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.*;

import javax.swing.*;
import javax.swing.JPanel;
import javax.swing.JScrollPane;


public class ScrollTest
extends JFrame {


    public ScrollTest() {

        setTitle("Test");

        setSize(600, 400);

        // Frame auf dem Bildschirm zentrieren
        setLocationRelativeTo(getParent());

        add( BorderLayout.CENTER, new TestPanel() );

        setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

        setVisible( true );

    }


    public static void main(String[] args) {
        new ScrollTest();
    }



    class TestPanel
    extends JPanel {

        CardLayout card;

        public TestPanel() {

            card = new CardLayout();

            this.setLayout(card);

            JPanel panel1 = new ScrollablePanel();
            JScrollPane scroll1 = new JScrollPane(panel1);
            panel1.setPreferredSize(new Dimension(800, 600));

            JPanel panel2 = new JPanel();
            JPanel panel3 = new JPanel();

            panel1.setBackground(Color.YELLOW);
            panel2.setBackground(Color.RED);
            panel3.setBackground(Color.BLUE);

            add(scroll1, "1");
            add(panel2, "2");
            add(panel3, "3");

        }

        public void showPanel(String panel) {
            card.show(this, panel);
        }

    }

}


class ScrollablePanel extends JPanel implements Scrollable
{
    public Dimension getPreferredScrollableViewportSize()
    {
        return getPreferredSize();
    }

    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
    {
        return 21;
    }
    public boolean getScrollableTracksViewportHeight()
    {
        return false;
    }
    public boolean getScrollableTracksViewportWidth()
    {
        return false;
    }
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
    {
        return 21;
    }
}
 
Es handelt sich eigentlich tatsächlich nur um ein JPanel, welches gescrollt werden soll, weshalb wohl die erst Lösungsmöglichkeit (die Scrollgeschwindigkeit beim JScrollPane zu setzen) einfacher ist. Ich hatte mich schon gewundert und gedacht, das JPanel mit den Formularkomponenten wäre evtl. zu voll und ist deshalb so schwer/langsam zu scrollen, oder ich hab das irgendwie falsch zugewiesen. Na ja, ich werde dann diese Scrollgeschwindigkeit in meiner Anwendung global setzen und den Scrollpanes zuweisen.

Vielen Dank für eure Hilfe...

Camino
 
Sorry, musste das Thema nochmal aufmachen, aber mir ist gerade noch etwas beim Scrollen aufgefallen. Und zwar setzt das Scrollen des JPanels aus, wenn ich mich mit der Maus über einer JTable befinde. Soweit ich das nachvollziehen kann, ist dann der "Scrollfokus" auf der JTable, auch wenn diese garnicht so viele Elemente drinstehen hat, dass deren Scrollbalken angezeigt werden. Ist ein bisschen unschön, weil dann das Scrollen der Seite (des Panels) blockiert wird und der User evtl. nicht genau erkennen kann, warum. Gibt es denn eine Möglichkeit, dass so zu machen, wie ich es auch in Webbrowsern funktioniert, nämlich dass wenn sich die Maus auf der Tabelle befindet und dort gescrollt werden kann, dass dann innerhalb der Tabelle gescrollt wird, bis in der Tabelle oben oder unten der Rand erreicht wird, und dann wird die Seite (Panel) weitergescrollt.
 
2 Dinge die mir so einfielen: 1) Die Scrollbalken nur "AS_NEEDED" anzeigen, vllt klappts dann oder aber für den Fall, dass die nicht benötigt werden setMouseWheelScrollingEnabled(false); aufzurufen.. Aber habs jetzt nicht getestet...
Sonst muss wohl jemand anders ran, der wirklich die Zusammenhänge mit den ganzen Events und co im Detail kennt^^
 
MouseWheel und Scrolling sind ein bißchen kompliziert. Schon das beschriebene Verhalten beim Browser ist (bei mir) so, dass man den Inneren Bereich bis zum Ende scrollt, aber dann NUR den äußeren Bereich scrollen kann, wenn man die Maus zwischendurch bewegt hat. Aber auf anderen Betriebssystemen und anderen Browsern bzw. anderen Programmen kann das schon wieder ganz anders sein. Speziell für Java hatte ich mir das kürzlich mal genauer angesehen: Er schickt den Event an die Component, die sich unter der Maus befindet, und wenn die sie nicht verarbeitet, wird eine Kopie des Events nach oben gereicht, und geschaut, ob irgendeine andere Component diesen Event verarbeiten will - ziemlich crank.
(Sorry, keine konkrete Antwort auf die Frage, aber ... wollte nur andeuten dass das vom OS abhängen und ggf. kompliziert sein könnte... aber vielleicht weiß ja jemand zufällig die Antwort...)
 
OK, danke für eure Infos und Tipps. Ich werde mir das nochmal genauer anschauen, und falls es keine wirklich brauchbare Lösung gibt, muss ich halt mit diesem Effekt leben.
 

Neue Themen


Zurück
Oben