アプリ版:「スタンプのみでお礼する」機能のリリースについて

ContainerにJPanelをaddし、ボタンを押すことで現在addされているJPanelとは違うJPanelを生成し、再描画させようとしているのですが、うまくいかないため、質問致しました。

-- src ---
public class Test extends JFrame implements ActionListener {
  Container container;
  JPanel panel;
  JButton btn;
  
  public Test() {
    container = getContentPane();
    container.setLayout(new BorderLayout());

    // ボタン用パネル
    JPanel btnp = new JPanel();
    btnp.setLayout(new FlowLayout());
    container.add(btnp, BorderLayout.NORTH);
    
    btn = new JButton("aaa");
    btn.addActionListener(this);
    btnp.add(btn);
    
    // 対象のパネル
    panel = new JPanel();
      (略)panelの設定
    container.add(panel, BorderLayout.CENTER);

    setVisible(true);
    setBounds(50, 50, 300, 300);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }
  
  public void actionPerformed(ActionEvent e) {
    if (e.getSource() == btn) {
      container.remove(1);
      panel = new JPanel();  // 本来はJPanelを継承したクラスをnewしています
      container .add(panel);
      repaint();       // ※
    }
  }
  
  public static void main(String args[]) {
    Test t = new Test();
  }
}

※の箇所をcontainer.repaint() にしたり、paintImmediaely() にしたり出来そうな事を色々試したつもりではいるのですが、うまくいきません…

ボタン押下後に、ウィンドウの枠をクリックすると描画されるのですが、いまいちよくわかりません…

なにか分かる方いらっしゃいましたらご教授願います。

A 回答 (4件)

ページ遷移とやりかたとして2つの方法があります。


・ページ遷移の際に次のページを追加して、今のページを削除する
常に一枚のパネルしか乗っていないので処理が軽いです。
その代わり、遷移の速度が遅くなります。
なので、パネルの枚数が多いときに向いていますね。

・あらかじめ全てのページを追加しておいてページ遷移の際に切り替える
パネルの遷移速度が速いです。
ですが、乗っているパネルの枚数から当然前者よりは重くなります。
パネルが少なければ気にならない程度ですが、多くなりすぎるとアプリケーション自体が重くなることもあります。
パネル総数が少ないときに実装するとより効率的になります。

今回のプログラムはパネルが2枚と少ないので後者のほうがよいといえます。

rancoさんの言うとおり作るものに適した実装のしかたをしましょう。
まずはレイアウトの種類と特徴,AWTとSwingの違いなどを勉強なさると良いでしょう。
他にも、類似的な機能の一長一短といったことも把握した上で考えるといい設計ができると思いますよ。
    • good
    • 0
この回答へのお礼

zozyさん、再度ご回答ありがとうございます。

なるほどです。
おっしゃっていただいたことを今後GUIプログラムを組むときに参考にさせていただこうと思います!

AWTとSwingの違いというところも今まであまり意識したことが無かったので、ちょっと調べようかと思います…

ありがとうございました。

お礼日時:2009/01/02 20:03

z...さんも言うように、アプリケーションレベルの要求を具体的に説明すべきです。



いちいちremove - new - addするのが、その要求の最適の実装ならば、JFrameのcontentPaneはデフォルトではJPanelなので、JPanelにキャストできます。そしてJPanelに限らず、Swingのコンテナは、なにかがaddされたあと、invalidate/validateではなく、単純にrevalidateだけをコールします。

参考URL:http://homepage1.nifty.com/algafield/JavaGUIFaq1 …
    • good
    • 2
この回答へのお礼

_ranco_さん、ご回答ありがとうございます。

何をするアプリケーションを作りたいのか?ということを説明すべきということですよね…失礼致しました。

「どれがいいか」というよりも、最適なものを選んで実装するということですね。

revalidate() は試してみたところ、すぐに再描画することができました。
ありがとうございました。

お礼日時:2009/01/02 19:43

逆に質問があるのですが、なんのためにパネルを新しく生成するのですか?



