如何在 BorderLayout 中重绘 JPanel
How to redraw JPanels inside BorderLayout
在我的 borderlayout 中,我有 JPanels,它们被数组 theGrid 引用。在一个单独的函数中,我想更改 JPanel 的外观,因此我更改了具体 JPanel 的绘制方式。我遇到的问题是我现在不知道如何让它绘制这个新版本的 JPanel?
我查看了其他问题并尝试在 mainPanel 或 contentPane 或两者上使用 .revalidate、.validate、.repaint() 等,但 none 将获得新版本的 JPanel我创建是为了在上面绘制。
在下面的构造函数中,我设置了网格以及它如何适应 JFrame 的其余部分
public class GraphicDisplay extends JFrame {
private static int ROWS = 6;
private static int COLS = 7;
private JPanel[][] theGrid = new JPanel[ROWS][COLS];
private JPanel mainPanel = new JPanel(new GridLayout(ROWS, COLS));
private Container contentPane;
public GraphicDisplay() {
for (int i = 0; i < theGrid.length; i++) { //Initialize theGrid (with blanks)
for (int j = 0; j < theGrid[i].length; j++) {
theGrid[i][j] = new JPanel();
}
}
//add them to the JFrame
contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel boardElements = new JPanel();
boardElements.setLayout(new BoxLayout(boardElements, BoxLayout.Y_AXIS)); //vertical layout for the two parts, theGrid itself and then the
// button which goes underneath,
final int SPACE = 3;
final Color COLORCHOICE = Color.BLACK;
mainPanel.setBorder(BorderFactory.createEmptyBorder(SPACE, SPACE, SPACE, SPACE));
mainPanel.setBackground(COLORCHOICE);
JPanel[][] panels = new JPanel[ROWS][COLS];
for (int i = 0; i < panels.length; i++) {
for (int j = 0; j < panels[i].length; j++) {
panels[i][j] = new JPanel(new GridLayout(1, 1, 1, 1));
panels[i][j].setBackground(COLORCHOICE);
panels[i][j].setBorder(BorderFactory.createEmptyBorder(SPACE, SPACE, SPACE, SPACE));
mainPanel.add(panels[i][j]);
panels[i][j].add(theGrid[i][j]);
}
}
//adding the grid to the vertical layout
boardElements.add(mainPanel);
//adding the button which will go directly under the grid
boardElements.add(new JButton("Button"));
contentPane.add(boardElements, BorderLayout.CENTER);
}
下面的函数在同一个 class 中,假设通过在点 3,3 处添加一个点来更新网格(但问题是我没有看到任何可见的变化)
public void addDotToGrid() {
//theGrid[3][3] reference was added to the panels array which is part of the layout, so I would of thought by changing the value of it here would then change this JPanel on the UI
theGrid[3][3] = new JPanel() {
public void paintComponent( Graphics g) {
//g.setColor(Color.RED);
int y = 0;
int diameter = getWidth() -10;
int x = (getWidth()/2) - (diameter/2);
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// Assume x, y, and diameter are instance variables.
Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2d.fill(circle);
}
};
}
创建 GraphicDisplay 对象的另一个 class 中的 Main 方法
public static void main(String[] args) {
GraphicDisplay display2 = new GraphicDisplay();
display2.setSize(600, 600);
display2.setVisible(true);
display2.addDotToGrid();
}
问题是显示了网格,但 addDotToGrid() 没有改变任何东西,也没有向网格添加点
您正在更改由 theGrid 数组保存的 JPanel,但这对 GUI 中显示的 JPanel 没有影响,这就是变量与引用或对象之间的关键区别 -- 更改对象一个变量引用的对象对它之前引用的对象没有影响。您的解决方案是更改网格持有的 JPanel。
一种方法是为它们提供绘制所需内容的所有 paintComponent 方法,但让它们由布尔值控制,然后更改感兴趣面板的布尔变量。
如果这是我的 GUI,我会创建一个 JLabel 网格,并在需要的位置和时间简单地交换 ImageIcons -- 尽可能简单!
例如
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
@SuppressWarnings("serial")
public class MyGridEg extends JPanel {
private static final int SPACE = 6;
private static final int ROWS = 6;
private static final int COLS = 7;
private static final int IMG_W = 80;
private static final int SML_GAP = 3;
private static final Color IMG_BACKG = new Color(240, 240, 240);
private static final String TITLE = "Click on a Cell";
private JLabel[][] labelGrid = new JLabel[ROWS][COLS];
private Icon blankIcon = createIconDisk(new Color(0, 0, 0, 0));
private Icon redIcon = createIconDisk(Color.RED);
public MyGridEg() {
MyMouse myMouse = new MyMouse();
JPanel gridHolder = new JPanel(new GridLayout(ROWS, COLS, SPACE, SPACE));
gridHolder.setBackground(Color.BLACK);
for (int i = 0; i < labelGrid.length; i++) {
for (int j = 0; j < labelGrid[i].length; j++) {
JLabel label = new JLabel(blankIcon);
label.addMouseListener(myMouse);
labelGrid[i][j] = label;
gridHolder.add(label);
}
}
gridHolder.setBorder(BorderFactory.createLineBorder(Color.black, SPACE));
JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 20));
JButton clearButton = new JButton(new ClearAction("Clear"));
JPanel btnPanel = new JPanel();
btnPanel.add(clearButton);
setLayout(new BorderLayout());
add(gridHolder, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
add(titleLabel, BorderLayout.PAGE_START);
}
private Icon createIconDisk(Color color) {
BufferedImage img = new BufferedImage(IMG_W, IMG_W, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(IMG_BACKG);
g2.clearRect(0, 0, IMG_W, IMG_W);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(color);
int x = SML_GAP;
int y = x;
int width = IMG_W - 2 * x;
int height = IMG_W - 2 * y;
g2.fillOval(x, y, width, height);
g2.dispose();
return new ImageIcon(img);
}
private class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
JLabel selected = (JLabel) e.getSource();
Icon icon = selected.getIcon() == blankIcon ? redIcon : blankIcon;
selected.setIcon(icon);
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
for (JLabel[] labelRow : labelGrid) {
for (JLabel cell : labelRow) {
cell.setIcon(blankIcon);
}
}
}
}
private static void createAndShowGui() {
MyGridEg mainPanel = new MyGridEg();
JFrame frame = new JFrame("MyGridEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
这段代码的关键是我没有换掉 JLabel 或 JPanel,而是保持 JLabel 不变,但正在改变它们的状态。这样,如果我更改二维数组 labelGrid 所持有的 JLabel 的状态,这会反映在视图的更改中,就像我在 clearButton JButton 调用的 ClearAction class 中所做的那样:
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
for (JLabel[] labelRow : labelGrid) {
for (JLabel cell : labelRow) {
cell.setIcon(blankIcon);
}
}
}
}
在我的 borderlayout 中,我有 JPanels,它们被数组 theGrid 引用。在一个单独的函数中,我想更改 JPanel 的外观,因此我更改了具体 JPanel 的绘制方式。我遇到的问题是我现在不知道如何让它绘制这个新版本的 JPanel?
我查看了其他问题并尝试在 mainPanel 或 contentPane 或两者上使用 .revalidate、.validate、.repaint() 等,但 none 将获得新版本的 JPanel我创建是为了在上面绘制。
在下面的构造函数中,我设置了网格以及它如何适应 JFrame 的其余部分
public class GraphicDisplay extends JFrame {
private static int ROWS = 6;
private static int COLS = 7;
private JPanel[][] theGrid = new JPanel[ROWS][COLS];
private JPanel mainPanel = new JPanel(new GridLayout(ROWS, COLS));
private Container contentPane;
public GraphicDisplay() {
for (int i = 0; i < theGrid.length; i++) { //Initialize theGrid (with blanks)
for (int j = 0; j < theGrid[i].length; j++) {
theGrid[i][j] = new JPanel();
}
}
//add them to the JFrame
contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel boardElements = new JPanel();
boardElements.setLayout(new BoxLayout(boardElements, BoxLayout.Y_AXIS)); //vertical layout for the two parts, theGrid itself and then the
// button which goes underneath,
final int SPACE = 3;
final Color COLORCHOICE = Color.BLACK;
mainPanel.setBorder(BorderFactory.createEmptyBorder(SPACE, SPACE, SPACE, SPACE));
mainPanel.setBackground(COLORCHOICE);
JPanel[][] panels = new JPanel[ROWS][COLS];
for (int i = 0; i < panels.length; i++) {
for (int j = 0; j < panels[i].length; j++) {
panels[i][j] = new JPanel(new GridLayout(1, 1, 1, 1));
panels[i][j].setBackground(COLORCHOICE);
panels[i][j].setBorder(BorderFactory.createEmptyBorder(SPACE, SPACE, SPACE, SPACE));
mainPanel.add(panels[i][j]);
panels[i][j].add(theGrid[i][j]);
}
}
//adding the grid to the vertical layout
boardElements.add(mainPanel);
//adding the button which will go directly under the grid
boardElements.add(new JButton("Button"));
contentPane.add(boardElements, BorderLayout.CENTER);
}
下面的函数在同一个 class 中,假设通过在点 3,3 处添加一个点来更新网格(但问题是我没有看到任何可见的变化)
public void addDotToGrid() {
//theGrid[3][3] reference was added to the panels array which is part of the layout, so I would of thought by changing the value of it here would then change this JPanel on the UI
theGrid[3][3] = new JPanel() {
public void paintComponent( Graphics g) {
//g.setColor(Color.RED);
int y = 0;
int diameter = getWidth() -10;
int x = (getWidth()/2) - (diameter/2);
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// Assume x, y, and diameter are instance variables.
Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2d.fill(circle);
}
};
}
创建 GraphicDisplay 对象的另一个 class 中的 Main 方法
public static void main(String[] args) {
GraphicDisplay display2 = new GraphicDisplay();
display2.setSize(600, 600);
display2.setVisible(true);
display2.addDotToGrid();
}
问题是显示了网格,但 addDotToGrid() 没有改变任何东西,也没有向网格添加点
您正在更改由 theGrid 数组保存的 JPanel,但这对 GUI 中显示的 JPanel 没有影响,这就是变量与引用或对象之间的关键区别 -- 更改对象一个变量引用的对象对它之前引用的对象没有影响。您的解决方案是更改网格持有的 JPanel。
一种方法是为它们提供绘制所需内容的所有 paintComponent 方法,但让它们由布尔值控制,然后更改感兴趣面板的布尔变量。
如果这是我的 GUI,我会创建一个 JLabel 网格,并在需要的位置和时间简单地交换 ImageIcons -- 尽可能简单!
例如
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
@SuppressWarnings("serial")
public class MyGridEg extends JPanel {
private static final int SPACE = 6;
private static final int ROWS = 6;
private static final int COLS = 7;
private static final int IMG_W = 80;
private static final int SML_GAP = 3;
private static final Color IMG_BACKG = new Color(240, 240, 240);
private static final String TITLE = "Click on a Cell";
private JLabel[][] labelGrid = new JLabel[ROWS][COLS];
private Icon blankIcon = createIconDisk(new Color(0, 0, 0, 0));
private Icon redIcon = createIconDisk(Color.RED);
public MyGridEg() {
MyMouse myMouse = new MyMouse();
JPanel gridHolder = new JPanel(new GridLayout(ROWS, COLS, SPACE, SPACE));
gridHolder.setBackground(Color.BLACK);
for (int i = 0; i < labelGrid.length; i++) {
for (int j = 0; j < labelGrid[i].length; j++) {
JLabel label = new JLabel(blankIcon);
label.addMouseListener(myMouse);
labelGrid[i][j] = label;
gridHolder.add(label);
}
}
gridHolder.setBorder(BorderFactory.createLineBorder(Color.black, SPACE));
JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 20));
JButton clearButton = new JButton(new ClearAction("Clear"));
JPanel btnPanel = new JPanel();
btnPanel.add(clearButton);
setLayout(new BorderLayout());
add(gridHolder, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
add(titleLabel, BorderLayout.PAGE_START);
}
private Icon createIconDisk(Color color) {
BufferedImage img = new BufferedImage(IMG_W, IMG_W, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(IMG_BACKG);
g2.clearRect(0, 0, IMG_W, IMG_W);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(color);
int x = SML_GAP;
int y = x;
int width = IMG_W - 2 * x;
int height = IMG_W - 2 * y;
g2.fillOval(x, y, width, height);
g2.dispose();
return new ImageIcon(img);
}
private class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
JLabel selected = (JLabel) e.getSource();
Icon icon = selected.getIcon() == blankIcon ? redIcon : blankIcon;
selected.setIcon(icon);
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
for (JLabel[] labelRow : labelGrid) {
for (JLabel cell : labelRow) {
cell.setIcon(blankIcon);
}
}
}
}
private static void createAndShowGui() {
MyGridEg mainPanel = new MyGridEg();
JFrame frame = new JFrame("MyGridEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
这段代码的关键是我没有换掉 JLabel 或 JPanel,而是保持 JLabel 不变,但正在改变它们的状态。这样,如果我更改二维数组 labelGrid 所持有的 JLabel 的状态,这会反映在视图的更改中,就像我在 clearButton JButton 调用的 ClearAction class 中所做的那样:
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
for (JLabel[] labelRow : labelGrid) {
for (JLabel cell : labelRow) {
cell.setIcon(blankIcon);
}
}
}
}