- PR -

JComboBox の GlassPane 上でのレンダリング

投稿者投稿内容
わたなべ
大ベテラン
会議室デビュー日: 2007/12/09
投稿数: 123
お住まい・勤務地: 札幌
投稿日時: 2007-12-09 11:51
Java6 を用いてSwingアプリケーションを作成しています。
その中でGlassPane上にカスタムコンポーネントを配置し、その上にJPanelを用いた画面を作成しています。
作成しているイメージはこちらを参照(http://www.curious-creature.org/2007/08/01/blurred-background-for-dialogs-extreme-gui-makeover-2007/)。
概ね問題なく動作しているのですが、JComboBoxにて不具合が発生しており、調査はしたのですが解決策が見つからないので質問です。

コードに関しては、上記リンク先とほぼ同じようなコードで構成されており、表示するコンポーネントにはJComboBoxが含まれます。
この時、JComboBoxのプルダウンメニューが表示されなくなりました。
原因を調査していくと、JComboBoxのLightWeightPopupEnabledプロパティをfalseにする事で改善しました。
重量コンポーネントと明示する事で一覧は表示されるようになるのです。
しかし、選択状態を変更しようとしても、コンボボックスのスクロールバーをクリックしても描画されません。

さらに調査をしていくと、DefaultCellRendererのrepaint等が1.5でパフォーマンス改善の為、オーバーライドされていました。
この辺りが怪しいと踏んでいるのですが、解決策が見つかりません。
DefaultCellRendererを書き直して見たのですが、JLabelのrepaintを呼んでも再描画されない・・・。

こんな所ではまっています。
何か関連情報やヒントなどがあればご教授願います。
a-san
ベテラン
会議室デビュー日: 2004/06/01
投稿数: 53
投稿日時: 2007-12-09 23:38
よくわからないです。
Java6の不具合でしょうか?それとも作り方が悪いため?
GlassPaneって、JFrameとかのGlassPaneのことですか?
>さらに調査をしていくと、DefaultCellRendererのrepaint等が1.5でパフォーマンス改善の為、オーバーライドされていました。
>この辺りが怪しいと踏んでいるのですが、解決策が見つかりません。
1.4以前では正しく動くのでしょうか?
再現するコードと、再現させるまでの操作手順をUPしてもらえませんか?
わたなべ
大ベテラン
会議室デビュー日: 2007/12/09
投稿数: 123
お住まい・勤務地: 札幌
投稿日時: 2007-12-10 01:28
返信有難うございます。
不具合なのか作り方が悪いのかはわからないので質問してます。

環境は書いたとおりJava6です。
1.4以前のJREは現在、手元にない為に試しておりません。

必要最低限のコードを示します。
再現手順は・・・mainに貼り付けて実行し、コンボボックスを選択してください。
さらにsetLightWeightPopupEnabledの行をコメントアウトしてみてください。
コード:
        JFrame frame = new JFrame();
        frame.setSize(200, 200);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        JPanel panel = new JPanel();
        JComboBox comboBox = new JComboBox(new String[]{"A", "B", "C"});
        comboBox.setLightWeightPopupEnabled(false); // 重量Component化?すると表示はされる
        panel.add(comboBox);
        frame.getRootPane().setGlassPane(panel);
        panel.setVisible(true);


ranco
大ベテラン
会議室デビュー日: 2007/11/02
投稿数: 112
投稿日時: 2007-12-10 15:04
> 選択状態を変更しようとしても、コンボボックスのスクロールバーをクリックしても描画されません。
投稿されたテストコードで、私の環境では、選択状態の変更はふつうにできます。JPanelをsetせず、デフォルトのglass paneをContainerにキャスとしてコンボボックスをaddしても、選択変更は正常にできます。
[私の環境]
[~]# java -version
java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b05)
Java HotSpot(TM) Client VM (build 1.6.0_02-b05, mixed mode, sharing)
まさ
ベテラン
会議室デビュー日: 2002/11/15
投稿数: 74
投稿日時: 2007-12-10 22:48
現象、再現しましたよ。

java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

JRE のバグかもしれませんね。
アップデートしてみては?
a-san
ベテラン
会議室デビュー日: 2004/06/01
投稿数: 53
投稿日時: 2007-12-10 22:56
私も再現しました。
java version "1.4.2_02"
java version "1.5.0_03" どちらも同じです。
ただし、ソースを以下のように変更したら起こらなくなりました。試してみてください。
コード:
import javax.swing.*;

class JComboBoxTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(200, 200);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
//      JPanel panel = new JPanel();
        JPanel panel = (JPanel) frame.getRootPane().getGlassPane();
        JComboBox comboBox = new JComboBox(new String[]{"A", "B", "C"});
//      comboBox.setLightWeightPopupEnabled(false); // 重量Component化?すると表示はされる
        panel.add(comboBox);
//      frame.getRootPane().setGlassPane(panel);
        panel.setVisible(true);
    }
}


ところで、なぜGlassPaneに配置するのでしょうか?
通常は、ContentPaneの方に配置するのですが。
nekoyama
ベテラン
会議室デビュー日: 2005/03/12
投稿数: 71
投稿日時: 2007-12-11 00:02
以下のコードで多分大丈夫だと思います。
コード:
        JFrame frame = new JFrame();
        frame.setSize(200, 200);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        JPanel panel = new JPanel();
        panel.setOpaque(false);//ココ
        /*
        これは任意
        java.awt.Component oldGlassPane = frame.getRootPane().getGlassPane();
        oldGlassPane.setVisible(false);
        */
        JComboBox comboBox = new JComboBox(new String[]{"A", "B", "C"});
        //comboBox.setLightWeightPopupEnabled(false); // 重量Component化?すると表示はされる
        panel.add(comboBox);
        frame.getRootPane().setGlassPane(panel);
        panel.setVisible(true);


nekoyama
ベテラン
会議室デビュー日: 2005/03/12
投稿数: 71
投稿日時: 2007-12-11 00:27
ついでに概略だけですが。
引用:

DefaultCellRendererのrepaint等が1.5でパフォーマンス改善の為、オーバーライドされていました。
この辺りが怪しいと踏んでいるのですが、解決策が見つかりません。
DefaultCellRendererを書き直して見たのですが、JLabelのrepaintを呼んでも再描画されない・・・。


DefaultCellRendererのperformance reasonでオーバーライドされている理由は、
DefaultCellRendererをRendererに特化して使用するため、該当するメソッドが呼び出される可能性があるものの、Rendererとして考えたときに処理が不要なため処理をしない、または最小限のオーバーヘッドに抑えるためにオーバーライドされています。

素早くレンダリングしたい場合は、独自のレンダラクラスを実装した方が良いですが、
デフォルトで用意されているクラス(DefaultCellRenderer)を利用するのであれば、
DefaultCellRendererのメソッドのオーバーライドはJTableやJTree等で大量のデータを、
できる限り早くレンダリングする場合、特に重要です。

ということで、DefaultCellRendererのrepaint()を実行しようとすること自体が誤りです。RendererはRendererとして考える必要があります。

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