我从来没有编写过一个仅具有裸露GUI的程序,所以我承担了一个个人项目来编写国际象棋应用程序。

我在该项目中的目标之一是使电路板重新调整以适应窗口大小,而我做到了这一点而没有太多麻烦。但是,在此过程中,我遇到了一个问题,即我的作品(在JButtons上用Icons表示)没有随董事会的其他部分重新缩放。

我决定用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();
}}


我已经进行了广泛的调试,但是大多数调试都无济于事。要注意的一件事是,在调用drawImage时,ScalingJButton中的“ image”变量可保存正确的图片,所以这不是问题。另一个有趣的一点是,其中包含棋子的正方形是要绘制的最后一个正方形,根据我向棋盘添加正方形的顺序,将绘制不同的棋子(因此不会出现加载棋子的问题)。

奇怪的是,如果我取消了paintComponent中的super,则将鼠标滚动到绘制的块上会导致其他正方形在将鼠标移到绘制的块上时被该块填充。

我完全迷路了,不知道该怎么办,所以任何帮助将不胜感激!

最佳答案

首先,您需要保留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);
}

07-24 20:31