Swing JScrollPane ans ende Scrollen

Anton2k

Aktives Mitglied
Hallo, nachdem ich bei meinem Problem:Altes Problem
nicht so wirklich weiter gekommen bin hab ich noch mal nachgedacht und hab mir jetzt die HTML Fähigkeiten des JPanels zu nutze gemacht um den Text umzubrechen.

Gut ich füge die komponente ein und setzte den Scrollbar auf Maximum. Aber dieses Maximum ist leider nur das Maximum was er vor dem hinzufügen hatte. Erstelle ich einen zweiten knopf der ihn unabhängig vom ersten auf Maximum setzt klappt es.
Also fehlt ihm irgend etwas wenn ich direkt nach dem hinzufügen den Scrollbar auf Max setzen möchte.
Vieleicht kennt ja jemand die Antwort wie man das Problem lösen könnte.

Hier mal das ganze als kleiner Testcode:

Java:
package test;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Start implements ActionListener{
	JFrame frame= new JFrame("Test");
	JButton button =new JButton("Neu");
	JPanel textPanel=new JPanel();
	JScrollPane scrollPane=new JScrollPane(textPanel);
	
	public Start(){
		 
		 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 frame.setSize(800,600);
		 frame.setLayout(new FlowLayout(FlowLayout.CENTER));	
		 	 
		 button.addActionListener(this);
		 textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.PAGE_AXIS));		 		 
		 scrollPane.setPreferredSize(new Dimension(100,100));

		 
		 frame.add(scrollPane);
		 frame.add(button);
		 frame.pack();
		 frame.setVisible(true);
	}

	public void actionPerformed(ActionEvent arg0) {
		JLabel tempLabel=new JLabel("Hallo Welt");
		tempLabel.setBackground(Color.BLUE);
		tempLabel.setForeground(Color.WHITE);
		tempLabel.setOpaque(true);
		textPanel.add(tempLabel);
		textPanel.revalidate();
		
		scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum());
		
	}
	
	public static void main(String[] args) {

		new Start();

	}	

}
 
Zuletzt bearbeitet von einem Moderator:
Du kannst die Position des ScrollPanes erst setzen, wenn dieses angezeigt wird. Das macht man am besten so: [java=23]scrollPane.addHierarchyListener(new HierarchyListener() {

public void hierarchyChanged(HierarchyEvent e) {
final JScrollPane scrollPane = (JScrollPane) e.getSource();
if (scrollPane.isShowing()) {
scrollPane.removeHierarchyListener(this);
final JViewport viewport = scrollPane.getViewport();
final JComponent view = (JComponent) viewport.getView();
final int h = view.getHeight();
view.scrollRectToVisible(new Rectangle(0, h, 1, h));
}
}
});
[/code]
Ebenius
 
Puh hab jetzt etwas damit rumprobiert und nachgelesen aber so ganz kapiere ich es nicht.
Das hierarchyChange event wird ausgelöst wenn sich bei einem untergeordneten element etwas ändert?
Ich hab mal ein System.out reingepackt um zu sehen wann es ausgelöst wird. Wenn ich es ganz am anfang registriere bekomme ich 3x meine textzeile.
Vermute mal, 2x durch seine eigenen scrollbars, 1x durch mein Panel was ich hinzufüge. Füge ich aber dem Pannel weiter hinzu wird das event nicht ausgelöst.
Damit das ganze nicht als endlosschleife läuft nimmt sich die Methode vermutlich selbst hiermit wieder raus "scrollPane.removeHierarchyListener(this);" Also müsste sie bei jedem klick auf meinen button neu registriert werden. Aber egal wie ich es drehe klappt es nicht.
Durchschaue es einfach nicht.
 
Zuletzt bearbeitet:
Es geht darum, dass Du mitbekommen möchtest, wenn [c]isShowing()[/c] von [c]false[/c] auf [c]true[/c] wechselt. Das kannst Du mit nem HierarchyListener machen. Hier mal ein KSKB:
Java:
/* (@)ScrollPaneTestGui.java */

