You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSplitPane与paintComponent冲突:自定义City组件圆形不显示求助

解决JSplitPane中自定义JPanel组件不显示的问题

嘿,我一眼就发现问题所在了——你在使用**绝对布局(null布局)**的时候,没有给你的City组件指定尺寸和位置!

问题根源解释

你给左右两侧的面板lp和rp都用了new JPanel(null),也就是放弃了Swing的布局管理器,采用手动定位。这种情况下,所有添加到面板的组件都必须通过setBounds(x, y, width, height)手动设置位置和大小,否则组件的默认尺寸是0×0,自然就看不到了。

你提到把City直接加到JFrame时能显示,那是因为JFrame的默认内容面板用的是BorderLayout,它会自动拉伸组件填满可用空间,所以City能被渲染出来,但这时候你替换了原来的JSplitPane,导致其他组件被覆盖消失。


方案1:快速修复——给City组件设置边界

在主类中实例化City之后,直接添加一行代码指定它的位置和大小:

City test = new City(0, 0); // 这里的坐标改为相对于右侧面板rp的位置,比如(0,0)
rp.add(test);
test.setBounds(301, 301, 10, 10); // 位置(x,y) + 宽高(width,height)

注意:这里的xPos和yPos要和setBounds的位置对应,或者调整City类里的绘制逻辑,让圆形绘制在组件自身的坐标范围内(比如把xPos和yPos设为相对于组件左上角的偏移,而不是相对于整个窗口)。


方案2:推荐方案——放弃绝对布局,使用Swing布局管理器

绝对布局在Swing中是非常不推荐的,它无法适配窗口大小变化、不同平台的UI差异,还容易出现组件错位的问题。我们可以改用布局管理器来解决这个问题:

步骤1:修改右侧面板的布局

把右侧面板rp的初始化改为使用BorderLayout:

JPanel rp = new JPanel(new BorderLayout()); // 替换null布局

步骤2:调整City类的绘制逻辑

让圆形可以根据组件的尺寸自适应位置(比如画在组件中心):

public class City extends JPanel{
    // 可以保留xPos和yPos,或者改为动态计算位置
    int xPos, yPos;
    City(int x, int y){
        xPos = x;
        yPos = y;
    }
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        // 如果要固定位置,就用xPos和yPos;如果要自适应,就用组件的宽高计算
        // 示例:画在组件中心
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;
        g.fillOval(centerX - 5, centerY - 5, 10, 10);
    }
}

步骤3:添加City到右侧面板

用布局管理器的方式添加组件,不需要手动设置边界:

City test = new City(0, 0);
rp.add(test, BorderLayout.CENTER); // 让City填满右侧面板

另外,左侧面板lp也建议改用布局管理器(比如GridBagLayout或BoxLayout)来排列标签、Spinner和按钮,这样组件的布局会更稳定、更符合Swing的设计规范。


修复后的完整主类示例(方案2)

import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class TSP{
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TSP();
            }
        });
    }
    TSP(){
        JLabel instructions = new JLabel("Enter the number of cities: ");
        SpinnerNumberModel numMod = new SpinnerNumberModel(2, 2, 10, 1);
        JSpinner numOfCities = new JSpinner(numMod);
        JButton start = new JButton("Start Simulation");
        
        // 左侧面板改用GridBagLayout来排列组件(替代null布局)
        JPanel lp = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10);
        gbc.gridx = 0;
        gbc.gridy = 0;
        lp.add(instructions, gbc);
        gbc.gridx = 1;
        lp.add(numOfCities, gbc);
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.gridwidth = 2;
        lp.add(start, gbc);
        
        // 右侧面板用BorderLayout
        JPanel rp = new JPanel(new BorderLayout());
        
        JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        sp.setDividerLocation(300);
        sp.setLeftComponent(lp);
        sp.setRightComponent(rp);
        sp.setEnabled(false);
        
        JFrame frame = new JFrame("Travelling Salesperson");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 用常量替代魔数3
        frame.setSize(1100,600);
        frame.setResizable(false);
        
        // 添加City到右侧面板
        City test = new City(0, 0);
        rp.add(test, BorderLayout.CENTER);
        
        frame.add(sp);
        frame.setVisible(true);
    }
}

这样修改后,圆形会稳定显示在JSplitPane的右侧面板中,同时左侧的组件也能正常显示,布局也更健壮。

内容的提问来源于stack exchange,提问作者SteamedBun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:42:45