Exception beim LineWrapping

Status
Nicht offen für weitere Antworten.

Arbon

Bekanntes Mitglied
Hallo. Ich hab ein JLabel, welches automatisch einen Zeilenumbruch implementieren soll. Ich habe dazu folgendes gefunden:
forums.sun.com/thread.jspa?threadID=623043&tstart=32519
Das besagte Programm funktioniert auch ohne Probleme. Wenn ich es aber in meinen Chat integrieren will, funktioniert es nicht mehr. Ich verwende die Klasse wie folgt:

PS: Die Klasse TextWrapper entspricht dem in der oberen Seite angegeben "class SizeTestLabel extends JLabel", lediglich der Konstruktor wurde abgeändert (Text wird nicht am Anfang festgelegt), was aber eigendlich keine Probleme verursachen sollte.

Code:
	/**
	 * The Class MyListRenderer.
	 */
	class MyListRenderer extends TextWrapper implements ListCellRenderer {

		public MyListRenderer() {
                        super();
			setOpaque(true);
		}

		/** The Constant serialVersionUID. */
		private static final long serialVersionUID = -6477398272501139124L;

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing
		 * .JList, java.lang.Object, int, boolean, boolean)
		 */
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			setSize(0, 25);
			changeText("<html>" + value.toString() + "</html>");
			try {
				if (!((ClientTextListObject) value).isHeader()) {
					setBackground(isSelected ? Color.blue : Color.white);
					setForeground(isSelected ? Color.white : Color.black);
				} else {
					setBackground(isSelected ? Color.blue : Color.lightGray);
					setForeground(isSelected ? Color.white : Color.red);
				}
			} catch (ClassCastException ex) {
				setBackground(isSelected ? Color.blue : Color.white);
				setForeground(isSelected ? Color.white : Color.black);
			}
			return this;
		}
	}

Dabei tritt immer folgende Exception auf:
Code:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at arm.chat.TextWrapper.findFontSize(TextWrapper.java:61)
	at arm.chat.TextWrapper.changeText(TextWrapper.java:82)
	at arm.chat.client.TextPanel$MyListRenderer.getListCellRendererComponent(TextPanel.java:69)
	at javax.swing.plaf.basic.BasicListUI.updateLayoutState(BasicListUI.java:1349)
	at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(BasicListUI.java:1299)
	at javax.swing.plaf.basic.BasicListUI.getPreferredSize(BasicListUI.java:566)
	at javax.swing.JComponent.getPreferredSize(JComponent.java:1632)
	at javax.swing.ScrollPaneLayout.layoutContainer(ScrollPaneLayout.java:769)
	at java.awt.Container.layout(Container.java:1398)
	at java.awt.Container.doLayout(Container.java:1387)
	at java.awt.Container.validateTree(Container.java:1485)
	at java.awt.Container.validate(Container.java:1457)
	at javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:670)
	at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:127)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
 
wie bereits erwähnt wurde diese Methode von dem Link oben übernommen. Hier ist sie nochmal wie sie jetzt bei mir akutell aussieht:

Code:
package arm.chat;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.JLabel;

public class TextWrapper extends JLabel
{
    /**
	 * 
	 */
	private static final long serialVersionUID = -4952477986216129011L;
	String text;
    Font font;
    final int PAD  = 20;
    final float SIZE = 6.0f;
 
    public TextWrapper()
    {
        font = new Font("lucida sans regular", Font.PLAIN, 24);
    }
 
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setFont(font);
        FontRenderContext frc = g2.getFontRenderContext();
        AttributedString as = new AttributedString(text);
        as.addAttribute(TextAttribute.FONT, font);
        AttributedCharacterIterator iterator = as.getIterator();
        LineBreakMeasurer measurer = new LineBreakMeasurer(iterator, frc);
        float wrappingWidth = getWidth() - 2*PAD;
        float x = PAD, y = PAD;
        while(measurer.getPosition() < text.length())
        {
            TextLayout layout = measurer.nextLayout(wrappingWidth);
            y += layout.getAscent();
            float dx = layout.isLeftToRight() ?
                           0 : wrappingWidth - layout.getAdvance();
            layout.draw(g2, x + dx, y);
            y += layout.getDescent() + layout.getLeading();
        }
    }
 
    private void findFontSize()
    {
        int h = getHeight();
        float y = 0;
        Font lastFont = font;
        float size = SIZE;
        while(y + PAD <= h)
        {
            y = PAD;
            Font testFont = font.deriveFont(++size);
            Graphics2D g2 = (Graphics2D)getGraphics();
            g2.setFont(testFont);
            FontRenderContext frc = g2.getFontRenderContext();
            AttributedString as = new AttributedString(text);
            as.addAttribute(TextAttribute.FONT, testFont);
            AttributedCharacterIterator iterator = as.getIterator();
            LineBreakMeasurer measurer = new LineBreakMeasurer(iterator, frc);
            float wrappingWidth = getWidth() - 2*PAD;
            while(measurer.getPosition() < text.length())
            {
                TextLayout layout = measurer.nextLayout(wrappingWidth);
                y += layout.getAscent();
                y += layout.getDescent() + layout.getLeading();
            }
            if(y + PAD <= h)
                lastFont = testFont;
        }
        font = lastFont;
        repaint();
    }
 
    public void changeText(String s)
    {
        text = s;
        findFontSize();
    }
}
 
