16

JTextPaneを使用している2つの異なるエディターがあり、以前のJVMバージョンでは発生しなかったJava7の奇妙なバグがあります。これは、スタイル付きのテキストまたはコンポーネントを含む長い行で発生します。

これは、このバグを示す例です。この例では、文字が挿入されるたびに、すべてのテキストにデフォルトのスタイルが適用されます。JDK1.7.0_04でテストしました。

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

public class BugWrapJava7 extends JFrame {

    JTextPane jtp;
    StyledDocument doc;

    public BugWrapJava7() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        jtp = new JTextPane();
        add(jtp, BorderLayout.CENTER);
        jtp.setText("\ntype some text in the above empty line and check the wrapping behavior");
        doc = jtp.getStyledDocument();
        doc.addDocumentListener(new DocumentListener() {
            public void insertUpdate(DocumentEvent e) {
                insert();
            }
            public void removeUpdate(DocumentEvent e) {
            }
            public void changedUpdate(DocumentEvent e) {
            }
        });
        setSize(200, 200);
        setVisible(true);
    }
    public void insert() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE);
                doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false);
            }
        });
    }
    public static void main(String[] args) {
        new BugWrapJava7();
    }
}

私の質問は:私のコードに何か問題がありますか、それともJava 7で導入された新しいバグですか?また、それが新しいJVMバグである場合、回避策はありますか?

質問8666727に関連している可能性がありますが、ここでの問題は、スクロールバーの外観ではなく、間違った折り返しにあります。

4

3 に答える 3

16

先物の読者のために、バグはJDK1.7.0_04にまだ存在します。

Java7と安定したJava6を比較して、

ここに画像の説明を入力してください<------Java7とJava6--->ここに画像の説明を入力してください

ここに画像の説明を入力してください<------Java7とJava6--->ここに画像の説明を入力してください

ここに画像の説明を入力してください<------Java7とJava6--->ここに画像の説明を入力してください

ここに画像の説明を入力してください <------Java7とJava6---> ここに画像の説明を入力してください

コードから

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

public class BugWrapJava7 {

    private JFrame frame = new JFrame();
    private JTextPane jtp;
    private StyledDocument doc;

    public BugWrapJava7() {
        jtp = new JTextPane();
        jtp.setText("\ntype some text in the above empty line and check the wrapping behavior");
        doc = jtp.getStyledDocument();
        doc.addDocumentListener(new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                insert();
            }

            public void removeUpdate(DocumentEvent e) {
                insert();
            }

            public void changedUpdate(DocumentEvent e) {
                insert();
            }

            public void insert() {
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE);
                        doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false);
                    }
                });
            }
        });
        JScrollPane scroll = new JScrollPane(jtp);
        scroll.setPreferredSize(new Dimension(200, 200));
        frame.add(scroll);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

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

            public void run() {
                BugWrapJava7 bugWrapJava7 = new BugWrapJava7();
            }
        });
    }
}
于 2012-06-12T17:44:35.683 に答える
8

これを調査しました。その理由は、breakSpotsのキャッシュです。それらを保存しているように見えLabelView、以前のテキスト編集でオフセットを再計算しません。手動でリセットしてもバグは発生しません。

回避策(プライベートbreakSpotsフィールドのために非常に汚れています)は次のとおりです

import java.awt.Dimension;
import java.lang.reflect.Field;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

public class BugWrapJava7 {

    private JFrame frame = new JFrame();
    private JTextPane jtp;
    private StyledDocument doc;

    public BugWrapJava7() {
        jtp = new JTextPane();
        jtp.setEditorKit(new MyStyledEditorKit());
        jtp.setText("\ntype some text in the above empty line and check the wrapping behavior");
        doc = jtp.getStyledDocument();
        doc.addDocumentListener(new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                insert();
            }

            public void removeUpdate(DocumentEvent e) {
                insert();
            }

            public void changedUpdate(DocumentEvent e) {
                insert();
            }

            public void insert() {
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE);
                        doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false);
                    }
                });
            }
        });
        JScrollPane scroll = new JScrollPane(jtp);
        scroll.setPreferredSize(new Dimension(200, 200));
        frame.add(scroll);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

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

            public void run() {
                BugWrapJava7 bugWrapJava7 = new BugWrapJava7();
            }
        });
    }
}

class MyStyledEditorKit extends StyledEditorKit {
    private MyFactory factory;

    public ViewFactory getViewFactory() {
        if (factory == null) {
            factory = new MyFactory();
        }
        return factory;
    }
}

class MyFactory implements ViewFactory {
    public View create(Element elem) {
        String kind = elem.getName();
        if (kind != null) {
            if (kind.equals(AbstractDocument.ContentElementName)) {
                return new MyLabelView(elem);
            } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
                return new ParagraphView(elem);
            } else if (kind.equals(AbstractDocument.SectionElementName)) {
                return new BoxView(elem, View.Y_AXIS);
            } else if (kind.equals(StyleConstants.ComponentElementName)) {
                return new ComponentView(elem);
            } else if (kind.equals(StyleConstants.IconElementName)) {
                return new IconView(elem);
            }
        }

