- PR -

JTextPaneへのコンポーネント追加時の挙動について

1
投稿者投稿内容
えにょ
会議室デビュー日: 2006/01/29
投稿数: 3
投稿日時: 2006-01-29 09:40
自分ではどうも原因が分からないので質問させてください。

現在JTextPaneを用いてエディタを製作しているのですが、その途中insertComponentメソッドを用いてコンポーネントをJTextPaneに追加する際に、通常ならば追加されたコンポーネントがエリア上に表示されるはずですが、他のクラスで生成されたドキュメントをJTextPaneにセットした後にinsertComponentメソッドを用いてコンポーネントの追加を行うと、なぜかコンポーネントがJTextPane上に表示されません(内部では関連付けられているドキュメントに挿入されているようです)。これは何が原因なのでしょうか?

この現象を再現するソースを以下に記載します。

■ファイル名: JTextPaneTest.java
コード:
import java.awt.*;

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

class JTextPaneTest extends JFrame implements ActionListener{
JTextPane text;
JScrollPane scroll;
JButton button01;
JButton button02;

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

JTextPaneTest(){
text = new JTextPane();
scroll = new JScrollPane(text);
scroll.setPreferredSize(new Dimension(400,300));
button01 = new JButton("JTextPaneへのコンポーネントの挿入");
button01.addActionListener(this);
button01.setActionCommand("ins");
button02 = new JButton("JTextPaneへの他ドキュメントセット");
button02.addActionListener(this);
button02.setActionCommand("set");

getContentPane().add(scroll,BorderLayout.NORTH);
getContentPane().add(button01,BorderLayout.CENTER);
getContentPane().add(button02,BorderLayout.SOUTH);

pack();
setTitle("JTextPaneTest");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
text.grabFocus();
setVisible(true);
}

public void actionPerformed(ActionEvent e){
if(e.getActionCommand().equals("ins")){
text.insertComponent(new JLabel("ラベルコンポーネント"));
text.grabFocus();
}else if(e.getActionCommand().equals("set")){
text.setDocument(Other.makeStyledDocument("他のクラスで生成されたドキュメント"));
}
}
}

class Other{
public static StyledDocument makeStyledDocument(String ss){
JTextPane text = new JTextPane();
text.setText(ss);

return text.getStyledDocument();
}
}



■Javaのバージョン
引用:
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)



[ メッセージ編集済み 編集者: えにょ 編集日時 2006-01-30 09:45 ]
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2006-01-29 16:27
えにょさん、こんにちは。

まず、このプログラム実行すると例外が出ていますよね。

そして問題が起こるのは、えにょさんのプログラムでは
APIドキュメントの insertComponent()に書かれて
いる、『複数のテキストコンポーネントでモデルを共用
する場合は、このメソッドを使わないで下さい。』とい
う注意書きを守っていないことが原因です。
えにょ
会議室デビュー日: 2006/01/29
投稿数: 3
投稿日時: 2006-01-30 04:37
Kissingerさんレスどうもです。

>>まず、このプログラム実行すると例外が出ていますよね。

私の環境では上記プログラムを実行しても例外が出ないんですが
どこで例外が出てるか参考までに教えて頂きたいです。

>>『複数のテキストコンポーネントでモデルを共用
>>する場合は、このメソッドを使わないで下さい。』

APIリファレンスは私も読みましたが、この注意書きには
「コンポーネントは複数のコンテナの子になることはできないため...」
とあるので挿入するコンポーネント自体を複数の場所で
共用してはいけないと認識していました。
私の見当違いなんでしょうか・・・。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2006-01-31 00:55
えにょさん、お返事が遅くなりました。

例外は、コンポーネントを挿入したあと、自動的に
レイアウト変更されるときに発生しております。
※それ自体が問題なら、ここにスタックトレースを
 貼っても良いのですが、根本的な原因を解決する
 べきなのでとりあえず、省略します。

挿入するコンポーネント自体を複数の場所で共用し
てはいけないという認識で正しいです。

えにょさんのプログラムでは、挿入するたびにコン
ポーネントを生成してはいますが、JTextPaneTestクラ
ス内部で作られた JTextPaneのオブジェクトに挿入し
ているつもりが、Otherクラス内で作った JTextPaneの
オブジェクトにも挿入しようとしています。
それが、共有してしまっている意味です。

私の説明うまくないので、別の説明をしますと、
Otherの内部の JTextPaneから取り出した Documentは、
その JTextPaneから取り除かれたわけではありません。
そのドキュメントを別の JTextPaneに設定すると、
1個のDocumentが2つのJTextPaneに関係付けられて
しまいます。

もし、確認したいなら、Otherの中で作った JTextPane
も表示してみれば、挿入したコンポーネントがそち
らのほうに表示されているのが確認できますよ。
※ただし、もう一方の JTextPaneのレイアウト
 処理で例外が発生するため、表示は乱れます。

えにょさんのやりたいことを満たすかわかりませんが、
なるべく近い形で、Otherクラスを書きなおしてみました。
コード:
class Other {
    public static StyledDocument makeStyledDocument(String ss)
        throws BadLocationException
    {
        StyledDocument document = new DefaultStyledDocument();
        document.insertString(0, ss, null);
        return document;
    }
}


参考になればよいのですが。
えにょ
会議室デビュー日: 2006/01/29
投稿数: 3
投稿日時: 2006-01-31 02:27
Kissingerさん、レスありがとうございます。
おかげでこの問題の原因の意味がよく分かりました。
他クラスで生成したJTextPaneとStyledDocumentの関連は消えずに残るんですね・・・。
それとStyledDocumentの生成と編集がJTextPaneでしか行えないものだと
勘違いしていたのでこんな変な書き方をしてしまったのだと思います。
丁寧な説明ありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)