Javaの道 Javaに関する
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道 >  掲示板 >  掲示板(ExcelのデータをJTableに格納とすると実行時にエラーが出て困っています。)
閲覧数:2053
掲示板(ExcelのデータをJTableに格納とすると実行時にエラーが出て困っています。)
名前
匿名
題名 ExcelのデータをJTableに格納とすると実行時にエラーが出て困っています。
質問内容

質問を評価する
(0ポイント)
eclipseでApache POIを使ってExcelのデータを取得し、JTableに格納しようとしています。
ですが、以下のようなエラーが出てしまって困っています。

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.table.DefaultTableCellRenderer$UIResource cannot be cast to javax.swing.text.JTextComponent
    at javax.swing.text.html.EditableView.paint(EditableView.java:76)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.ParagraphView.paint(ParagraphView.java:587)
    at javax.swing.text.html.ParagraphView.paint(ParagraphView.java:233)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.html.BlockView.paint(BlockView.java:282)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.html.BlockView.paint(BlockView.java:282)
    at javax.swing.plaf.basic.BasicHTML$Renderer.paint(BasicHTML.java:481)
    at javax.swing.plaf.basic.BasicLabelUI.paint(BasicLabelUI.java:173)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:778)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.CellRendererPane.paintComponent(CellRendererPane.java:151)
    at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2115)
    at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
    at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:778)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JSplitPane.paintChildren(JSplitPane.java:1047)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5228)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1482)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1413)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1206)
    at javax.swing.JComponent.paint(JComponent.java:1040)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:78)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:115)
    at java.awt.Container.paint(Container.java:1967)
    at java.awt.Window.paint(Window.java:3877)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:781)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:728)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:677)
    at javax.swing.RepaintManager.access$700(RepaintManager.java:59)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1621)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:721)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:682)
    at java.awt.EventQueue$3.run(EventQueue.java:680)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:691)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

エラーは出るものの一応ExcelのデータはJTableに格納されているようで、画面を見るとJTable部分にExcelのデータが入っているのが見えます。
また、そのテーブルをクリックしてみても同じエラーが出ます。

とりあえず原因がありそうな部分周辺を貼っておきます。

InputStream is = new FileInputStream(file.getPath());
Workbook wb = WorkbookFactory.create(is);
JTable[] tagTable = new JTable[wb.getNumberOfSheets()];
for(int n = 0;n<wb.getNumberOfSheets();n++){
    //tagTable[n]
    Sheet sheet = wb.getSheetAt(n);
    int r=0;
    while(sheet.getRow(r)!= null){
        r++;
    }
    tagTable[n] = new JTable(r,2);
    for(r--;r>=0;r--){
        Row row = sheet.getRow(r);
        tagTable[n].setValueAt(row.getCell(0).getStringCellValue(), r, 0);
        tagTable[n].setValueAt(row.getCell(1).getStringCellValue(), r, 1);
    }
    tagTab.addTab(wb.getSheetName(n), tagTable[n]);
}

テーブルにデータを格納する部分を書くまではエラー出ることなく動いていたので、多分テーブルにデータを格納する部分が原因だと思っていますが、私にははっきりとはわかっていません。
どうしたらエラーを解決できるでしょうか?
長文になってしまいましたが、よろしくお願いします。
質問日時 2013-01-24 00:39:30
名前
匿名
回答内容

回答を評価する
(0ポイント)
もう少し見てみたところ、最初に見ているタブに問題があるようで、ほかのタブに切り替えたときはエラーが出ませんでした。
そのタブにあるJTableには以下のようなExcelデータを入れています。
(A列にタグ、B列にタグ説明があります。)

<html>\n<head>\n<title></title>\n</head>\n<body>\n</body>\n</html>    基本タグセット
<html>\n</html>    htmlタグ
<head>\n</head>    ヘッダー
<title></title>    タイトル
<body>\n</body>    本文

ほかのシートの内容と(書き方において)違う点は\nが入っているくらいです。
それが原因ではないとも思いましたが、ためしに\nを消してみました。
ですが、やはりそれでもエラーが出てしまいます。
いったいどこに原因があるのでしょうか?
回答日時 2013-01-24 21:31:38
名前
匿名
回答内容

回答を評価する
(0ポイント)
POI使わずに直接ダミーの値を入れると?
POIは関係ない気がするんだけど。
回答日時 2013-01-24 23:32:11
名前
匿名
回答内容