        // default to text display
        return new LabelView(elem);
    }
}

class MyLabelView extends LabelView {
    public MyLabelView(Element elem) {
        super(elem);
    }
    public View breakView(int axis, int p0, float pos, float len) {
        if (axis == View.X_AXIS) {
            resetBreakSpots();
        }
        return super.breakView(axis, p0, pos, len);
    }

    private void resetBreakSpots() {
        try {
            // HACK the breakSpots private fields
            Field f=GlyphView.class.getDeclaredField("breakSpots");
            f.setAccessible(true);
            f.set(this, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

反射なしでハックを減らします。モデル変更時のbreakSpotsの通常のリセットに基づきます。

class MyLabelView extends LabelView {

    boolean isResetBreakSpots=false;

    public MyLabelView(Element elem) {
        super(elem);
    }
    public View breakView(int axis, int p0, float pos, float len) {
        if (axis == View.X_AXIS) {
            resetBreakSpots();
        }
        return super.breakView(axis, p0, pos, len);
    }

    private void resetBreakSpots() {
        isResetBreakSpots=true;
        removeUpdate(null, null, null);
        isResetBreakSpots=false;

//        try {
//            Field f=GlyphView.class.getDeclaredField("breakSpots");
//            f.setAccessible(true);
//            f.set(this, null);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }

    public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
        super.removeUpdate(e, a, f);
    }

    public void preferenceChanged(View child, boolean width, boolean height) {
        if (!isResetBreakSpots) {
            super.preferenceChanged(child, width, height);
        }
    }
}

更新:これはTextSamplerDemoも修正します。すべてのラベルビューのすべてのスポットをリセットしました。

class MyStyledEditorKit extends StyledEditorKit {
    private MyFactory factory;

    public ViewFactory getViewFactory() {
        if (factory == null) {
            factory = new MyFactory();
        }
        return factory;
    }
}

class MyFactory implements ViewFactory {
    public View create(Element elem) {
        String kind = elem.getName();
        if (kind != null) {
            if (kind.equals(AbstractDocument.ContentElementName)) {
                return new MyLabelView(elem);
            } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
                return new MyParagraphView(elem);
            } else if (kind.equals(AbstractDocument.SectionElementName)) {
                return new BoxView(elem, View.Y_AXIS);
            } else if (kind.equals(StyleConstants.ComponentElementName)) {
                return new ComponentView(elem);
            } else if (kind.equals(StyleConstants.IconElementName)) {
                return new IconView(elem);
            }
        }

        // default to text display
        return new LabelView(elem);
    }
}

class MyParagraphView extends ParagraphView {

    public MyParagraphView(Element elem) {
        super(elem);
    }
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
    super.removeUpdate(e, a, f);
    resetBreakSpots();
}
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
    super.insertUpdate(e, a, f);
    resetBreakSpots();
}

private void resetBreakSpots() {
    for (int i=0; i<layoutPool.getViewCount(); i++) {
        View v=layoutPool.getView(i);
        if (v instanceof MyLabelView) {
            ((MyLabelView)v).resetBreakSpots();
        }
    }
}

}

class MyLabelView extends LabelView {

    boolean isResetBreakSpots=false;

    public MyLabelView(Element elem) {
        super(elem);
    }
    public View breakView(int axis, int p0, float pos, float len) {
        if (axis == View.X_AXIS) {
            resetBreakSpots();
        }
        return super.breakView(axis, p0, pos, len);
    }

    public void resetBreakSpots() {
        isResetBreakSpots=true;
        removeUpdate(null, null, null);
        isResetBreakSpots=false;
   }

    public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
        super.removeUpdate(e, a, f);
    }

    public void preferenceChanged(View child, boolean width, boolean height) {
        if (!isResetBreakSpots) {
            super.preferenceChanged(child, width, height);
        }
    }
}
于 2013-01-09T08:02:44.393 に答える
0

私のHTMLDocumentは文字ごとに折り返されていました。上記のStanislavLのソリューションをインストールしました。喜びはありませんが、<td>要素内で文字ごとに折り返します。そこで、StanislavLのコードのバグを修正しました。喜び; どこでも単語ごとにラッピング。次に、自分のプログラムがStanislavLコードを使用していないことを発見しました。私のいじくり回しは、私自身のコードの同じバグを修正したようです。

問題は、2種類の要素(javax.swing.textとjavax.swing.text.html.parser)があり、どちらも文字列値「content」のタグタイプ名を持っていることです。メソッドElement.getNameは、オブジェクトの代わりに文字列を返すことでこれを混乱させます。

したがって、コードが「.equals()」と言っている場合

    String kind = elem.getName();
    if (kind != null) {
        if (kind.equals(AbstractDocument.ContentElementName)) {
    ...

「=="」と表示されます

    Object absDocName = attrs.getAttribute(AbstractDocument.ElementNameAttribute)
    if (absDocName != null){
        if (kind == AbstractDocument.ContentElementName) {
    ...
于 2019-09-03T18:26:08.610 に答える