# Text in JTextPane vertikal (!) zentrieren



## TobyNick (29. Jan 2011)

Hallo Leute,
ich verzweifel bald -.- Ich habe schon so viel dazu gesucht und schon scheinbar Lösungen, die dann doch nicht so wollten, wie ich. Und falls es hier doch noch schon ein Thema dazu geben sollte, dann bitte ich das zu entschuldigen. 
Also hier mein Problem (ich erklärs mal ausführlich):

Ich habe ein Fenster (JFrame), das ich in 3 Teile gleichgroße Teile vertikal aufteilen will. Das geht ja ganz gut mit dem GridLayout (new GridLayout(3, 1)). In das unterste Teil, sollen ein paar Buttons (das ist nicht das Problem). In den zwei oberen Teilen, soll - unabhängig voneinander - Text dargestellt werden. Also sollen die beiden Teile gleich funktionieren, und somit haben sie das gleiche problem, deswegen erklär ich es jetzt nur für einen teil. ;-)
Und zwar soll der Text so dargestellt werden, dass er in der Mitte steht (horizontal und vertikal zentriert). Das horizontale kriege ich hin: Ich lasse den Text in einem JTextPane darstellen und setze StyleConstants.setAlignment auf StyleConstants.ALIGN_CENTER.
Die vertikale Zentrierung soll jetzt so geschehen: Zuerst müsst ihr wissen, dass der Text immer unterschiedlich sein kann. Mal über mehrere Zeilen, mal nur eine Zeile. Also, wenn es nur eine Zeile ist, dann soll es einfach in der Mitte stehen. Wenn der Text über mehrere Zeilen geht, soll er weiterhin zentriert bleiben (sich sozusagen nach unten und nach oben gleichzeitig ausbreiten und nicht nur nach unten). Und wenn er dann noch so lang wird, dass er nicht mehr in diesen drittel Fensterteil passt, dann soll gescrollt werden (mit JScrollPane kann man das ja machen). Mein Problem ist nur das es genau so funktionieren soll. Ich habe schon Tips gelesen mit GridBagLayout oder BoxLayout (und dann oberhalb und unterhalb des Textes ein verticalGlue). Aber das hat alles nichts gebracht im Hinblick auf dieses spezielle Problem. Die Sache ist halt das das JTextPane merken muss, wenn der Text über den Rand hinausgeht, dass es sich dann vergrößert und wenn es merkt, dass es sich nicht mehr vergrößern kann, weil es an den Rand stößt, dass dann der JScrollPane zum Einsatz kommt. Ich hoffe ihr versteht, was ich meine. Entschuldigt den langen Text.  Ich mein es kann doch nicht so schwer sein einen Text mittig darzustellen. -.-

Danke schon mal für jede Hilfe


----------



## ellessedil (29. Jan 2011)

Hi,
interessantes Problem.
Meine Lösung ist vielleicht nicht schön, aber meiner Meinung nach elegant ;o).
Dein Vorschlag in Richtung des GridBagLayouts war schon richtig, wobei in diesem Fall die Klasse Box das viel einfacher erledigt. Der Text wird zwar nicht durch die TextPane zentriert, aber "who cares?" ;o)

Hier die Lösung.

```
import java.awt.Color;
import java.awt.Dimension;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

public class StandInTheMiddle extends JPanel {
	private static final long serialVersionUID = 7643726218850672636L;

	public StandInTheMiddle() {
		Box box = Box.createVerticalBox();

		JScrollPane sp = new JScrollPane(box);
		sp.setPreferredSize(new Dimension(320, 240));
		sp.getViewport().setBackground(Color.WHITE);

		box.add(Box.createVerticalGlue());

		StyleContext.NamedStyle centerStyle = StyleContext.getDefaultStyleContext().new NamedStyle();
		StyleConstants.setAlignment(centerStyle, StyleConstants.ALIGN_CENTER);

		final JTextPane tp = new JTextPane();
		tp.setLogicalStyle(centerStyle);
		tp.setText("Erste Zeile.");

		box.add(tp);

		tp.setMaximumSize(new Dimension(sp.getPreferredSize().width, 50));

		box.add(Box.createVerticalGlue());
		
		add(sp);
		
		Timer t = new Timer();
		t.schedule(new TimerTask() {
			
			@Override
			public void run() {
				tp.setText(tp.getText() + "\n eine Zeile mehr");			
			}
		}, 3000, 1000);
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame("TextFrame");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame.getContentPane().add(new StandInTheMiddle());

		frame.pack();

		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
}
```