回答を評価する
(0ポイント)
row.getCell(0).getStringCellValue()とかの代わりに空の文字
列""や"tag","タグ"などを入れて試してみると、エラーが出るこ
となく表示できました。
また、シートを入れ替えてみてもそこのデータを入れた
JTableがあるタブだけエラーになってしまうので、そのシー
トのデータが原因のようです。
そこで、試しに1行目のデータをほかのシートに移動させて代
わりの文字(A1に<>,B1にdummy)を入れてみると、そのタブ
はエラーが出ることなく表示できました。
ということはそのデータに問題があるようです。
試しにそのデータをセルのコピーではなく数式バーからすべ
て選んでコピーして貼り付けてみると、\n\n\nになっていまし
た。
そもそもこのデータはiPod touchのメモで書いていたものを
Yahoo!メールに送り、そのままだとwebのフォント等が残る
のでは?と一度メモ帳に張り付けたものをコピーしてExcelに
張り付けたものです。
もしかしたらそのどこかでデータが見た目は正しくても内部
は異なってしまったのかもしれません。
でも、そのデータをどこかからのコピペでなく手打ちでやっ
てみるもエラーが消えませんでした。
問題はそこだけではないのかもしれないとそのシートのデー
タすべて手打ちしなおしてみても変わりませんでした。
そのタブのデータをよく見てみると、
<html>\n<head>\n<title>
</title>\n</head>\n<body>\n</body>\n</html>が\n\n\n\n\nと、
<html>\n</html>が\nと表示されていました。
問題はこの2つにあるようです 。
そこで、その2つに共通しているhtmlを削除してみました。
すると、今度はエラーが出ることなく表示することができま
した。
また、htmlをhtmにしてもエラーが出ることなく表示すること
ができました。
そこからhtmlに戻してみると、再びエラーが出るようになり
ました。
そこで、ソースから直接"<html>"と"</html>"を入れてみると、
</html>は表示されるのですが<html>のほうは表示されません
でした。
また<html>の後ろに何かを書き足すとそれだけしか表示され
ませんでした。
<html>ってなにか問題あったのでしょうか?
回答日時 2013-01-25 04:37:35
名前
匿名
回答内容

回答を評価する
(0ポイント)
やっぱりPOIは関係ないみたいね。
デフォルトのレンダラがタグを解釈するんだったかな。

<を&lt;に置換するか、レンダラを自分で用意してセットする
か、なのかな。
試してないけど。
回答日時 2013-01-25 08:12:45
名前
匿名
回答内容

回答を評価する
(0ポイント)
<を&lt;に置換してみると、エラーは出ないものの&lt;は&lt;のままでした。
レンダラのことはまだ理解できていませんが、デフォルトで<html>を見つけたらタグが記述されたと解釈されてそれ以降のタグも(webページと同じように)出てこなくなるのですね。
とりあえずレンダラについてもう少し調べてみようと思います。
回答日時 2013-01-25 14:52:40
名前
匿名
回答内容

回答を評価する
(0ポイント)
デフォルトのレンダラがJLabelの拡張だからって話みたいね。
やっぱりレンダラを自前で用意するしかないなー。
回答日時 2013-01-25 17:32:57
名前
匿名
回答内容

回答を評価する
(0ポイント)
JComponent#putClientProperty("html.disable", 
Boolean.TRUE);
として、HTMLタグの自動解釈, HTMLレンダリングを無効
化してやれば良いです。

今回の場合はTableCellRender、
DefaultTableCellRender(JLabel)でしょうか?を使って
いるならば、DefaultTableCellRenderに対して上記を設
定します。

詳細は、javax.swing.plaf.basic.BasicHTMLのソースコ
ードを参照してください。

参考:http://tinyurl.com/bg3xlae

# JAVA4, 5あたりでは、VM起動時のシステムプロパティ
でも設定できたような記憶がありますが、JAVA6, 7でも
可能なのかは知りません。
回答日時 2013-01-25 17:53:05
名前
匿名
回答内容

回答を評価する
(0ポイント)
おー、プロパティあったのか。知らなかった。
メモメモ。
回答日時 2013-01-25 18:32:05
名前
匿名
回答内容

回答を評価する
(0ポイント)
tagTable[n] = new JTable(r,2);
tagTable[n].putClientProperty("html.disable", Boolean.TRUE);

としてみましたが、最初の<html>\n<head>\n<title></title>\n</head>\n<body>\n</body>\n</html>の部分はきちんと表示されたものの、相変わらずエラーが出てしまっていて、次の<html>\n</html>は相変わらず\nでした。