g2.setFont(testFont);
also bei zeile 68

Wenn ich allerdings das Beispiel von dem Link dort oben compiliere, funktinoiert es :/. Ich hab ja eigendlich nicht wirklich as geändert daran.
 
Nur ein schnellschuss aber:

public TextWrapper()
{
font = new Font("lucida sans regular", Font.PLAIN, 24);
}

ich würde erstmal auch im Konstruktor der abgeleiteten Klasse den super()-Konstruktor aufrufen
Also

public TextWrapper()
{
super();!!!!!!!!!
font = new Font("lucida sans regular", Font.PLAIN, 24);
}

Vielleicht liegts ja daran
 
leider nicht :/
Gäbe es vl noch alternativen zum JLabel, das eine Methode setLineWrap bietet, also eine Textkomponente? Die Vorraussetzung ist halt das es html tags beherrscht, auch den img-tag um smilies einzubinde.
 
Was ist überhaupt dein testFont, warum nicht gleich ein "richtiger Font", also dein Sans Serif.

Ansonsten bietet JTextArea nen LineWrap, aber weiss nicht wegen Html Bescheid
 
ahh egeal wegen dem testfont, hab jetzt verstanden worauf das hinauslaufen soll
 
Anonymous hat gesagt.:
public TextWrapper()
{
super();!!!!!!!!!
font = new Font("lucida sans regular", Font.PLAIN, 24);
}
Ich weiß ja nicht, ob die Ausrufezeichen etwas daran ändern... ;-) Aber der Default-Super-Konstruktor wird implizit gerufen, wenn nichts anderes dasteht. Also: weglassen macht das gleiche.

Ursache des Problems
getGraphics() gibt null zurück. Warum ist das so? getGraphics() gibt immer null zurück, wenn die Komponente (noch) nicht displayable ist.

Im Beispiel aus dem Link wird changeText() bzw. findFontSize() von einem ActionListener ausgeführt. Das heißt, das passiert erst, wenn jemand einen Button drückt. In diesem Moment wird alles schon angezeigt und damit gibt getGraphics() auch ein Graphics-Objekt zurück.

In Deinem Beispiel wird changeText() bzw. findFontSize() aus einer getListCellRendererComponent()-Methode ausgeführt. Die Komponente hat zum Zeitpunkt des Aufrufs der Methode keinen vollständigen Hierarchybaum (also liegt nicht auf einem Window). Deswegen gibt es auch zu diesem Zeitpunkt keine Graphics-Instanz.

Lösung des Problems
Du kannst changeText() und findFontsize() um ein Graphics2D-Argument erweitern. In der Renderer-Methode holst Du Dir das Graphics-Objekt von der JList.

Mal sehen, ob ich recht habe...
 
Letzter Versuch 🙂
setz mal den Zugriffspezifiezierer von font auf protexted, weil du mit ableitung arbeitest wird das vielleiiicchhhht ja font nicht weitervererbt -> NullPointer

also:
public class TextWrapper extends JLabel
{
/**
*
*/
private static final long serialVersionUID = -4952477986216129011L;
PROTECTED String text;
PROTECTED Font font;
PROTECTD final int PAD = 20;
PROTECTD final float SIZE = 6.0f;
 
Ohh, deine Antwort noch nich gesehen, aber danke für den Hinweis mit dem super(), wusste ich nicht.

OK, Wettbewerb, mal sehen ob ich recht habe (;
 
Anonymous hat gesagt.:
setz mal den Zugriffspezifiezierer von font auf protexted, weil du mit ableitung arbeitest wird das vielleiiicchhhht ja font nicht weitervererbt -> NullPointer
Vielleicht schneit's auch und das ist der Grund. ;-) Ich bin mir ziemlich sicher, dass meine Lösung oben stimmt... Arbon mach hin! Ich bin gespannt...
 
Wahrscheinlich habe ich nicht recht, wenn ich es mir recht überlege ):
 
Ebenius hatte recht. Nacher kam noch ein Fehler, der ebenfalls damit zu tun hatte dass die Komponente noch nicht displayable war, aber den hab ich jetzt selber hingekriegt da ich nun ja wusste woran das liegt. Jetzt ist ein neues Problem, er stürzt zwar nicht ab aber es wird gar nix angezeigt. Ich mach jetzt aber schluss für heute und werde morgen schauen ob ich das vl noch selber hinbekomme.
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben