JPanel异常问题:点击按钮后子面板无法正常显示圆形
Java Swing 图形绘制与组件显示问题修复
需求与问题现象
需求
实现初始界面显示图片与JButton,点击按钮后隐藏二者,显示带有圆形的子面板及左右箭头按钮,通过点击箭头重绘圆形实现移动。
问题现象
- 初始界面显示正常
- 点击按钮后子面板显示,但无圆形(仅示例文本可见)
- 点击箭头按钮后圆形仍不出现,按钮旁反而出现第二个无圆形的子面板
- 调整布局、面板大小后问题未解决
问题代码
驱动类 FinalProject
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.JFrame; import java.awt.Graphics; import java.awt.Graphics2D; public class FinalProject{ public static void main(String[] args){ JFrame frame = new JFrame("exploration game"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setVisible(true); Graphics x = frame.getGraphics(); FinalProjectPanel panel = new FinalProjectPanel(x, new BorderLayout()); frame.getContentPane().add(panel); frame.pack(); frame.setResizable(false); } }
主面板类 FinalProjectPanel
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.JFrame; import java.awt.Graphics; import java.awt.Graphics2D; public class FinalProjectPanel extends JPanel{ private JButton startButton; private JLabel starttext; private ImageIcon startingscren; private JButton Left; private JButton Right; private GraphicSubpanel subpanel; public FinalProjectPanel(Graphics g, BorderLayout b){ startingscren = new ImageIcon("starting-screen.png"); starttext = new JLabel(startingscren); starttext.setVisible(false); startButton = new JButton("Start Game"); startButton.addActionListener(new startListener()); Left = new JButton("<-"); Left.setVisible(false); Left.addActionListener(new leftListener()); Right = new JButton("->"); Right.addActionListener(new rightListener()); Right.setVisible(false); setPreferredSize(new Dimension(500,500)); subpanel = new GraphicSubpanel(g, 10, 100); subpanel.setPreferredSize(new Dimension(100,100)); subpanel.setVisible(false); add(starttext, BorderLayout.PAGE_START); add(startButton, BorderLayout.PAGE_END); add(Left,BorderLayout.LINE_START); add(Right,BorderLayout.LINE_END); add(subpanel, BorderLayout.CENTER); } private class startListener implements ActionListener{ public void actionPerformed (ActionEvent event){ startButton.setVisible(false); starttext.setVisible(false); subpanel.setVisible(true); Left.setVisible(true); Right.setVisible(true); } } private class leftListener implements ActionListener{ public void actionPerformed (ActionEvent event){ subpanel.setX(subpanel.getX()-10); } } private class rightListener implements ActionListener{ public void actionPerformed (ActionEvent event){ subpanel.setX(subpanel.getX()+10); } } }
绘图子面板类 GraphicSubpanel
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.JFrame; import java.awt.Graphics; import java.awt.Graphics2D; public class GraphicSubpanel extends JPanel{ private int x; private int y; private JLabel randomlabel; private Circle player; private Graphics2D g2d; public GraphicSubpanel(Graphics g2d, int x, int y){ this.x = x; this.y = y; this.g2d = (Graphics2D) g2d; randomlabel = new JLabel("sample text"); player = new Circle(60,x,y); player.setVisible(true); add(player); add(randomlabel); setBackground(Color.YELLOW); repaint(); } public int getX(){ return x; }public int getY(){ return y; } public void setX(int a){ x = a; repaint(); } public void setY(int a){ y = a; repaint(); } private class Circle extends JComponent { private int diam; private int x; private int y; public Circle(int diam, int x, int y) { this.diam = diam; this.x = x; this.y = y; setPreferredSize(new Dimension(diam, diam)); } @Override public void paintComponent(Graphics g) { super.paintComponent(g2d); g2d.setColor(Color.RED); g2d.fillOval(x, y, diam, diam); System.out.println("test"); } public int getX(){ return x; } public int getY(){ return y; } } }
核心问题与修复点
- 禁止提前获取Graphics对象:删除main方法中
Graphics x = frame.getGraphics();的调用,Swing组件的绘制必须使用paintComponent方法传入的上下文,临时获取的Graphics对象会失效。 - 重命名冲突的getX/getY方法:将自定义的坐标方法改为
getCircleX/setCircleX,避免覆盖JComponent自带的组件位置获取方法,解决布局混乱问题。 - 修正Circle的绘制逻辑:
- 在
paintComponent中使用方法参数的g,转换为Graphics2D,而非外部传入的对象 - 圆形绘制使用自身组件的相对坐标(
0,0),通过setBounds控制组件在父面板的位置
- 在
- 同步坐标更新:点击箭头时,更新GraphicSubpanel的坐标后,同步更新Circle的坐标并调用
repaint() - 调整窗口初始化顺序:main方法中先添加组件,再调用
frame.setVisible(true),确保组件正确渲染 - 修复布局问题:GraphicSubpanel使用绝对布局(或根据需求选择合适布局),避免FlowLayout导致的组件排列混乱
内容的提问来源于stack exchange,提问作者Adsf ghjkl
相关产品推荐
相关产品推荐