----------



## TobyNick (29. Jan 2011)

DANKE! Es funktioniert!
Nur eine Sache noch nicht. Die kannst du auch an deinem Programm testen. Kommentier mal die Timer-Zeilen aus (die sind jetzt nicht wichtig). Und gib bei tp.setText irgendwas ganz langes ein, ohne Zeilenumbruch. Also ein ganz langes Wort sozusagen und ganz spät erst ein leerzeichen oder zeilenumbruch. Z.b. "sdghiusdfgiusdfhgisudhfuasifhdasifuhdsiuvhiguhdfibuhsdicuhsivuhdfviuhdcisuahfgiurenhuvinfi \n sdfjiugjfgiufgjiugs"
Dann ist das ein bisschen komisch. Wüsstest du woran das liegt? Oder was man dagegen tun kann?


----------



## ellessedil (29. Jan 2011)

ja es liegt an der von mir gelobten Box ;o) Die verändert warum auch immer die Breite durch den überlangen String.
Wenn Du die PreferredSize der Box änderst, bekommst dieses Problem in den Griff, aber dadurch bekommst Du einige andere...
Die Box macht mir schon immer Schwierigkeiten, wenn man dort feste Werte vergibt...
Leider muss ich grad weg, schaue auch erst morgen wieder hier rein. Aber schau mal unter:
How to Use BoxLayout (The Java™ Tutorials > Creating a GUI With JFC/Swing > Laying Out Components Within a Container)

Vielleicht hilft das, ansonsten schau ich morgen nochmal danach.


----------



## ellessedil (30. Jan 2011)

ok, also das Problem ist, dass das Boxlayout penibel auf Preferred und Max-Size reagiert. Mit diesem überlangen String reagiert die PreferredSize der TextPane auf einen X-Wert, der die Anzeige des Strings in einer Zeile ermöglicht. Daher wurde auch die Box größer. Hab bissl rumgewurschtelt und es ein wenig andersherum probiert. In meinem Beispiel hast Du nun eine Box, die eine JScrollPane mit VerticalGlue umspannt, um sie in der Mitte zu halten. Solange der Text "größer" wird, passe ich die Größe der ScrollPane bis zu ihrem Maximum an, was den gewünschten Effekt bringt, aber irgendwie nicht mehr ganz so schön ist. Das Borderlayout drumherum kann man irgendwie auch nicht weglassen, manchmal ist mir Java ein Rätsel ;o)

```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

public class StandInTheMiddle extends JPanel {
	private static final long serialVersionUID = 7643726218850672636L;

	int maxWidth = 320;
	int maxHeight = 240;

	public StandInTheMiddle() {
		setPreferredSize(new Dimension(maxWidth, maxHeight));

		setLayout(new BorderLayout());

		final Box box = Box.createVerticalBox();

		box.add(Box.createVerticalGlue());

		StyleContext.NamedStyle centerStyle = StyleContext.getDefaultStyleContext().new NamedStyle();
		StyleConstants.setAlignment(centerStyle, StyleConstants.ALIGN_CENTER);

		final JTextPane tp = new JTextPane();
		tp.setBackground(Color.blue);
		tp.setMaximumSize(new Dimension(maxWidth - 5, 50));
		tp.setLogicalStyle(centerStyle);

		tp.setText("sdghiusdfgiusdfhgisudhfuasifhdasifuhdsiuvhiguhdfibuhsdicuhsivuhdfviuhdcisuahfgiurenhuvinfi \n sdfjiugjfgiufgjiugs ");

		tp.repaint();
		tp.revalidate();

		final JScrollPane sp = new JScrollPane(tp);
		sp.setMaximumSize(new Dimension(maxWidth, 240));
		sp.getViewport().setBackground(Color.WHITE);

		box.add(sp);

		box.add(Box.createVerticalGlue());

		add(box, BorderLayout.CENTER);

		Timer t = new Timer();
		t.schedule(new TimerTask() {

			@Override
			public void run() {
				tp.setText(tp.getText() + "\n eine Zeile mehr");

				box.revalidate();
			}
		}, 3000, 1000);
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame("TextFrame");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame.getContentPane().add(new StandInTheMiddle());
		frame.pack();

		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
}
```


----------

