2

さて、ここでまた行きます。

paintComponent()JPanelに背景画像を提供するために、カスタムbufferedImageをオーバーライドして描画したJPanelがあります。カスタム形状のボタンを作成するために、同じことを行ったJButtonもあります。問題は、JButtonが背景画像とともにJPanelに適切に追加されているように見えても、適切に描画されていないことです。

ボタンから実際に存在するかのように入力を取得できますが、標準のJPanelでは表示されますが、実際には表示されません。例を以下に示します。

助けてくれてありがとう。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Test {
    public static void main (String[] args){
        final JFrame frame = new JFrame();
        DrawPanel panel1 = new DrawPanel(createBufferedImage("background.png"));
        JPanel panel2 = new JPanel();

        DrawButton button1 = new DrawButton(createBufferedImage("button.png"));
        button1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                JOptionPane.showMessageDialog(frame, "input detected, button1");
            }
        });

        DrawButton button2 = new DrawButton(createBufferedImage("button.png"));
        button2.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                JOptionPane.showMessageDialog(frame, "input detected, button2");
            }
        });

        panel1.add(button1);
        panel2.add(button2);
        frame.getContentPane().add(panel1, BorderLayout.NORTH);
        frame.getContentPane().add(panel2, BorderLayout.CENTER);
        frame.validate();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    protected static BufferedImage createBufferedImage(String path){
        File img = new File(path);
        BufferedImage bi = null;
        try{
            bi = ImageIO.read(img);
        }
        catch (IOException ioe){
            throw new RuntimeException();
        }
        BufferedImage newImage = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = newImage.createGraphics();
        g2d.drawImage(bi, 0, 0, null);
        g2d.dispose();  
        return newImage;
    }
}

class DrawPanel extends JPanel{

    private BufferedImage bg; 

    public DrawPanel(BufferedImage bg){
        this.bg = bg;
        new JPanel();
        setPreferredSize(new Dimension(bg.getWidth(), bg.getHeight()));
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(bg, 0, 0, null);
        g.dispose();
    }
}

class DrawButton extends JButton{

    private BufferedImage bi;

    public DrawButton(BufferedImage bi){
        setPreferredSize(new Dimension(bi.getWidth(), bi.getHeight()));
        this.bi = (BufferedImage) bi;
        setContentAreaFilled(false);
    }

    @Override
    public Dimension getPreferredSize(){
        return new Dimension(bi.getWidth(), bi.getHeight());
    }

    public BufferedImage getIconImage(){
        return bi;
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(bi, 0, 0, null);
        g.dispose();
    }
}
4

1 に答える 1

4

JVMから提供されたGraphicsオブジェクトに対してdisposeを呼び出さないでください。自分で作成した、Graphicsオブジェクトに対してのみ呼び出してください。

だからこれはOKです:

    BufferedImage newImage = new BufferedImage(bi.getWidth(), bi.getHeight(), 
         BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = newImage.createGraphics();
    g2d.drawImage(bi, 0, 0, null);
    g2d.dispose();

しかし、これはそうではありません:

protected void paintComponent(Graphics g){
    super.paintComponent(g);
    g.drawImage(bg, 0, 0, null);
    g.dispose();
}

JVMは、コンテナの子コンポーネントの描画を含むさらなる描画のためにそのオブジェクトを使用する必要がある場合があります(おそらくそうなるでしょう)。それを破棄すると、これが発生するのを防ぐことができます。

別の提案:setPreferredSizeではなく、getPreferredSizeをオーバーライドすることを検討してください。だからこれではなく:

setPreferredSize(new Dimension(bg.getWidth(), bg.getHeight()));

検討:

@Override
public Dimension getPreferredSize() {
  if (bg == null) {
    return super.getPreferredSize();
  } else {
    return new Dimension(bg.getWidth(), bg.getHeight());
  }
}

このようにして、コンポーネントの優先サイズが確実に設定され、コンポーネントのユーザーはそれを変更できません。

于 2012-12-12T02:31:33.970 に答える