【问题标题】:How to create rounded and complex illustrated elements in Java Swing Gui?如何在 Java Swing Gui 中创建圆润复杂的插图元素?
【发布时间】:2014-12-25 10:35:34
【问题描述】:

previously asked question 之后,我现在面临为公司软件创建这个复杂插图的任务:

这是一个包含变化数据的动态图。这 3 行不仅仅是一个示例,实际上可以有 1 行到 32 行之间的任何数字。它们上面的数字数据也可能随着应用程序的运行而不断动态变化。

我有一位平面设计师可供我使用,但我不确定如何使用她的帮助来完成这项任务。 在我上面链接的上一个问题上,我最终使用了一个 JPanel 网格,我在它们上面放置了图形作为 JLabels。但这项任务是处理圆形和非矩形形状。 由于圆形是圆形的,我不知道如何在 JPanel 上放置大圆圈并将这些线放在不同的相邻 JPanel 上。

任何想法如何操作这种图形?这整个结构应该驻留在 JFrame 或 JPanel 上,但这不是问题。

为了做到这一点,我愿意努力工作并学习新技能。

感谢您的任何评论或见解。

【问题讨论】:

  • 我认为您将需要免费获得并且对 Graphics2D 非常友好
  • 还可以考虑使用jfreechart 自定义AbstractRenderer

标签: java swing graphics jpanel rounding


【解决方案1】:

为您提供的演示代码查看它是否有助于您实现软件设计。 我使用了java自带的graphics2D。 这是静态 JFrame。但是你可以通过编程来动态实现这个设计。

如您所见,如果从图片中删除所有颜色,那么它是相同的设计。但是你也可以使用灰度来为这个例子提供你所有的颜色效果。 我添加了一些随机代码,所以你看到的虚线是随机生成的。 所以这是创建的代码,

package Stakeoverflow.swingFrame;

