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

在Swing中创建可变统计信息展示界面遇到的技术问题

嘿,恭喜你在Stack Overflow提第一个问题!别担心疏漏,大家都是从新手阶段过来的😉 我完全理解你的需求:做一个动态的统计展示界面,支持/反对两类统计项,每个项的名称要放在对应条形元素的上方,而且所有统计项的数量、名称、百分比都是不固定的。

针对你遇到的“名称无法放在对应元素上方”的问题,我给你提供一个实用的Swing实现思路和代码示例:

核心思路

把每个统计项做成一个垂直排列的独立小容器,顶部放名称标签,下方放显示百分比的条形组件(可以用默认的JProgressBar,也可以自定义绘制更个性化的条形)。然后把这些小容器分别归类到“支持”和“反对”两个大面板中,最终组合成主界面。

完整代码示例

1. 主统计面板类(支持动态添加项)

import javax.swing.*;
import java.awt.*;

public class DecisionStatsPanel extends JPanel {
    private final JPanel supportGroupPanel;
    private final JPanel opposeGroupPanel;

    public DecisionStatsPanel() {
        // 主面板用两列网格布局,分隔支持/反对区域
        setLayout(new GridLayout(1, 2, 30, 0));
        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        // 初始化支持区域面板
        supportGroupPanel = createGroupPanel("支持");
        // 初始化反对区域面板
        opposeGroupPanel = createGroupPanel("反对");

        add(supportGroupPanel);
        add(opposeGroupPanel);
    }

    // 创建每个类别的头部面板
    private JPanel createGroupPanel(String groupName) {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        JLabel groupLabel = new JLabel(groupName, SwingConstants.CENTER);
        groupLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
        panel.add(groupLabel);
        panel.add(Box.createVerticalStrut(15));
        return panel;
    }

    // 动态添加单个统计项
    public void addStatItem(String itemName, double percentage, boolean isSupport) {
        JPanel itemPanel = createSingleStatItem(itemName, percentage, isSupport);
        if (isSupport) {
            supportGroupPanel.add(itemPanel);
        } else {
            opposeGroupPanel.add(itemPanel);
        }
        // 添加项之间的间距
        supportGroupPanel.add(Box.createVerticalStrut(20));
        opposeGroupPanel.add(Box.createVerticalStrut(20));
        // 更新界面布局
        revalidate();
        repaint();
    }

    // 创建单个统计项的垂直容器(名称+条形)
    private JPanel createSingleStatItem(String itemName, double percentage, boolean isSupport) {
        JPanel itemPanel = new JPanel();
        itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
        itemPanel.setAlignmentX(Component.CENTER_ALIGNMENT);

        // 顶部的名称标签
        JLabel nameLabel = new JLabel(itemName, SwingConstants.CENTER);
        nameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        nameLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        // 下方的百分比条形(这里用自定义组件,样式更灵活)
        CustomPercentageBar bar = new CustomPercentageBar(percentage, isSupport);
        bar.setAlignmentX(Component.CENTER_ALIGNMENT);

        // 添加到容器并设置间距
        itemPanel.add(nameLabel);
        itemPanel.add(Box.createVerticalStrut(8));
        itemPanel.add(bar);

        return itemPanel;
    }

    // 自定义百分比条形组件(比默认ProgressBar样式更可控)
    static class CustomPercentageBar extends JComponent {
        private final double percentage;
        private final boolean isSupport;

        public CustomPercentageBar(double percentage, boolean isSupport) {
            this.percentage = Math.max(0, Math.min(1, percentage)); // 限制0-1范围
            this.isSupport = isSupport;
            setPreferredSize(new Dimension(220, 35)); // 设置默认尺寸
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // 绘制背景边框
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 8, 8);

            // 绘制填充进度
            int fillWidth = (int) (getWidth() * percentage);
            g2d.setColor(isSupport ? new Color(46, 204, 113) : new Color(231, 76, 60));
            g2d.fillRoundRect(0, 0, fillWidth, getHeight(), 8, 8);

            // 绘制百分比文本
            g2d.setColor(Color.WHITE);
            g2d.setFont(new Font("微软雅黑", Font.BOLD, 14));
            String text = String.format("%.0f%%", percentage * 100);
            FontMetrics fm = g2d.getFontMetrics();
            int textX = (getWidth() - fm.stringWidth(text)) / 2;
            int textY = (getHeight() + fm.getAscent()) / 2;
            g2d.drawString(text, textX, textY);
        }
    }

    // 测试主方法
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("决策统计展示");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            DecisionStatsPanel statsPanel = new DecisionStatsPanel();

            // 模拟动态添加统计项
            statsPanel.addStatItem("sneezing", 0.78, true);
            statsPanel.addStatItem("coughing", 0.65, true);
            statsPanel.addStatItem("headache", 0.42, false);
            statsPanel.addStatItem("fatigue", 0.83, false);

            frame.add(statsPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

关键说明

  1. 垂直布局的小容器:用BoxLayout.Y_AXIS实现名称和条形的上下排列,确保每个统计项的结构独立。
  2. 自定义条形组件:相比默认的JProgressBar,自定义绘制可以更灵活地控制颜色、圆角、文本样式,完全匹配你想要的效果。
  3. 动态更新:添加新的统计项后调用revalidate()和repaint(),确保界面及时刷新显示新内容。

如果需要调整样式(比如条形颜色、字体、间距),直接修改对应代码里的参数就行,非常灵活。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:08:00