Top > Blog > Programming

JDialog のコーヒーカップアイコンを消す

今回珍しく Applet(Swing) + RMI の仕事でした。 Swing 自体は専門的によく知っているわけではないですが、 以前の仕事でも暗号化ツールを Swing で試作してみたりなど、 普段からよく使っているので何の抵抗もなく利用できました。 …なのですが、1つだけ「何でこうなってんの?」とつまったのが表題の件です。

例えば普通にダイアログを作成すると、下の図のようになります。

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;

public class DialogIconTest extends JFrame {

    static Font font = new Font("SansSerif", Font.PLAIN, 12);

    final JButton button;

    public void openDialog() {
        final JDialog dialog = new JDialog(this, "テスト用ダイアログ");
        Container pane = dialog.getContentPane();

        JLabel label = new JLabel();
        label.setText("テスト用のダイアログです。");
        label.setFont(font);
        label.setPreferredSize(new Dimension(240, 120));
        label.setHorizontalAlignment(SwingConstants.CENTER);
        pane.add(label);
        dialog.setBounds(14, 14, 240, 120);
        dialog.pack();
        dialog.setVisible(true);
    }

    public DialogIconTest() {
        super("テスト用JFrame");
        Container pane = getContentPane();

        // ダイアログを開くボタン
        button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                openDialog();
            }
        });
        button.setText("open dialog");
        button.setFont(font);
        pane.add(button);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setBounds(0, 0, 240, 120);
    }

    public static void main(String[] args) {
        try {
            UIManager
              .setLookAndFeel(
                "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (Exception e) {
            e.printStackTrace();
        }

        JFrame frame = new DialogIconTest();
        frame.setVisible(true);
    }
}

ダイアログのアイコンを消したかったので、少し調べてみたところ、こうすると消えました。

    ...(前略)...
    public void openDialog() {
        final JDialog dialog = new JDialog(this, "テスト用ダイアログ");
        Container pane = dialog.getContentPane();

        JLabel label = new JLabel();
        label.setText("テスト用のダイアログです。");
        label.setFont(font);
        label.setPreferredSize(new Dimension(240, 120));
        label.setHorizontalAlignment(SwingConstants.CENTER);
        pane.add(label);
        
        dialog.setResizable(false); // ←ここ
        
        dialog.setBounds(14, 14, 240, 120);
        dialog.pack();
        dialog.setVisible(true);
    }
    ...(後略)...

アイコンは消えるのですが…かなり疑問のある動作です。 あくまで「サイズ変更不可にする」と指定しているのに、 アイコンまで消えてしまう…。

Sun Microsystems の Bug Parade を閲覧すると、やはり同じように 「こんな副作用的な動作は変なんじゃないの?」 と指摘している人がいました。私もそう思うのですが、このようになっている理由は「 Windows では “resizable dialogs have an icon, not-resizable dialogs don’t” と推奨してあるから」だそうです。

たしかに他のプラットフォームと比べてみても、ウィンドウのタイトルバーにアイコンを表示するのは Windows だけなんですね。しかしだからと言って

  • デフォルトのアイコンイメージが Java Cup になっている
  • あえてアイコン指定を null にすると、やはり Java Cup になる
  • Windows だけしか使わないような API は用意しない
というのもおかしいなぁ、と思うのですが、どうなんでしょうね? 改善される見込みはあるのでしょうか…?(議論の結論がどうなっているのか、把握してません)

ちなみに上述の Forum では 「アイコンは消したくないけど、サイズ変更不可にしたい!」 という投稿もあって、それにはこうしなさいと回答がありました。

    dialog.addComponentListener(new ComponentAdapter() {
        public void componentResized(ComponentEvent e) {
            dialog.pack();
        }
    });

動かしてみるとサイズ変更は出来るものの、マウスを放したとたんに元の大きさに戻る…という感じです。 結果的にサイズ変更は出来ませんが、あまり根本的な解決策ではないですね。 やはりこういう問題が出てくること自体が問題だと思います。

コメントの投稿