/**
 *
 * @author Naimish
 */
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class ShapeTest extends JFrame {

    private static final long serialVersionUID = 1L;
    private int width = 300;
    private int height = 300;
    private int padding = 50;
    private BufferedImage graphicsContext;
    private JPanel contentPanel = new JPanel();
    private JLabel contextRender;
    private Stroke dashedStroke = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 2f, new float[] {3f, 3f}, 0f);
    private Stroke solidStroke = new BasicStroke(3.0f);
    private RenderingHints antialiasing;
    private Random random = new Random();

    public static void main(String[] args) {
        //you should always use the SwingUtilities.invodeLater() method
        //to perform actions on swing elements to make certain everything
        //is happening on the correct swing thread
        Runnable swingStarter = new Runnable()
        {
            @Override
            public void run(){
                new ShapeTest();
            }
        };

        SwingUtilities.invokeLater(swingStarter);
    }

    public ShapeTest(){
        antialiasing = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphicsContext = new BufferedImage(width + (2 * padding), width + (2 * padding), BufferedImage.TYPE_INT_RGB);
        contextRender = new JLabel(new ImageIcon(graphicsContext));

        contentPanel.add(contextRender);
        contentPanel.setSize(width + padding * 2, height + padding * 2);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setContentPane(contentPanel);
        //take advantage of auto-sizing the window based on the size of its contents
        this.pack();
        this.setLocationRelativeTo(null);
        this.paint();
        setVisible(true);
    }

    public void paint() {

        Graphics2D g2d = graphicsContext.createGraphics();
        g2d.setRenderingHints(antialiasing);

        //Set up the font to print on the circles
        Font font = g2d.getFont();
        font = font.deriveFont(Font.BOLD, 14f);
        g2d.setFont(font);

        //clear the background
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, graphicsContext.getWidth(), graphicsContext.getHeight());

        //set up the large circle
        Point2D largeCircleCenter = new Point2D.Double((double)width / 2 + padding, (double)height / 5 + padding);
        double largeCircleRadius = (double)width / 5;
        Ellipse2D largeCircle = getCircleByCenter(largeCircleCenter, largeCircleRadius);

        //here we build the small circle
        Point2D smallCircleCenter = new Point2D.Double();
        double smallCircleRadius = 15;

        //the resulting end point of the vector is a random distance from the center of the large circle
        //in a random direction, and guaranteed to not place the small circle outside the large
        smallCircleCenter.setLocation(largeCircleCenter);
        Ellipse2D smallCircle = getCircleByCenter(smallCircleCenter, smallCircleRadius);

        //before we draw any of the circles or lines, set the clip to the large circle
        //to prevent drawing outside our boundaries
        // -- g2d.setClip(largeCircle);



        //chose a random angle for the line through the center of the small circle
        double angle = random.nextDouble() * 360.0d;
        //we create two lines that start at the center and go out at the angle in
        //opposite directions. We use 2*largeCircleRadius to make certain they
        //will be large enough to fill the circle, and the clip we set prevent stray
        //marks outside the big circle
        Line2D centerLine1 = getVector(smallCircleCenter, angle, largeCircleRadius * 2);
        Line2D centerLine2 = getVector(smallCircleCenter, angle, -largeCircleRadius * 2);

        Line2D centerLine90 = getVector(smallCircleCenter, 45, 200);
        // set line width
        g2d.setStroke(new BasicStroke(5));
        g2d.setColor(Color.RED);
        g2d.draw(centerLine90);

        Ellipse2D lineEndCircle = getCircleByCenter(centerLine90.getP2(), smallCircleRadius + 10);
        g2d.setStroke(new BasicStroke(2));
        g2d.setColor(Color.BLUE);
        g2d.draw(lineEndCircle);

        // Level 3 Circales 

        Point2D endCir = centerLine90.getP2();
        Line2D centerLine5 = getVector(endCir, 90, smallCircleRadius+30);
        g2d.setColor(Color.black);
        g2d.draw(centerLine5);


        Ellipse2D lineEndCircle2 = getCircleByCenter(centerLine5.getP2(), smallCircleRadius - 5);
        g2d.setStroke(new BasicStroke(2));
        g2d.setColor(Color.BLUE);
        g2d.draw(lineEndCircle2);
        g2d.fill(lineEndCircle2);

        Line2D centerLine6 = getVector(endCir,0, smallCircleRadius+30);
        g2d.setColor(Color.black);
        g2d.draw(centerLine6);


        Ellipse2D lineEndCircle3 = getCircleByCenter(centerLine6.getP2(), smallCircleRadius - 5);
        g2d.setStroke(new BasicStroke(2));
        g2d.setColor(Color.BLUE);
        g2d.draw(lineEndCircle3);
        g2d.fill(lineEndCircle3);

        //now we just add 20 and 120 to our angle for the center-line, start at the center
        //and again, use largeCircleRadius*2 to make certain the lines are big enough
        Line2D sightVector1 = getVector(smallCircleCenter, angle + 60, largeCircleRadius * 2);
        Line2D sightVector2 = getVector(smallCircleCenter, angle + 120, largeCircleRadius * 2);

        //fill the small circle with blue
        g2d.setColor(Color.BLUE);
        g2d.fill(smallCircle);

        //draw the two center lines lines
        g2d.setStroke(dashedStroke);
        g2d.draw(centerLine1);
        g2d.draw(centerLine2);



        //create and draw the black offset vector
        Line2D normalVector = getVector(smallCircleCenter, angle + 90, largeCircleRadius * 2);
        g2d.setColor(Color.black);
        g2d.draw(normalVector);

        //draw the offset vectors
        g2d.setColor(new Color(0, 200, 0));
        g2d.draw(sightVector1);
        g2d.draw(sightVector2);


        //we save the big circle for last, to cover up any stray marks under the stroke
        //of its perimeter. We also set the clip back to null to prevent the large circle
        //itselft from accidentally getting clipped
        g2d.setClip(null);
        g2d.setStroke(solidStroke);
        g2d.setColor(Color.BLACK);
        g2d.draw(largeCircle);

        g2d.dispose();
        //force the container for the context to re-paint itself
        contextRender.repaint();

    }

    private static Line2D getVector(Point2D start, double degrees, double length){
        //we just multiply the unit vector in the direction we want by the length
        //we want to get a vector of correct direction and magnitute
        double endX = start.getX() + (length * Math.sin(Math.PI * degrees/ 180.0d));
        double endY = start.getY() + (length * Math.cos(Math.PI * degrees/ 180.0d));
        Point2D end = new Point2D.Double(endX, endY);
        Line2D vector = new Line2D.Double(start, end);
        return vector;
    }

    private static Ellipse2D getCircleByCenter(Point2D center, double radius)
    {
        Ellipse2D.Double myCircle = new Ellipse2D.Double(center.getX() - radius, center.getY() - radius, 2 * radius, 2 * radius);
        return myCircle;
    }

}

【讨论】:

    【解决方案2】:

    原则上,一个 JPanel 绘制图形:项目和它们之间的连接。这些图形元素可以是自己的类。

    一个想法是考虑SVG (Scalable Vector Graphics),这是一种用于此类图的XML 表示法,以及带有将XML 映射到对象的注解的JAXB。设计者可以使用 GUI 编辑器帮助生成元素,该编辑器有助于数字细节。不幸的是,SVG 相当具体。您需要填写绘画和旋转之类的内容。您可能会选择更抽象的编码,但元素的 SVG 定义可能会有所帮助。至少有两个 java SVG 库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-07
      • 2012-01-27
      • 1970-01-01
      相关资源
      最近更新 更多