質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.93%

javaのSwingにて背景に画像を表示したいがされない問題

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,813

tarutarupop

score 16

前提・実現したいこと

javaのswingでGUIについて勉強しています。今、背景に画像を使ったパネルを作り、さらにその上に一回り小さいデフォルトのパネルを作成して表示したいと考えています。

発生している問題・エラーメッセージ

エラーメッセージはでていませんが、Mainクラスを実行すると大小二つのタブが生成されます。どちらも何も表示されていません。

該当のソースコード

package スタート画面;

import java.io.IOException;

import javax.swing.JFrame;

public class Main extends JFrame {

    public Main(){
        super("test");
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
    public static void main(String[] args) throws IOException {
        Main main = new Main();
        StartScreen jp = new StartScreen();
        main.getContentPane().add(jp);

    }
}
package スタート画面;

//import java.awt.CardLayout;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class StartScreen extends JPanel {
    private ImageIcon img;
    //private CardLayout layout = new CardLayout();
    private JPanel mainpane;

    public StartScreen() throws IOException {
        //背景
        BufferedImage img;
        try {
              img = ImageIO.read(new File("p0131_l.jpg"));
            } catch (Exception e) {
              e.printStackTrace();
              img = null;
            }
        //img = new ImageIcon("p0131_l.jpg");
        ImagePanel backpane = new ImagePanel(img);
        backpane.setVisible(true);

        //メインパネル
        mainpane = new JPanel();
        mainpane.setLayout(null);
        mainpane.setBounds(400, 400, 900, 500);
        mainpane.setVisible(true);
        backpane.add(mainpane);
    }
}
package スタート画面;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JPanel;

public class ImagePanel extends JPanel{
    private BufferedImage image;
    /*
     * コンストラクタ引用(Java Swing Hacks,Joshua Marinacci著)
    */
    public ImagePanel(BUfferedImage image){
        this.image = image;
        Dimension size = new Dimension(image.getWidth(null),image.getHeight(null));
        setPreferredSize(size);
        setMaximumSize(size);
        setMinimumSize(size);
        setLayout(null);
    }
    public void paintComponent(Graphics g){
        g.drawImage(image, 0, 0, null);
    }
}


StartScreenのフィールドでカードレイアウトがインスタンス化されてるのはいずれデフォルトのパネルに適応しパネルを追加して画面遷移を行いたいと考えているからです。

補足情報(言語/FW/ツール等のバージョンなど)

作業環境はEclipseです。画像はインポートで取り込み同じプロジェクトファイル内にあります。画像の大きさは1200×1035です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

なんというか、いろいろと不可解なコードです。(修正確認しました)

  • 命名がおかしい
    MainとImagePanelがJFrame?SmartScreenがJPanel?
  • 画像の取り扱いがおかしい
    1200x1035の画像はアイコンとは呼べないと思います。
    また、どうしてJFrameにべた張りしようとしているのでしょうか。
  • コンポーネントの自己主張が激しい
    特にSmartScreen。自身をaddする前にsetVisible(true)にしてしまっています。
    あとMainのコンストラクタは完全に無駄だと思います。
  • setLayout(null)
    せっかくlayout用意したのに使わないんですか?

もっと簡潔に書けるはずです。
重複して書いているからフレームも二つ出て、処理の順序が前後しているからまっしろです。

追記

デバッグしてみましたが、それなりの量書き換える必要がありました。
要点は次のとおりです。

  • pack()とsetVisible(true)の呼ばれるタイミングを適切にする
    これらのメソッドはその性格上、コンポーネントの配置がすべて終わった時に呼ばれるべきです。
  • SmartScreenがパネルとして機能していない
    フィールドのmainpaneに対して操作をしているので、SmartScreenのインスタンスjpは真っ白です。
  • パネルの親子関係に意識を向ける
    下記のコードを見る限り、mainpaneはbackpaneの子なのですよね?
backpane.add(mainpane);

メインとなるフレームから子を直接呼び出すのはおかしな設計です。

  • フレームに与えるのは親のパネル
    直前の項と重複しますが、子をaddしてどうするんです?
StartScreen jp = new StartScreen();
main.getContentPane().add(jp);
  • 必要のないsetVisibleを削る
    しっかりとGUIを組めていれば、フレームを可視化すればそれで充分です。

設計的に改善するとしたら、次のどっちかですかね。

  • MainクラスからImagePanelを呼び出し、ImagePanelからStartPanelを呼び出す。
  • Mainクラスから両方を呼び出し、ImagePanelに子としてStartScreenを与える。

後者の方が柔軟な気もします。どんな機能を組み込むかにもよりますが。
ともかく、インタフェースを意識して作る必要はあるでしょう。

不明な点がありましたらコメントにてお知らせ下さい。
コードを見せちゃった方が早いんですが、質問者様のデバッグの機会を奪いたくないので。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/28 05:15

    処理の順序について教えてもらってもいいでしょうか?

    キャンセル

  • 2017/07/28 12:05

    追記しました。setVisibleやpackを呼び出す順序を特に気にしてください。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる