更新不可见的 JPanel 中的值
Update values in a JPanel that is not visible
一段时间以来,我一直对我的代码中一些非常奇怪的行为感到沮丧,在花时间慢慢地一点一点地整理我的代码之后,我终于找到了问题的根源。
总体概述:使用Java Swing,以下代码创建了一个选项卡式界面。用户可见的第一个选项卡有一个按钮。第二个选项卡的左上角有一个蓝色方块。
应该发生什么:程序打开后,先单击按钮,然后打开另一个选项卡。该按钮调用另一个选项卡上的函数,使方块移动到新位置。因此,另一个选项卡应该在新位置显示正方形,而不是左上角。
实际情况:如果您先单击按钮然后打开选项卡,方块的位置不会改变。它保留在左上角,就好像从未按下过按钮一样。如果您首先打开选项卡,它似乎以某种方式“启动”了程序,所以现在该按钮按预期工作。
当然,首先单击选项卡以确保程序正常运行似乎是一个小麻烦,但这可能是一个非常大的问题。为什么选项卡在至少被查看一次之前无法更新?
观察:调试代码时,我可以单步执行 setUnit()
函数并验证正方形实际上已成功更改,完全覆盖了之前的位置。然而,当我打开第二个选项卡时,正方形的位置现在恢复到之前的位置。如果此时检查变量,则表明正方形的原始位置完全保持不变,就好像从未调用过 setUnit()
函数一样。知道这些组件除非重新绘制,否则不会在视觉上更新,因此我确保在 setUnit()
函数中添加 repaint()
函数调用。我真的很想知道广场位置的原始值存储在哪里?我可以在调试器中看到值被覆盖,所以它们应该完全不存在了,对吧?
代码:
DragPanel.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JPanel;
class DragPanel extends JPanel
{
private static final long serialVersionUID = 1L;
boolean isFirstTime = true;
Rectangle area;
Rectangle rect = new Rectangle(0, 0, 20, 20);
private Dimension dim = new Dimension(400, 300);
public DragPanel() {
setBackground(Color.white);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (isFirstTime) {
area = new Rectangle(dim);
rect.setLocation(0, 0);
isFirstTime = false;
}
g2d.setColor(Color.blue);
g2d.fill(rect);
}
public void setUnit()
{
rect.setLocation(200, 50);
repaint();
}
}
ShapeMover.Java:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class ShapeMover {
public ShapeMover() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
}
public static void main(String s[]) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ShapeMover();
}
});
}
private void initComponents(JFrame frame) {
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(10, 93, 426, 527);
frame.getContentPane().add(tabbedPane);
DragPanel shaper = new DragPanel();
shaper.setBounds(0, 79, 420, 420);
JPanel input = new JPanel();
tabbedPane.addTab("Test", null, input, null);
input.setLayout(null);
JButton add = new JButton("Click this");
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
shaper.setUnit();
}
});
add.setBounds(201, 64, 65, 23);
input.add(add);
JPanel output = new JPanel();
tabbedPane.addTab("Second", null, output, null);
output.setLayout(null);
output.add(shaper);
frame.pack();
frame.setVisible(true);
}
}
根据 tgdavies 的评论,我找到了解决办法。
paintComponent
不是对象构造的一部分,而是仅在看到面板时调用。也就是画的时候。在看到面板之前,即使调用 repaint()
也不会调用 paintComponent
。因此,第一次查看面板时,这段代码只执行一次:
if (isFirstTime)
{
area = new Rectangle(dim);
rect.setLocation(0, 0);
isFirstTime = false;
}
执行一次后,isFirstTime
设置为false,不再运行该段代码。因此,调用 setUnit()
确实会覆盖正方形的原始位置。然后上面显示的代码部分将其设置回 0,0。
只需注释掉显示为 rect.setLocation(0, 0);
的代码行即可解决问题。
一段时间以来,我一直对我的代码中一些非常奇怪的行为感到沮丧,在花时间慢慢地一点一点地整理我的代码之后,我终于找到了问题的根源。
总体概述:使用Java Swing,以下代码创建了一个选项卡式界面。用户可见的第一个选项卡有一个按钮。第二个选项卡的左上角有一个蓝色方块。
应该发生什么:程序打开后,先单击按钮,然后打开另一个选项卡。该按钮调用另一个选项卡上的函数,使方块移动到新位置。因此,另一个选项卡应该在新位置显示正方形,而不是左上角。
实际情况:如果您先单击按钮然后打开选项卡,方块的位置不会改变。它保留在左上角,就好像从未按下过按钮一样。如果您首先打开选项卡,它似乎以某种方式“启动”了程序,所以现在该按钮按预期工作。
当然,首先单击选项卡以确保程序正常运行似乎是一个小麻烦,但这可能是一个非常大的问题。为什么选项卡在至少被查看一次之前无法更新?
观察:调试代码时,我可以单步执行 setUnit()
函数并验证正方形实际上已成功更改,完全覆盖了之前的位置。然而,当我打开第二个选项卡时,正方形的位置现在恢复到之前的位置。如果此时检查变量,则表明正方形的原始位置完全保持不变,就好像从未调用过 setUnit()
函数一样。知道这些组件除非重新绘制,否则不会在视觉上更新,因此我确保在 setUnit()
函数中添加 repaint()
函数调用。我真的很想知道广场位置的原始值存储在哪里?我可以在调试器中看到值被覆盖,所以它们应该完全不存在了,对吧?
代码:
DragPanel.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JPanel;
class DragPanel extends JPanel
{
private static final long serialVersionUID = 1L;
boolean isFirstTime = true;
Rectangle area;
Rectangle rect = new Rectangle(0, 0, 20, 20);
private Dimension dim = new Dimension(400, 300);
public DragPanel() {
setBackground(Color.white);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (isFirstTime) {
area = new Rectangle(dim);
rect.setLocation(0, 0);
isFirstTime = false;
}
g2d.setColor(Color.blue);
g2d.fill(rect);
}
public void setUnit()
{
rect.setLocation(200, 50);
repaint();
}
}
ShapeMover.Java:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class ShapeMover {
public ShapeMover() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
}
public static void main(String s[]) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ShapeMover();
}
});
}
private void initComponents(JFrame frame) {
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(10, 93, 426, 527);
frame.getContentPane().add(tabbedPane);
DragPanel shaper = new DragPanel();
shaper.setBounds(0, 79, 420, 420);
JPanel input = new JPanel();
tabbedPane.addTab("Test", null, input, null);
input.setLayout(null);
JButton add = new JButton("Click this");
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
shaper.setUnit();
}
});
add.setBounds(201, 64, 65, 23);
input.add(add);
JPanel output = new JPanel();
tabbedPane.addTab("Second", null, output, null);
output.setLayout(null);
output.add(shaper);
frame.pack();
frame.setVisible(true);
}
}
根据 tgdavies 的评论,我找到了解决办法。
paintComponent
不是对象构造的一部分,而是仅在看到面板时调用。也就是画的时候。在看到面板之前,即使调用 repaint()
也不会调用 paintComponent
。因此,第一次查看面板时,这段代码只执行一次:
if (isFirstTime)
{
area = new Rectangle(dim);
rect.setLocation(0, 0);
isFirstTime = false;
}
执行一次后,isFirstTime
设置为false,不再运行该段代码。因此,调用 setUnit()
确实会覆盖正方形的原始位置。然后上面显示的代码部分将其设置回 0,0。
只需注释掉显示为 rect.setLocation(0, 0);
的代码行即可解决问题。