欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

超轻量Swing仪表盘组件 Swing仪表盘 

程序员文章站 2022-06-02 09:53:59
...
XDoc发布了8.2.5版本,新版本中增加了扩展组件:刻度盘,用于动态图示化展示数据
现在将它封装成一个Swing组件与大家分享,大家可以稍做调整画出更漂亮的仪表盘
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 刻度盘
 * @author xdoc
 */
public class Tick extends JComponent {
    private static final int VALUE_FONT_SIZE = 18;
    private double from = 0;
    private double to = 10;
    private String type = "line";
    private double major = 1;
    private double minor = 0.1;
    private String value = "";
    private String unit = "";
    public double getFrom() {
        return from;
    }
    public Tick() {
        super();
        this.setPreferredSize(new Dimension(60, 60));
        this.setBackground(Color.WHITE);
    }
    public void setFrom(double from) {
        this.from = from;
    }
    public double getMajor() {
        return major;
    }
    public void setMajor(double major) {
        this.major = major;
    }
    public double getMinor() {
        return minor;
    }
    public void setMinor(double minor) {
        this.minor = minor;
    }
    public double getTo() {
        return to;
    }
    public void setTo(double to) {
        this.to = to;
    }
    public String getType() {
        return type;
    }
    /**
     * 直尺
     */
    public static final String LINE = "line";
    /**
     * 120度圆环
     */
    public static final String RING_120 = "ring120";
    public static final String RING_180 = "ring180";
    public static final String RING_240 = "ring240";
    /**
     * 圆盘
     */
    public static final String CIRCLE = "circle";
    public void setType(String type) {
        this.type = type;
    }
    public String getUnit() {
        return unit;
    }
    public void setUnit(String unit) {
        this.unit = unit;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public void paintComponent(Graphics g) {
        double w = this.getWidth();
        double h = this.getHeight();
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(this.getBackground());
        g2.fillRect(0, 0, (int) w, (int) h);
        g2.setColor(this.getForeground());
        g2.setStroke(new BasicStroke(1));
        int fontSize = 14;
        g2.setFont(new Font(Font.SERIF, Font.PLAIN, fontSize));
        if (major <= 0) {
            major = to - from;
        }
        if (to > from) {
            if (type.startsWith("ring") || type.equals("circle")) {
                double angle;
                double angleStart;
                if (type.equals("circle")) {
                    angle = 360;
                    angleStart = Math.PI / 2;
                } else {
                    angle = toDouble(type.substring(4));
                    angleStart = (180 + (angle - 180) / 2) / 180 * Math.PI;
                }
                double r = angle <= 180 ? Math.min(w / 2, h) : Math.min(w / 2, h / 2);
                double voff = angle <= 180 ? 0 : r;
                double dunit = (angle / 180 * Math.PI) / (to - from);
                for (int i = 0; i <= (to - from) / major; i++) {
                    g2.draw(new Line2D.Double(Math.cos(angleStart - i * major * dunit) * r + w / 2, h - voff - Math.sin(angleStart - i * major * dunit) * r,
                            Math.cos(angleStart - i * major * dunit) * r * 0.75 + w / 2, h - voff - Math.sin(angleStart - i * major * dunit) * r * 0.75));
                    if (minor > 0 && i < (to - from) / major) {
                        for (int j = 1; j < major / minor; j++) {
                            if (i * major + j * minor < to - from) {
                                g2.draw(new Line2D.Double(Math.cos(angleStart - (i * major + j * minor) * dunit) * r + w / 2, h - voff - Math.sin(angleStart - (i * major + j * minor) * dunit) * r,
                                        Math.cos(angleStart - (i * major + j * minor) * dunit) * r * 0.875 + w / 2, h - voff - Math.sin(angleStart - (i * major + j * minor) * dunit) * r * 0.875));
                            }
                        }
                    }
                }
                if (value.length() > 0) {
                    double val = toDouble(value);
                    GeneralPath p = new GeneralPath();
                    p.moveTo(Math.cos(angleStart - (val - from) * dunit) * r * 0.875 + w / 2, h - voff - Math.sin(angleStart - (val - from) * dunit) * r * 0.875);
                    p.lineTo(Math.cos(angleStart - (val - from) * dunit + Math.PI * 0.5) * 2 + w / 2, h - voff - Math.sin(angleStart - (val - from) * dunit + Math.PI * 0.5) * 2);
                    p.lineTo(Math.cos(angleStart - (val - from) * dunit - Math.PI * 0.5) * 2 + w / 2, h - voff - Math.sin(angleStart - (val - from) * dunit - Math.PI * 0.5) * 2);
                    p.closePath();
                    g2.fill(p);
                }
            } else {
                if (w > h) {
                    double dunit = w / (to - from);
                    for (int i = 0; i <= (to - from) / major; i++) {
                        g2.draw(new Line2D.Double(i * major * dunit, 0, i * major * dunit, h - fontSize));
                        if (i < (to - from) / major && minor > 0) {
                            for (int j = 1; j < major / minor; j++) {
                                g2.draw(new Line2D.Double((i * major + j * minor) * dunit, 0, (i * major + j * minor) * dunit, (h - fontSize) / 2));
                            }
                        }
                    }
                    if (value.length() > 0) {
                        double val = toDouble(value);
                        GeneralPath p = new GeneralPath();
                        p.moveTo((val - from) * dunit, (h - fontSize) / 2);
                        p.lineTo((val - from) * dunit - 4, h - fontSize);
                        p.lineTo((val - from) * dunit + 4, h - fontSize);
                        p.closePath();
                        g2.fill(p);
                    }
                } else {
                    int max = (int) Math.max(getStrBounds(g2, format(from)).getWidth(), getStrBounds(g2, format(to)).getWidth());
                    double dunit = h / (to - from);
                    for (int i = 0; i <= (to - from) / major; i++) {
                        g2.draw(new Line2D.Double(0, h - i * major * dunit, w - max, h - i * major * dunit));
                        if (i < (to - from) / major && minor > 0) {
                            for (int j = 1; j < major / minor; j++) {
                                g2.draw(new Line2D.Double(0, h - (i * major + j * minor) * dunit, (w - max) / 2, h - (i * major + j * minor) * dunit));
                            }
                        }
                    }
                    if (value.length() > 0) {
                        double val = toDouble(value);
                        GeneralPath p = new GeneralPath();
                        p.moveTo((w - max) / 2, h - (val - from) * dunit);
                        p.lineTo(w - max, h - (val - from) * dunit - 4);
                        p.lineTo(w - max, h - (val - from) * dunit + 4);
                        p.closePath();
                        g2.fill(p);
                    }
                }
            }
        }
        if (to > from) {
            if (major > 0) {
                if (type.startsWith("ring") || type.equals("circle")) {
                    double angle;
                    double angleStart;
                    if (type.equals("circle")) {
                        angle = 360;
                        angleStart = Math.PI / 2;
                    } else {
                        angle = toDouble(type.substring(4));
                        angleStart = (180 + (angle - 180) / 2) / 180 * Math.PI;
                    }
                    double r = angle <= 180 ? Math.min(w / 2, h) : Math.min(w / 2, h / 2);
                    double voff = angle <= 180 ? 0 : r;
                    double dunit = (angle / 180 * Math.PI) / (to - from);
                    int xoff = 0;
                    int yoff = 0;
                    double strAngle;
                    for (int i = type.equals("circle") ? 1 : 0; i <= (to - from) / major; i++) {
                        String str;
                        str = format(from + i * major);
                        strAngle = (angleStart - i * major * dunit + Math.PI * 2) % (Math.PI * 2);
                        xoff = 0;
                        yoff = 0;
                        if (strAngle >= 0 && strAngle < Math.PI * 0.25) {
                            xoff = (int) -getStrBounds(g2, str).getWidth();
                            yoff = fontSize / 2;
                            if (strAngle == 0 && angle == 180) {
                                yoff = 0;
                            }
                        } else if (near(strAngle, Math.PI * 0.5)) {
                            xoff = (int) -getStrBounds(g2, str).getWidth() / 2;
                            yoff = fontSize;
                        } else if (strAngle >= Math.PI * 0.25 && strAngle < Math.PI * 0.5) {
                            xoff = (int) -getStrBounds(g2, str).getWidth();
                            yoff = fontSize;
                        } else if (strAngle >= Math.PI * 0.5 && strAngle < Math.PI * 0.75) {
                            yoff = fontSize;
                        } else if (strAngle >= Math.PI * 0.75 && strAngle < Math.PI) {
                            yoff = fontSize / 2;
                        } else if (near(strAngle, Math.PI)) {
                            xoff = 1;
                            yoff = fontSize / 2;
                            if (angle == 180) {
                                yoff = 0;
                            }
                        } else if (strAngle >= Math.PI && strAngle < Math.PI * 1.25) {
                            yoff = fontSize / 4;
                        } else if (near(strAngle, Math.PI * 1.5)) {
                            xoff = (int) -getStrBounds(g2, str).getWidth() / 2;
                        } else if (strAngle >= Math.PI * 1.5 && strAngle < Math.PI * 2) {
                            xoff = (int) -getStrBounds(g2, str).getWidth();
                        }
                        g2.drawString(str, (int) (Math.cos(strAngle) * r * 0.75 + w / 2) + xoff, (int) (h - voff - Math.sin(strAngle) * r * 0.75) + yoff);
                    }
                    g2.setFont(new Font("", Font.BOLD, VALUE_FONT_SIZE));
                    if (value.length() > 0) {
                        voff = angle <= 180 ? 10 : r - fontSize / 2;
                        drawValue(g2, value + unit, (int) (w / 2 - getStrBounds(g2, value).getWidth() / 2), (int) (h - voff));
                    }
                } else {
                    if (w > h) {
                        double dunit = w / (to - from);
                        int off = 0;
                        String str;
                        for (int i = 0; i <= (to - from) / major; i++) {
                            str = format(from + i * major);
                            if (i == 0) {
                                str += unit;
                                off = 0;
                            } else if (i == (to - from) / major) {
                                off = (int) -getStrBounds(g2, str).getWidth();
                            } else {
                                off = (int) (-getStrBounds(g2, str).getWidth() / 2);
                            }
                            g2.drawString(str, (int) (i * major * dunit) + off, (int) (h - 2));
                        }
                        if (value.length() > 0) {
                            double val = toDouble(value);
                            value = format(val);
                            if (val == from) {
                                off = 0;
                            } else if (val == to) {
                                off = (int) -getStrBounds(g2, value + unit).getWidth();
                            } else {
                                off = (int) (-getStrBounds(g2, value + unit).getWidth() / 2);
                            }
                            if ((h - fontSize) / 2 >= fontSize) {
                                drawValue(g2, value + unit, (int) ((val - from) * dunit) + off, (int) ((h - fontSize) / 2));
                            } else {
                                drawValue(g2, value + unit, (int) ((val - from) * dunit) + off, fontSize);
                            }
                        }
                    } else {
                        double dunit = h / (to - from);
                        int max = (int) Math.max(getStrBounds(g2, format(from)).getWidth(), getStrBounds(g2, format(to)).getWidth());
                        int off = 0;
                        for (int i = 0; i <= (to - from) / major; i++) {
                            if (i == 0) {
                                off = 0;
                            } else if (i == (to - from) / major) {
                                off = fontSize;
                            } else {
                                off = fontSize / 2;
                            }
                            g2.drawString(format(from + i * major), (int) (w - max + 1), (int) (h - i * major * dunit) + off);
                        }
                        if (unit.length() > 0) {
                            g2.drawString(unit, (int) ((w - max) / 2 + 1), (int) (h - fontSize));
                        }
                        if (value.length() > 0) {
                            double val = toDouble(value);
                            value = format(val);
                            if (val == 0) {
                                off = 0;
                            } else if (val == to) {
                                off = VALUE_FONT_SIZE;
                            } else {
                                off = VALUE_FONT_SIZE / 2;
                            }
                            drawValue(g2, value + unit, (int) ((w - getStrBounds(g2, value + unit).getWidth()) / 2), (int) (h - (val - from) * dunit + off));
                        }
                    }
                }
            }
        }
    }
    private void drawValue(Graphics2D g2, String value, int x, int y) {
        g2.setFont(new Font(Font.SERIF, Font.BOLD, VALUE_FONT_SIZE));
        g2.drawString(value, x, y);
    }
    private String format(double d) {
        if ((int) d == d) {
            return String.valueOf((int) d);
        } else {
            return String.valueOf(d);
        }
    }
    private double toDouble(String string) {
        try {
            return Double.valueOf(string);
        } catch (Exception e) {
            return 0;
        }
    }
    private boolean near(double d1, double d2) {
        return Math.round(d1 * 1000000) == Math.round(d2 * 1000000);
    }
    private static Rectangle2D getStrBounds(Graphics2D g, String str) {
        Font f = g.getFont();
        Rectangle2D rect = f.getStringBounds(str, g.getFontRenderContext());
        if (rect.getHeight() < f.getSize()) {
            rect.setFrame(rect.getX(), rect.getY(), rect.getWidth(), f.getSize() + 1);
        }
        return rect;
    }
    public static void main(String[] args) {
        try {
            JFrame f = new JFrame("刻度盘测试");
            Container p = f.getContentPane();
            Tick tick;
            tick = new Tick();
            tick.setType(Tick.LINE);
            tick.setValue("3");
            tick.setUnit("CM");
            p.add(tick, BorderLayout.NORTH);
            tick = new Tick();
            tick.setType(Tick.LINE);
            p.add(tick, BorderLayout.WEST);
            JPanel panel = new JPanel(new GridLayout(2, 2));
            tick = new Tick();
            tick.setForeground(Color.BLUE);
            tick.setType(Tick.RING_120);
            tick.setValue("3.5");
            tick.setUnit("A");
            panel.add(tick);
            tick = new Tick();
            tick.setType(Tick.RING_180);
            tick.setValue("6");
            tick.setUnit("V");
            panel.add(tick);
            tick = new Tick();
            tick.setType(Tick.RING_240);
            tick.setValue("3");
            tick.setUnit("Kg");
            panel.add(tick);
            tick = new Tick();
            tick.setType(Tick.CIRCLE);
            tick.setValue("3");
            tick.setUnit("Kg");
            tick.setBackground(Color.BLACK);
            tick.setForeground(Color.WHITE);
            panel.add(tick);
            p.add(panel, BorderLayout.CENTER);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setSize(640, 480);
            f.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


超轻量Swing仪表盘组件
            
    
    
        Swing仪表盘 

虽然很简单,但放入XDoc中小虫就变小龙了,看看在XDoc中的表现吧:

超轻量Swing仪表盘组件
            
    
    
        Swing仪表盘 
  • 超轻量Swing仪表盘组件
            
    
    
        Swing仪表盘 
  • 大小: 59.7 KB
  • 超轻量Swing仪表盘组件
            
    
    
        Swing仪表盘 
  • 大小: 72.9 KB
  • 超轻量Swing仪表盘组件
            
    
    
        Swing仪表盘 
  • 大小: 81 KB
相关标签: Swing 仪表盘