所以,我有一个Square类的多个对象,它是JButton的子类。我有一个类Board的实例,其中包含一些Square实例。我想要做的是当我按下其中一个按钮(正方形),在它上面画一个形状(一个圆圈)。为此,我在Square类中有一个布尔变量,即isClicked,它基本上决定了paintComponent方法中必须绘制的内容。
问题是,当我有几个按钮时,按钮开始以奇怪的方式运行。令人惊讶的是,如果只有其中一个,则完全没有问题。起初,我原以为问题可能与线程有关,但是,我把主代码放到invokeLater方法中,这根本没用。
我看到了一个使用BufferedImage的解决方案,但我想看看是否有可能以我的方式解决问题。
抱歉可能不是完美的英语。
Square class:
public class Square extends JButton implements ActionListener {
private int number;
private boolean isClicked;
public Square(int x) {
number = x;
isClicked = false;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
if (!isClicked) {
super.paintComponent(g);
} else {
System.out.println("EXECUTED for: " + number);
g2d.drawOval(this.getX(), this.getY(), 100, 100);
}
}
@Override
public void actionPerformed(ActionEvent e) {
isClicked = !isClicked;
System.out.println(isClicked + " " + number);
repaint();
}
}
董事会成员:
public class Board extends JPanel {
private static final int BOARD_WIDTH = (int) (TicTacToe.WIDTH * 0.7);
private static final int VERTICAL_LINE_LENGTH = (int) (TicTacToe.WIDTH * 0.5);
private static final int HORIZONTAL_LINE_LENGTH = (int) (TicTacToe.HEIGHT * 0.8);
private static final int STROKE_WIDTH = 5;
private Square[] squares;
public Board() {
}
public void addButtons() {
squares = new Square[9];
for (int i = 0; i < 3; i++) {
Square square = new Square(i);
square.setPreferredSize(new Dimension(30, 30));
square.addActionListener(square);
this.add(square);
squares[i] = square;
((GridLayout)this.getLayout()).setHgap(30);
((GridLayout)this.getLayout()).setVgap(30);
}
}
public Square[] getButtons() {
return squares;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(STROKE_WIDTH));
// Horiztontal lines
g2d.drawLine(0, TicTacToe.HEIGHT / 3,
BOARD_WIDTH, TicTacToe.HEIGHT / 3);
g2d.drawLine(0, 2 * TicTacToe.HEIGHT / 3,
BOARD_WIDTH, 2 * TicTacToe.HEIGHT / 3);
// Vertical lines
g2d.drawLine(BOARD_WIDTH / 3, 0, BOARD_WIDTH / 3,
TicTacToe.HEIGHT);
g2d.drawLine(2 * BOARD_WIDTH / 3, 0, 2 * BOARD_WIDTH / 3,
TicTacToe.HEIGHT);
}
}
主要方法:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Board board = new Board();
board.setPreferredSize(new Dimension((int) (WIDTH * 0.7), HEIGHT));
board.setLayout(new GridLayout(3, 3));
board.addButtons();
GameOptions opt = new GameOptions();
opt.setPreferredSize(new Dimension((int) (WIDTH * 0.3), HEIGHT));
JFrame frame = new JFrame("Tic Tac Toe");
frame.setLayout(new FlowLayout());
frame.add(board);
frame.add(opt);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
答案 0 :(得分:1)
您在按钮的绘图代码中使用getX()
和getY()
是完全错误的,不属于。这些方法返回按钮相对于其容器的位置,因此虽然这可能适用于位于左上角的按钮,但它会因其他任何原因而失败,因为您最终会在远离按钮本身的位置绘制,并且你的很多图画都不会出现。
你最好不要扩展JButton,而是简单地交换显示你想要在JButton上绘制的内容的ImageIcons。这更加简单,更加白痴。您可以通过调用按钮的.setIcon(myImageIcon)
来设置按钮的图标,并传递选择的图标。
但如果您绝对想要在按钮上绘图,则不必使用getX()
或getY()
。你也可能想要使用JToggleButton作为父类,因为你正在切换状态。例如,我的MCVE:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
@SuppressWarnings("serial")
public class DrawButtonPanel extends JPanel {
private static final int SIDE = 3;
private static final int GAP = 5;
private static final Color BG = Color.BLACK;
public DrawButtonPanel() {
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new GridLayout(SIDE, SIDE, GAP, GAP));
setBackground(BG);
for (int i = 0; i < SIDE * SIDE; i++) {
// add(new DrawButton1());
DrawButton2 drawButton2 = new DrawButton2(i);
AbstractButton button = drawButton2.getButton();
add(button);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawButtonPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class DrawButton2 {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private static final int GAP = 20;
private static final float STROKE_WIDTH = 15f;
private static final Stroke BASIC_STROKE = new BasicStroke(STROKE_WIDTH);
private static final Color COLOR = Color.RED;
private static final Color BG = Color.LIGHT_GRAY;
private AbstractButton button = new JToggleButton();
private int index;
public DrawButton2(int index) {
this.index = index;
button.setBorderPainted(false);
button.setBorder(null);
button.setIcon(createPlainIcon());
button.setSelectedIcon(createSelectedIcon());
button.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Index: " + index);
}
}
});
}
public int getIndex() {
return index;
}
private Icon createPlainIcon() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, PREF_W, PREF_H);
g2d.dispose();
return new ImageIcon(img);
}
private Icon createSelectedIcon() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(BASIC_STROKE);
g2d.setColor(BG);
g2d.fillRect(0, 0, PREF_W, PREF_H);
g2d.setColor(COLOR);
g2d.drawOval(GAP, GAP, PREF_W - 2 * GAP, PREF_H - 2 * GAP);
g2d.dispose();
return new ImageIcon(img);
}
public AbstractButton getButton() {
return button;
}
}
@SuppressWarnings("serial")
class DrawButton1 extends JToggleButton {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private static final int GAP = 20;
private static final float STROKE_WIDTH = 15f;
private static final Stroke BASIC_STROKE = new BasicStroke(STROKE_WIDTH);
private static final Color COLOR = Color.RED;
private static final Color BG = Color.LIGHT_GRAY;
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(BASIC_STROKE);
if (!isSelected()) {
super.paintComponent(g);
} else {
g2d.setColor(BG);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(COLOR);
g2d.drawOval(GAP, GAP, getWidth() - 2 * GAP, getHeight() - 2 * GAP);
}
g2d.dispose(); // since we created a new one
}
}
编辑以显示如何使用JToggleButton和图标执行此操作。