/* Copyright 2010 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;

import javax.swing.*;

public class ScrollPaneTestGui {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

      public void run() {
        createAndShowGui();
      }
    });
  }

  private static void createAndShowGui() {
    final JScrollPane scrollPane = new JScrollPane(new JTable(100, 4));
    scrollPane.addHierarchyListener(new HierarchyListener() {

      public void hierarchyChanged(HierarchyEvent e) {
        if (((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0)
              && e.getComponent().isShowing()) {
          final JScrollPane scrollPane = (JScrollPane) e.getSource();
          scrollPane.removeHierarchyListener(this);
          final JViewport viewport = scrollPane.getViewport();
          final JComponent view = (JComponent) viewport.getView();
          final int h = view.getHeight();
          view.scrollRectToVisible(new Rectangle(0, h, 1, h));
        }
      }
    });

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(scrollPane);

    final JFrame f = new JFrame("Test Frame: ScrollPaneTestGui"); //$NON-NLS-1$
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
}
Die Prüfung in Zeile 42 [java=42] if (((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0)
&& e.getComponent().isShowing()) {[/code]
... kann man auch kürzen (wie oben): [java=42] if (e.getComponent().isShowing()) {[/code]
Ebenius
 
Zuletzt bearbeitet:
Ok es klappt vielen Dank. Auch wenn ich mich noch etwas mit den Hintergründen beschäftigen muss wie es genau abläuft.
 
Zuletzt bearbeitet:
Ok gestern Nacht hatte ich es nicht mehr gemerkt. Es funktioniert nur wenn ich die ScrollPane.setVisible(false) und direkt .setVisible(true) aufrufe. Sowohl das false als auch das auf true setzten löst das event je 1x aus. Gut gefiltert wird nur es ja nur auf das Sichtbar machen. Ist das richtig das ich schnell die sichtbarkeit wechseln muss oder nicht? Der Benutzer wird davon letztendlich nichts merken.
 
Das ist nicht richtig. Es geht ja um die Eigenschaft [c]showing[/c] und nicht [c]visible[/c]. Mach mir doch bitte mal ein KSKB bei dem das Problem auftaucht. Funktioniert mein KSKB denn bei Dir?

Ebenius
 
Hallo,

Hier mal der Komplette Code meiner Testanwendung

Java:
package test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;

import javax.swing.*;

public class Start implements ActionListener{
	JFrame frame= new JFrame("Test");
	JButton button =new JButton("Neu");
	JPanel textPanel=new JPanel();
	JScrollPane scrollPane=new JScrollPane(textPanel);
	
	public Start(){
		 
		 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 frame.setSize(800,600);
		 frame.setLayout(new FlowLayout(FlowLayout.CENTER));	
		 	 
		 button.addActionListener(this);
		 textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.PAGE_AXIS));		 		 
		 scrollPane.setPreferredSize(new Dimension(100,100));
		 
			frame.add(scrollPane);
			frame.add(button);
			
		 frame.pack();
		 frame.setVisible(true);
	}

	public void actionPerformed(ActionEvent arg0) {
		
		scrollPane.addHierarchyListener(new HierarchyListener() {
			 
		  public void hierarchyChanged(HierarchyEvent e) {
		  	System.out.println("Hierarchy Event");
		  	final JScrollPane scrollPane = (JScrollPane) e.getSource();
		    if (scrollPane.isShowing()) {
		    	System.out.println("scr");
		      scrollPane.removeHierarchyListener(this);
		      final JViewport viewport = scrollPane.getViewport();
		      final JComponent view = (JComponent) viewport.getView();
		      final int h = view.getHeight();
		      view.scrollRectToVisible(new Rectangle(0, h, 1, h));
		    }
		  }
		});
		
		JLabel tempLabel=new JLabel("Hallo Welt");
		tempLabel.setBackground(Color.BLUE);
		tempLabel.setForeground(Color.WHITE);
		tempLabel.setOpaque(true);
		
		textPanel.add(tempLabel);
		textPanel.revalidate();

		//Ohne die nächsten 2 Zeilen wird nicht ans Ende gescrollt
		scrollPane.setVisible(false);
		scrollPane.setVisible(true);

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

		new Start();

	}	

}

Und hier zwei Versionen einmal mit und einmal ohne die 2 SetVisible Zeilen
http://sroot.marburgerfilmgroup.de/temp/ScrollPaneNichtOK.jar
http://sroot.marburgerfilmgroup.de/temp/ScrollPaneOK.jar

Hoffe der Fehler lässt sich finden.
 
Zuletzt bearbeitet von einem Moderator:
Bitte benutze die
Java:
-Tags, nicht die [code]-Tags für die Formatierung von Java-Code (oben geändert).

Oh mann, ich hab Dich einfach völlig falsch verstanden, obwohl Du's richtig erklärt hast. Ich dachte, Du willst direkt nach Programmstart nach ganz unten scrollen. Warum auch immer ich das dachte... :bloed: Deswegen auch der Listener...

Aber Du willst ja nur in der [c]actionPerformed[/c]-Methode nach Einfügen des neuen JLabels nach unten scrollen. Der Grund warum die View nur zu zum vorherigen Stand scrollt ist der, dass die Revalidierung Deines Kontainers erst verzögert statt findet. Also musst Du das scrollen ebenfalls hinten anstellen. Zum Beispiel so: [java=37]
    public void actionPerformed(ActionEvent arg0) {
        JLabel tempLabel=new JLabel("Hallo Welt");
        tempLabel.setBackground(Color.BLUE);
        tempLabel.setForeground(Color.WHITE);
        tempLabel.setOpaque(true);
        
        textPanel.add(tempLabel);
        textPanel.revalidate();

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                final JViewport viewport = scrollPane.getViewport();
                final JComponent view = (JComponent) viewport.getView();
                final int h = view.getHeight();
                view.scrollRectToVisible(new Rectangle(0, h, 1, h));
            }
        });
    }
Entschuldige die ganze Verwirrung.

Ebenius
 
Ja viele dank. Damit macht das ganze auch in meinen Augen wieder sinn. Wobei es mit Unsichtbar, sichtbar machen wie gesagt jetzt zwischenzeitlich ja auch funktioniert hat. Hab mich grade auch noch mal etwas in den sinn von invokeLater eingelesen und das Prinzip verstanden warum man es macht.
 

Zurück
Oben