You need to enable JavaScript to run this app. 如何在Swing自定义绘制的饼图各区块中心显示对应数据项
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swing自定义绘制的饼图各区块中心显示对应数据项

实现方案

完全可以实现,核心是计算每个扇形的中心坐标后在对应位置绘制文本即可,具体实现逻辑和修改后代码如下:

核心计算逻辑

  • 先确定饼图基础参数:你当前代码中饼图绘制区域左上角为(50,20)、宽高均为200px,因此圆心坐标为(150,120),半径为100px,文本放在半径一半的位置即可保证在扇形内部。
  • 每个扇形的中心角度 = 扇形起始角度 + 扇形扫过角度/2,需转换为弧度后调用三角函数计算坐标。
  • Swing的Y轴向下为正,和数学坐标系相反,坐标转换公式为:
    • X坐标 = 圆心X + 文本距离圆心长度 * cos(中心角度弧度)
    • Y坐标 = 圆心Y - 文本距离圆心长度 * sin(中心角度弧度)
  • 绘制时用FontMetrics计算文本宽高,对坐标做微调即可让文本完全居中。

修改后完整代码

public class DrawingPiePanel extends JPanel {
    private static final long serialVersionUID = 1L;

    Admin ad = Login.ad;
    String month = ad.year1 + "-01";
    kiosk_dao dao = new kiosk_dao();
    int Kor = dao.SelectSaleMonthRestaurant(month, "한식");
    int Ch = dao.SelectSaleMonthRestaurant(month, "중식");
    int Jp = dao.SelectSaleMonthRestaurant(month, "일식");
    int We = dao.SelectSaleMonthRestaurant(month, "양식");

    // 优化:Swing自定义绘制建议重写paintComponent而非paint方法
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.clearRect(0, 0, getWidth(), getHeight());

        int Total = Kor + Ch + Jp + We;
        if (Total != 0) {
            int arc1 = (int) (360.0 * Kor / Total);
            int arc2 = (int) (360.0 * Ch / Total);
            int arc3 = (int) (360.0 * Jp / Total);
            int arc4 = 360 - (arc1 + arc2 + arc3);

            double KorPer = (double) Kor / (double) Total * 100;
            double ChPer = (double) Ch / (double) Total * 100;
            double JpPer = (double) Jp / (double) Total * 100;
            double WePer = (double) We / (double) Total * 100;

            // 绘制扇形
            g.setColor(Color.YELLOW);
            g.fillArc(50, 20, 200, 200, 0, arc1);
            g.setColor(Color.RED);
            g.fillArc(50, 20, 200, 200, arc1, arc2);
            g.setColor(Color.BLUE);
            g.fillArc(50, 20, 200, 200, arc1 + arc2, arc3);
            g.setColor(Color.GREEN);
            g.fillArc(50, 20, 200, 200, arc1 + arc2 + arc3, arc4);

            // 新增:绘制扇形内部文本
            g.setColor(Color.BLACK);
            g.setFont(new Font("굴림체", Font.PLAIN, 12));
            int centerX = 50 + 200 / 2;
            int centerY = 20 + 200 / 2;
            int labelRadius = 50; // 文本距离圆心的长度,可自行调整
            FontMetrics fm = g.getFontMetrics();

            // 韩餐文本
            double midAngle = Math.toRadians(0 + arc1 / 2.0);
            int textX = (int) (centerX + labelRadius * Math.cos(midAngle));
            int textY = (int) (centerY - labelRadius * Math.sin(midAngle));
            String korText = String.format("%.1f%%", KorPer);
            textX -= fm.stringWidth(korText) / 2;
            textY += fm.getAscent() / 2;
            g.drawString(korText, textX, textY);

            // 中餐文本
            midAngle = Math.toRadians(arc1 + arc2 / 2.0);
            textX = (int) (centerX + labelRadius * Math.cos(midAngle));
            textY = (int) (centerY - labelRadius * Math.sin(midAngle));
            String chText = String.format("%.1f%%", ChPer);
            textX -= fm.stringWidth(chText) / 2;
            textY += fm.getAscent() / 2;
            g.drawString(chText, textX, textY);

            // 日料文本
            midAngle = Math.toRadians(arc1 + arc2 + arc3 / 2.0);
            textX = (int) (centerX + labelRadius * Math.cos(midAngle));
            textY = (int) (centerY - labelRadius * Math.sin(midAngle));
            String jpText = String.format("%.1f%%", JpPer);
            textX -= fm.stringWidth(jpText) / 2;
            textY += fm.getAscent() / 2;
            g.drawString(jpText, textX, textY);

            // 西餐文本
            midAngle = Math.toRadians(arc1 + arc2 + arc3 + arc4 / 2.0);
            textX = (int) (centerX + labelRadius * Math.cos(midAngle));
            textY = (int) (centerY - labelRadius * Math.sin(midAngle));
            String weText = String.format("%.1f%%", WePer);
            textX -= fm.stringWidth(weText) / 2;
            textY += fm.getAscent() / 2;
            g.drawString(weText, textX, textY);

            // 原右侧图例
            g.drawString(" 한식: 노랑" + String.format("%.2f", KorPer) + "%", 300, 150);
            g.drawString(" 중식: 빨강" + String.format("%.2f", ChPer) + "%", 300, 170);
            g.drawString(" 일식: 파랑" + String.format("%.2f", JpPer) + "%", 300, 190);
            g.drawString(" 양식: 초록" + String.format("%.2f", WePer) + "%", 300, 210);
            g.drawString(" 총매출액: " + Total + " 원", 300, 230);
        }
    }
}

可调参数说明

  • labelRadius:控制文本距离圆心的距离,数值越大文本越靠近扇形外侧,可根据实际显示效果调整。
  • 绘制的文本内容可以自行修改,如需显示分类名或者销售额直接替换字符串即可。
  • 如果扇形占比过小导致文本重叠,可以判断占比低于阈值时不绘制内部文本,只保留右侧图例即可。

内容的提问来源于stack exchange,提问作者이윤혁

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 23:24:03