この場合はボーダーレイアウトではなく、カードレイアウトを適応するのが上策と適切だと思います。
いちいち生成して前のパネルを削除していくのでは効率が悪いです。
カードレイアウトとはあらかじめコンテナにパネルを追加しておき、必要に応じてパネルを表示するレイアウトです。
コンテナまたはフレームがプレイヤー,パネルがカードでプレイヤーがカードを選択するのをイメージしてもらえるとわかりやすいでしょう。

サンプルとして、ページ切り替えのたびpanelのバックカラーを変更するものを作りましたので参考にしていただけると幸いです。

//インポートを1つずつ宣言しているのはメモリ節約のため
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Test2 extends JFrame{
//カードレイアウトの宣言
CardLayout layout=new CardLayout();
JPanel panel=new JPanel();
JPanel btnp=new JPanel();
JButton btn=new JButton("再描画");
JButton back=new JButton("戻る");
//乱数の宣言
Random r=new Random();
//panelのバックカラー
int red,green,blue;
public Test2(){
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//親フレームをカードレイアウトに設定
getContentPane().setLayout(layout);
//btnにリスナを追加し、カプセル化してます。
//明示的にリスナを区別するため、バグが発生しにくくなる
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt){
btnPush(evt);
}
});
back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt){
backPush(evt);
}
});
//btnpのレイアウトをグループレイアウトに設定
//グループレイアウトとはコンポーネントを自由配置できるレイアウトです
//階層型のため複雑になるので注意
GroupLayout btnpLayout=new GroupLayout(btnp);
btnp.setLayout(btnpLayout);
//水平方向の配置を設定してます
btnpLayout.setHorizontalGroup(
//左上からコンポーネントを配置します
btnpLayout.createParallelGroup()
//引数はそれぞれ,配置するコンポーネント,最小サイズ,実際のサイズ,最大サイズ
.addComponent(btn,0,300,300)
);
//垂直方向の配置を設定してます
btnpLayout.setVerticalGroup(
btnpLayout.createParallelGroup()
.addGroup(btnpLayout.createSequentialGroup()
.addGap(250,250,250)
.addComponent(btn))
);
//addの2個目の引数はカード名といい、ページ切り替えの際指定する文字列です
getContentPane().add(btnp,"btnp");
GroupLayout panelLayout=new GroupLayout(panel);
panel.setLayout(panelLayout);
panelLayout.setHorizontalGroup(
panelLayout.createParallelGroup()
.addComponent(back,0,300,300)
);
panelLayout.setVerticalGroup(
panelLayout.createParallelGroup()
.addGroup(panelLayout.createSequentialGroup()
.addGap(250,250,250)
.addComponent(back))
);
getContentPane().add(panel,"panel");
//追加したコンポーネントをみてウィンドウを推奨サイズに設定してくれます
pack();
}
private void btnPush(java.awt.event.ActionEvent evt){
red=r.nextInt(256);
green=r.nextInt(256);
blue=r.nextInt(256);
panel.setBackground(new Color(red,green,blue));
layout.show(getContentPane(),"panel");
}
private void backPush(java.awt.event.ActionEvent evt){
layout.show(getContentPane(),"btnp");
}
public static void main(String args[]) {
new Test2().setVisible(true);
}
}
    • good
    • 0
この回答へのお礼

zozyさん、ご回答ありがとうございます。

カードレイアウトを一度試したのですがうまくいかなかったので今のような手段をとってしまったのですが…(恐らく私のコードがどっか間違っていたのでしょうが…)

やはりカードレイアウトの方が効率がいいのでしょうか…?

お礼日時:2009/01/02 18:11

ここは



repaint();

ではなくて

invalidate();
validate();

すべきところですね。

あるいは

container.invalidate();
container.validate();

の方が多少効率がいいかもしれません。
    • good
    • 0
この回答へのお礼

ansariga10さん、ご回答ありがとうございます。

invalidate() と validate() をしてみたところ、すぐに再描画されました。
ありがとうございました。

お礼日時:2009/01/02 17:27

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています