2017-07-30 20 views
0

私はベアボーンGUI以外のプログラムを書いたことがないので、私はチェスアプリケーションを書くための個人的なプロジェクトに着手しました。JButtonのpaintComponent()をオーバーライドすると予期しない結果が発生する

このプロジェクトの私の目標の1つは、ボードをウィンドウに合わせてリサイズすることでしたが、これはあまり問題なく処理できました。しかし、このプロセスでは、私の作品(JButtons上のアイコンとして表されていた)がボードの残りの部分で再スケールされなかったという問題が発生しました。

代わりにImageクラスで表現することにし、paintComponentをオーバーロードするScalingJButtonというカスタムクラスを作成しました。これは実際にはかなりうまくいった... the last piece to be drawn。残りの部分は描画されず、結果としてプログラムが壊れてしまいます。

public class ScalingJButton extends JButton{ 
private Image image; 

ScalingJButton(){ 
    this.image = null; 
} 

ScalingJButton (Image image){ 
    this.image = image; 
} 

public void setImage(Image image){ 
    this.image = image; 
} 

public Image getImage(){ 
    return image; 
} 

@Override 
public void paintComponent(Graphics g){ 
    //super.paintComponent(g); 
    int x = getX(); 
    int y = getY(); 
    int width = getWidth(); 
    int height = getHeight(); 
    if (image != null) { 
     g.drawImage(image, x, y, width, height, this); 
    } 

}} 

また、ここではScalingJButtonsをインスタンス化するための責任のコードは(VisualBoardはJPanelのを拡張するクラスであり、これはコンストラクタである)である。ここに私のScalingJButtonクラスです。レイアウトは、関連するかもしれないので

public VisualBoard(){ 
    white = Color.WHITE; 
    black = Color.GRAY; 
    loadPieceImages(); 
    setLayout(new GridLayout(8, 8)); 
    for (int i = 0; i < 8; i++){ 
     for (int j = 0; j < 8; j++){ 
      squares[i][j] = new ScalingJButton(); 
      if ((i + j) % 2 != 0) { 
       squares[i][j].setBackground(white); 
      } 
      else{ 
       squares[i][j].setBackground(black); 
      } 
      add(squares[i][j]); 
     } 
    } 
    initializeStandardBoard(); 
} 

は最後に、ここではボードのオートスケールを行うコードは次のとおりです。

public class Chess { 
public static void main (String[] args){ 
    final VisualBoard board = new VisualBoard(); 

    final JPanel container = new JPanel(new GridBagLayout()); 
    container.add(board); 
    container.addComponentListener(new ComponentAdapter() { 
     @Override 
     public void componentResized(ComponentEvent e) { 
      drawResizedBoard(board, container); 
     } 
    }); 

    JFrame frame = new JFrame("Chess"); 
    frame.setSize(1000,1000); 
    frame.add(container); 
    frame.setLocationRelativeTo(null); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setVisible(true); 

} 

private static void drawResizedBoard(JPanel innerPanel, JPanel container) { 
    int w = (int)Math.round(container.getWidth()*0.9); 
    int h = (int)Math.round(container.getHeight()*0.9); 
    int size = Math.min(w, h); 
    innerPanel.setPreferredSize(new Dimension(size, size)); 
    container.revalidate(); 
}} 

私は大規模なデバッグを行っているが、それのほとんどはどこにもつながりません。注目すべきは、drawImageが呼び出されたときに、ScalingJButtonの "image"変数が正しい画像を保持していることです。別の興味深い点は、その中にあるピースの四角形が描かれる最後の四角形であり、どのような順番でボードに四角形を追加するかによって、異なるピースが描画されることです(ピースの読み込みに問題はありません)。

奇妙なことに、私がpaintComponentのsuperを使わないと、描画された部分の上にマウスを置くと、マウスの上にマウスを置くと、他の四角がその部分で塗りつぶされます。

私は完全に迷っていて、何をすべきかわからないので、どんな助けでも大歓迎です!

答えて

1

まず、super.paintComponent(g);の行を維持する必要があります。そうしないと、アーティファクトが一見無作為に表示されます。

第2に、getX()およびgetY()は親のコンポーネントの位置に戻ります。ペイントするとき、0,0がコンポーネントの左上隅である座標系が与えられます。したがって、getX()とgetY()は無視してください。

最も簡単な選択肢は、ボタンの左上隅を使用することです:あなたは、ボタンの境界線を考慮してよいでしょう

int x = 0; 
int y = 0; 

if (image != null) { 
    Rectangle inner = SwingUtilities.calculateInnerArea(this, null); 
    g.drawImage(image, inner.x, inner.y, inner.width, inner.height, this); 
} 

そして、あなたはボタンがしたい場合は実際には通常のボタンのように見えますが、マージンも考慮に入れることができます:

if (image != null) { 
    Rectangle inner = SwingUtilities.calculateInnerArea(this, null); 

    Insets margin = getMargin(); 
    inner.x += margin.left; 
    inner.y += margin.top; 
    inner.width -= (margin.left + margin.right); 
    inner.height -= (margin.top + margin.bottom); 

    g.drawImage(image, inner.x, inner.y, inner.width, inner.height, this); 
} 
+0

ありがとうございました!私はすでにStretchIconを使用することに自信していましたが(確かに悪い考えではありません)、あなたの投稿を読んだ後、私は自分のカスタムクラスに戻り、それがうまくいくことを発見しました。私は、g.drawImage()が右上隅を基準にしてScalingJButtonの位置から描画すると仮定しましたが、実際にはScalingJButton自体を基準に描画していました。そのような愚かな誤解の上で悲しんでいるすべてのこと! – TheRussianPatzer

0

しかし、その過程で私は(JButtonが上にアイコンとして表された)私の作品が

Stretch Iconは簡単な解決策かもしれ再スケールなかったことが問題に遭遇しました。このアイコンは、アイコンを表示できるすべてのコンポーネントで使用できます。イメージはアイコンに使用できるスペースを満たすためにサイズを動的に変更します。

+0

ありがとうございます。私は私の研究でストレッチアイコンを見つけました。この問題がなくならないので、私はそのルートに行くかもしれません。しかし、私はまだ何も他の何もない場合は、この問題の原因となっていることを将来の参照のために知りたいです。 – TheRussianPatzer

0

コードには2つの疑わしい行があります。最初のものは

frame.add(container); 

です。この行は、Swing要素をAWTコンテナに追加します。代わりに、あなたは

frame.setContentPane(container); 

と二行目にそれを置き換える必要があります方法

public void paintComponent(Graphics g) { 

は、このことができます

public void paint(Graphics g) { 

希望とそれを交換してみてくださいされています。

EDIT:

また、この

g.drawImage(image, x, y, width, height, this); 

public void paint(Graphics g) { 
    super.paint(g); 
    int width = getWidth(); 
    int height = getHeight(); 
    if (image != null) { 
     g.drawImage(image, 0, 0, width, height, this); 
    } 
} 

にあなたのイメージだけでグリッドの外であったに変更します。

+0

私はこれらの提案を試してみましたが、どちらもうまくいきませんでした。私の推測では、この問題は、Graphics.drawImage()が特定のレイアウトに関してどのように動作するかに関連していると思いますが、私はこれを完全に新しくしています。 – TheRussianPatzer

+0

私はあなたのコードで少し演奏しました。私の「拡張」答えを見てください。 –

+0

ありがとうございます。これにより、問題は直ちに解決されました!私はこれを考えていないのは本当に馬鹿だと感じています。 – TheRussianPatzer

関連する問題