覆盖JButton中的paintComponent()会产生意外结果

时间:2017-07-30 20:45:54

标签: java swing graphics awt chess

我从来没有用简单的GUI编写程序,所以我已经开始编写国际象棋应用程序的个人项目。

我在这个项目中的目标之一是让电路板重新调整以适应窗口,我设法做到这一点没有太多麻烦。但是,在这个过程中我遇到了一个问题,即我的作品(在JButtons上表示为图标)没有与其余的棋盘重新缩放。

我决定用Image类代表它们,并创建了一个名为ScalingJButton的自定义类,它覆盖了paintComponent。对于the last piece to be drawn来说,这实际上非常有效。其余部分未绘制,因此程序被破坏。这是我的ScalingJButton类:

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的类,这是它的构造函数)。

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();
}}

我已经做了大量的调试,但大部分都没有领先。有一点需要注意的是&#34;图像&#34; ScalingJButton中的变量在调用drawImage时保持正确的图片,因此不是问题。另一个有趣的观点是,其中包含片段的正方形是要绘制的最后一个正方形,并且根据我向棋盘添加正方形的顺序,将绘制不同的棋子(因此加载棋子没有问题)。

奇怪的是,如果我在paintComponent中使用super,那么当我将鼠标滑过它们时,将鼠标滚动到绘制的部分上会导致其他正方形填充该部分。

我完全迷失了,不知道该怎么做,所以非常感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

首先,您需要保留super.paintComponent(g);行。如果不这样做,工件将在看似随机的时间出现。

其次,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);
}

答案 1 :(得分:0)

  

然而,在这个过程中,我遇到的问题是我的作品(在JButtons上表示为图标)没有重新缩放

Stretch Icon可能是一个更简单的解决方案。您可以在任何可以显示图标的组件上使用此图标。图像将动态更改大小以填充图标可用的空间。

答案 2 :(得分:0)

您的代码中有两条可疑行。第一个是

frame.add(container);

此行将您的Swing元素添加到AWT容器中。相反,你应该用

替换它
frame.setContentPane(container);

第二行是方法

public void paintComponent(Graphics g) {

尝试用

替换它
public void paint(Graphics g) {

希望这有帮助。

编辑:

同时更改此

    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);
    }
}

您的图片只是在网格之外。