使い方が違っていたのでしょうか?
回答日時 2013-01-27 14:55:55
名前
匿名
回答内容

回答を評価する
(0ポイント)
テーブルじゃなくてレンダラに、て書いてくれてるじゃん。
回答日時 2013-01-27 18:39:32
名前
匿名
回答内容

回答を評価する
(0ポイント)
以下のサイトを参考にこのようにしてみました。

高木浩光@自宅の日記 - 久しぶりのSwing開発で躓いたところ
http://takagi-hiromitsu.jp/diary/20091219.html

TableCellRendererでセルの背景色を変更 - Java Swing Tips
http://terai.xrea.jp/Swing/StripeTable.html

TableRenderer renderer = new TableRenderer();
省略
tagTable[n].setDefaultRenderer(String.class, renderer);
省略
class TableRenderer extends DefaultTableCellRenderer {
    @Override public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus,
            int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        putClientProperty("html.disable", Boolean.TRUE);
        return this;
    }
}

それでも症状は変わりませんでした。
これも使い方間違っているでしょうか?
回答日時 2013-01-28 12:38:55
名前
匿名
回答内容

回答を評価する
(0ポイント)
>これも使い方間違っているでしょうか?
間違ってはいません。
ただし、TableCellRendererの適用方法
(setDefaultRenderer(String.class, renderer);の一
文)が間違っています。

あなたが使用しているTableRendererの
getTableCellRendererComponent内で、
print文でも記述してみれば、このTableCellRendererが
呼び出されていないことが分かるはずです。

また、prepareRenderer(TableCellRenderer renderer, 
int row, int column)をオーバーライドしてrendererを
printして確認してみたり、getCellRenderer(int row, 
int column)を実行して戻り値を確認してみても、あな
たが期待するTableRendererは取得できていないはずで
す。

では、なぜこれが呼び出されないのか?
問題を細分化して、論理的に考える習慣をつけないとい
けないです。

javadocが分かりにくければ、ソースコードを読んでみ
れば一目瞭然なのですが、
まずば、JTableのjavadocで
setDefaultRenderer(Class<?> columnClass, 
TableCellRenderer renderer)の下記の文を読んでみて
ください。

Sets a default cell renderer to be used if no 
renderer has been set in a TableColumn. If 
renderer is null, removes the default renderer for 
this column class.

あなたの使用しているTableModelでcolumnClassには
String.classを指定しているでしょうか?

自分でデフォルトの設定を変更するならば、その変更に
適応するように、そちらの設定も変えなければいけない
でしょう。
回答日時 2013-01-28 19:26:20
名前
匿名
回答内容

回答を評価する
(0ポイント)
自分で変更する前のsetDefaultRenderer(Object.class, renderer);にすると、getTableCellRendererComponent内に置いてみたprintlnは表示されるのですが、println1回目の後で一度だけ以下のようなエラーが出てました。

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: HTMLEditor.TagShow$TableRenderer cannot be cast to javax.swing.text.JTextComponent
    at javax.swing.text.html.EditableView.paint(EditableView.java:76)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.ParagraphView.paint(ParagraphView.java:587)
    at javax.swing.text.html.ParagraphView.paint(ParagraphView.java:233)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.html.BlockView.paint(BlockView.java:282)
    at javax.swing.text.BoxView.paintChild(BoxView.java:161)
    at javax.swing.text.BoxView.paint(BoxView.java:433)
    at javax.swing.text.html.BlockView.paint(BlockView.java:282)
    at javax.swing.plaf.basic.BasicHTML$Renderer.paint(BasicHTML.java:481)
    at javax.swing.plaf.basic.BasicLabelUI.paint(BasicLabelUI.java:173)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:778)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.CellRendererPane.paintComponent(CellRendererPane.java:151)
    at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2115)
    at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
    at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:778)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JViewport.paint(JViewport.java:731)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JSplitPane.paintChildren(JSplitPane.java:1047)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5228)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1482)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1413)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1206)
    at javax.swing.JComponent.paint(JComponent.java:1040)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:78)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:115)
    at java.awt.Container.paint(Container.java:1967)
    at java.awt.Window.paint(Window.java:3877)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:781)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:728)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:677)
    at javax.swing.RepaintManager.access$700(RepaintManager.java:59)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1621)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:721)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:682)
    at java.awt.EventQueue$3.run(EventQueue.java:680)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:691)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

そういうことじゃなかったのでしょうか?
回答日時 2013-01-28 20:22:49
名前
匿名
回答内容

回答を評価する
(0ポイント)
>そういうことじゃなかったのでしょうか?
そういうことです。

こちらで、ミニマムコードを書いて下記バージョンで実
行してみましたが、一切例外はスローされませんので、
これ以上は分かりません。
java 1.7.0_07
java 1.6.0_23

ところで、EDTではないスレッドで実行していませんか?
それが怪しいと思いますが。
回答日時 2013-01-28 21:18:35
名前
匿名
回答内容

回答を評価する
(0ポイント)
すいません。
EDTってなんですか?
初めて聞いたもので。
自分でもevent dispatch threadについて調べてみていますが、まだ全然わかっていません。
そういうのを知らないからこのようなことでつまずいてしまっているんでしょうね。

ちなみに、ここに載せたソースはmainを含んでいない自作classの中に書いています。
class・関数で囲んでいない部分はその自作class内の自作関数の中に書いています。
回答日時 2013-01-28 21:47:55
名前
匿名
回答内容

回答を評価する
(0ポイント)
EDTはEvent Dispatch Threadのことです。

ここを読んでください。
http://docs.oracle.com/javase/tutorial/uiswing/con
currency/dispatch.html

>そういうのを知らないからこのようなことでつまずい
てしまっているんでしょうね。

そうとは限りませんが、基礎を学習しておけば、無用な
問題を回避できると思いますので、swingに限らず使用
するAPI毎に、javadoc, java tutorialは一読しておい
た方が良いと思います。
http://docs.oracle.com/javase/tutorial/uiswing/

使用しながら、その都度習得していくというスタイルも
否定はしませんが。

また、スレッドやスレッドセーフはswingだけでなく、
マルチスレッドに対応している言語一般で重要です。
javaでいえば、個々のクラス、メソッドを設計、作成す
る場合でも、常に意識する必要があります。

>ちなみに、ここに載せたソースはmainを含んでいない
自作classの中に書いています。
class・関数で囲んでいない部分はその自作class内の自
作関数の中に書いています。

先の回答でも書きましたが、まずは、その問題を局所化
したミニマムコードを書いて実行してみることが重要で
す。

なぜその問題が発生するのか、発生しなくなったなら
ば、なぜ発生しなくなったのか、どうすれば、発生する
コードを書けるか、そういった疑問を論理的に考察しな
がら、その問題が発生する可能な限り最小の単位に切り
分ける試行を繰り返すことで、自然にそのように考えら
れるようになると思います。

大きな問題は小さな問題に分解することが重要です。
入門時点で優秀な人でない限り、そういうものだと思い
ます。
頑張ってください。
回答日時 2013-01-28 22:38:17
名前
匿名
回答内容

回答を評価する
(0ポイント)
FrameにJTabbedPaneを配置し、その中にJTableを配置してそこにExcelデータを入れるプログラムを作ってみました。

package ExcelTest;

import java.awt.Component;
import java.awt.Frame;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class ExcelTest extends Frame{
    public JTabbedPane tagTab = new JTabbedPane();

    ExcelTest(){
        setSize(400,400);
        addTab();
        add(tagTab);
        setVisible(true);
    }

    void addTab(){
        InputStream is;
        try {
            is = new FileInputStream("D:\\java\\HTMLEditor\\tag.xlsx");
            Workbook wb = WorkbookFactory.create(is);
            JTable[] tagTable = new JTable[wb.getNumberOfSheets()];
            TableRenderer renderer = new TableRenderer();
            for(int n = 0;n<wb.getNumberOfSheets();n++){
                Sheet sheet = wb.getSheetAt(n);
                int r=0;
                while(sheet.getRow(r)!= null){
                    r++;
                }
                tagTable[n] = new JTable(r,2);
                tagTable[n].setDefaultRenderer(Object.class, renderer);
                for(r--;r>=0;r--){
                    Row row = sheet.getRow(r);
                    tagTable[n].setValueAt(row.getCell(0).getStringCellValue(), r, 0);
                    tagTable[n].setValueAt(row.getCell(1).getStringCellValue(), r, 1);
                }
                tagTab.addTab(wb.getSheetName(n), tagTable[n]);
            }
        } catch (FileNotFoundException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        new ExcelTest();
    }

    class TableRenderer extends DefaultTableCellRenderer {
        @Override public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus,
                int row, int column) {
            System.out.println("pass");
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            putClientProperty("html.disable", Boolean.TRUE);
            return this;
        }
    }
}

エラーが出ているプログラムから抜き出しただけなので、もちろんエラーが出ました。

教えてもらったページや
How to Use HTML in Swing Components (The Java&#8482; Tutorials > Creating a GUI With JFC/Swing > Using Swing Components)
http://docs.oracle.com/javase/tutorial/uiswing/components/html.html
など読んでもう少し自分で勉強してみます。
回答日時 2013-01-31 01:07:46
名前
匿名
回答内容

回答を評価する
(0ポイント)
ふと思ったけど、<html>の前に何か1文字入れるとどうなんだ
ろ。
回答日時 2013-01-31 07:08:16
名前
匿名
回答内容

回答を評価する
(0ポイント)
<html>の前に半角スペースを入れてみました。
すると、エラーが出ることなくきちんと表示することができました。
ですが、今後そのJTableの中身をクリックしてJTexeAreaにコピーするなどをしたいため、できれば正規表現で―その先頭の半角スペースはコピーしないようにすれば問題ないかもですね。
でも、まだHTMLレンダラを無効にする方法を調べてみます。
回答日時 2013-01-31 11:12:02
名前
匿名
回答内容

回答を評価する
(0ポイント)
高木浩光@自宅の日記 - 久しぶりのSwing開発で躓いたところ
http://takagi-hiromitsu.jp/diary/20091219.html

TableCellRendererでセルの背景色を変更 - Java Swing Tips
http://terai.xrea.jp/Swing/StripeTable.html

を組み合わせて必要ないと思う部分を削除し、私がやりたいことに近づくよう修正して以下のようなプログラムを作ってみました。

package RendererTest;

import java.awt.Component;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableCellRenderer;

public class RendererTest extends JFrame {
    private final JTable table;
    public RendererTest() {
        super();
        table = new JTable(3,1);

        StripeTableRenderer renderer = new StripeTableRenderer();
        table.setDefaultRenderer(Object.class, renderer);

        table.setValueAt("<html>\n<head>\n<title></title>\n</head>\n<body>\n</body>\n</html>", 0, 0);
        table.setValueAt("<html>\n</html>", 1, 0);
        table.setValueAt("ai\nue", 2, 0);

        add(table);
    }

    public static void main(String[] args) {        RendererTest frame = new RendererTest();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(300,100);
        frame.setVisible(true);
    }
}

class StripeTableRenderer extends DefaultTableCellRenderer {
    @Override public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus,
            int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        putClientProperty("html.disable", Boolean.TRUE);
        return this;
    }
}

すると、タグもすべてそのまま表示されましたが、\nが表示されなくなってしまいました。
table.setDefaultRenderer(Object.class, renderer);
をコメントアウトしてみても変わりませんでした。
回答日時 2013-01-31 13:55:56
名前
匿名
回答内容

回答を評価する
(0ポイント)
例外解決方法:1行1処理化する

これで例外箇所の特定が容易になる。


\r \n が表示されないのは エスケープ文字だからで出力
するさいに \r を \\r に変換する必要がある。
回答日時 2013-01-31 17:59:20
名前
匿名
回答内容

回答を評価する
(0ポイント)
>\r \n が表示されないのは エスケープ文字だから

そうでしたね。
エラーが出ているときに表示されていたのは、HTMLレンダラーが利いていてjavaのエスケープシークエンスが無視されたからですね。
回答日時 2013-01-31 21:14:38
名前
匿名
回答内容

回答を評価する
(0ポイント)
やはり、EDTで実行していませんね。

><html>の前に半角スペースを入れてみました。
>すると、エラーが出ることなくきちんと表示すること
ができました。

小手先で対応するならば、それで良いかもしれません。

>まだHTMLレンダラを無効にする方法を調べてみます。

カスタマイズしていないJLabelでは、文字列については
一行のレンダリングにしか対応していません。
JLabelで複数行の文字列を描画するには、HTMLを使用す
るしかありません。

JLabelでHTMLでのレンダリングを無効にするには、現時
点では、putClientPropertyしか用意されていません。
そうでないならば、UIクラスを自作してJLabelにインス
トールするか、JLabelのpaint系メソッド(通常は
paintComponent)をオーバーライドして、自前で描画す
るしかありません。

何にこだわってJLabelを使おうとしているのか知りませ
んが、そもそもHTMLのレンダリングが不要ならば、
JTextArea(他のJTextComponentインスタンスでも構いま
せんが)をレンダリングコンポーネントにするだけで良
いんじゃないでしょうか。
回答日時 2013-01-31 23:43:35
名前
匿名
回答内容

回答を評価する
(0ポイント)
JTableで1つのセルに複数行文字を表示させたいつもりはありません。
以下のように複数行(シートによって行数が異なるので、タブによって行数は様々)2列で左側にタグ・右側にその説明をそれぞれ1行ずつ載せたタグ一覧を作りたいと思っています。
今のところ列タイトルはいらないと思っています。

-----------------------------------------
|<html>\n<head>\n<title> 以下略|基本タグ|
-----------------------------------------
|<html>\n</html>               |htmlタグ|
-----------------------------------------

そもそもJTableにこだわっているわけでもありません。
このような表示ができればListかなにかでもかまいません。
ですが、私の勝手な思い込みかもしれませんが、Listではこのように列を分けることはできない(VBAではできなかったので)と思っているので、表形式で表示ができるJTableを選びました。

この表形式表示ができたら、それをクリックしたらそのタグをテキストエリアのカーソル位置に挿入するというのをやりたいと思っています。
挿入したときに改行されるように、必要に応じてタグの間などに\nを記述しています。
そのテキストエリアの内容は任意でhtml形式(というか、ファイル保存のときに拡張子をhtmlにしただけ)で保存し、そのままwebページとして使えるようにするのが目的です。
回答日時 2013-02-02 19:25:57
名前
匿名
回答内容

回答を評価する
(0ポイント)
コンポーネントを2つ並べたコンポーネントを作り、それを縦に並べてテーブルを自前で作ることはできるね。
最下層のコンポーネントがJLabelなら結局同じことだが。
JTextFieldのreadonlyでもいいし。
回答日時 2013-02-02 21:48:32
名前
匿名
回答内容

回答を評価する
(0ポイント)
>そもそもJTableにこだわっているわけでもありませ
ん。
このような表示ができればListかなにかでもかまいませ
ん。
JTableでもJListでも、そういうことは可能です。
2013-02-02 21:48:32の方の回答のようにコンポーネン
トをグリッド状やリスト状に配置することでも実現可能
ですし、JComponentを継承した独自のコンポーネントを
作成することもできるでしょう。

いろいろな作成、表現方法があり、労力、自分の求める
UIデザイン、拡張性(後で列タイトルが必要になった場
合にすぐに対応できる)、メモリ効率等を考慮して、
JTableを選択するのは妥当かと思います。

それと、前から言っていますが、まずSwingをEDTで実行
してください。
スレッドの最低限の理解とSwingがシングルスレッド
(EDT)で実行されることを前提に設計されていることを
理解しなければいけません。

JLabelを使おうが使うまいが、SwingをEDTで実行するの
は必須です。SwingをEDTで実行しないならば、常に訳の
分からない例外が発生する可能性があり、それに悩まさ
れる危険性があることを認識すべきです。

EDTで実行すれば、putClientPropertyを実行したJLabel
で例外なんてスローされないと思いますよ?

EDTで実行しても例外がスローされるのであれば、スタ
ックトレースを遡ってソースコードを確認していけば原
因がわかるかもしれませんが、面倒であれば、2013-01-
31 23:43:35で書いたように、
TableCellRenderer#getTableCellRendererComponentの
戻り値でレンダラコンポーネントとしてJTextField(他
の任意のJTextComponentインスタンスでも構いま
せん)を返すようにTableCellRendererの実装を変更して
ください。
回答日時 2013-02-02 22:52:46
名前
匿名
回答内容

回答を評価する
(0ポイント)
2013-02-02 22:52:46の追記です。
「SwingをEDTで実行するのは必須」と書きましたが、
Swingコンポーネントに接続されていないモデルの処理
や、Swingコンポーネントに無関係の時間のかかる処理
等、すべてをEDTで実行しなければいけないという意味で
はありません。
それらの処理はむしろEDTと別スレッドで実行すべきで
す。
回答日時 2013-02-02 23:05:07
名前
匿名
回答内容

回答を評価する
(0ポイント)
EDTについてきちんと勉強していないままですいませんでした。
EventQueue.invokeLater
などの記述、サンプルで見かけてなんだろうと思いつつも使わなくても動くからいらないかななどという考えで勝手に消してしまっていました。
その時に調べもせずにいたのはよくなかったですね。

もっときちんとEDTについて勉強しなおしてきます。
回答日時 2013-02-03 22:22:45

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。



このページのトップへ
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道_CopyrightJavaの道