简体   繁体   English

如何在Java Swing Gui中创建圆形和复杂的插图元素?

[英]How to create rounded and complex illustrated elements in Java Swing Gui?

Following the previously asked question I now face the task of creating this sophisticated illustration for the company's software: 回答先前提出的问题之后,我现在面临着为公司的软件创建这个复杂的插图的任务:

在此处输入图片说明

This is a Dynamic diagram which contains varying data. 这是一个动态图,其中包含变化的数据。 Those 3 lines are not just an example and there can actually be any number between 1 line and 32 lines. 这3行不只是示例,实际上1行和32行之间可以有任何数字。 The numeric data above them also may change constantly and dynamically as the application lingers on. 随着应用程序的持续运行,它们上方的数字数据也可能会不断发生动态变化。

I have a graphic designer at my disposal, but I'm not sure how can I use her help with this task. 我有一名平面设计师可以使用,但是我不确定如何使用她的帮助。 on the previous question that I linked above, I eventually used a grid of JPanels which I had graphics place over them as JLabels. 在上面链接的上一个问题上,我最终使用了一个JPanels网格,将图形放置在它们上面作为JLabel。 But this task is dealing with rounded and unrectangular shapes. 但是此任务处理的是圆形和矩形。 I don't see how I can have the big circle over a JPanel and have those lines over different adjacent JPanels because of the rounded shape of the circle. 我看不到如何在JPanel上有一个大圆圈,并由于圆角的圆形而在不同的相邻JPanels上有那些线。

Any ideas how can I manipulate this kind of graphics? 有什么想法可以处理这种图形吗? this entire structure should reside over a JFrame or a JPanel but that is not an issue. 整个结构应该驻留在JFrame或JPanel上,但这不是问题。

I am willing to work hard and learn new skills in order to do this. 为此,我愿意努力学习新技能。

Thank you for any comment or insight. 感谢您的任何评论或见解。

Demo code for you check it out if it helps you to implement you for software design. 您的演示代码将检查出它是否有助于您实现软件设计。 I used graphics2D which comes with java. 我使用了Java随附的graphics2D。 This is static JFrame. 这是静态的JFrame。 But you can program it dynamic implementation of this design. 但是您可以对其进行编程以动态实现此设计。

测试图像的解决方案

As you can see if remove all colors form picture then it's same design. 如您所见,如果从图片上删除所有颜色,则它是相同的设计。 But you can use also gray-scale to provide all your color effect to this example. 但是您也可以使用灰度为该示例提供所有色彩效果。 I have added few random code so one you see dotted line are generated randomly. 我添加了一些随机代码,因此您会看到虚线是随机生成的。 So here is code that created, 这是创建的代码,

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;
    }

}

In principle a JPanel that does the drawing of a graph: items and connections between them. 原则上,JPanel执行图形绘制:项目及其之间的连接。 These graph elements can be own classes. 这些图元素可以是自己的类。

One idea is to consider SVG (Scalable Vector Graphics) , an XML notation for such graphs, and JAXB with annotations to map XML to objects. 一种想法是考虑使用SVG(可伸缩矢量图形) ,这种图形的XML表示法,以及带有将XML映射到对象的注释的JAXB The designer may help produce elements with a GUI editor which helps in the numerical details. 设计人员可以使用GUI编辑器来帮助生成元素,而GUI编辑器可以帮助提供数字细节。 Unfortunately SVG is rather concrete. 不幸的是,SVG是相当具体的。 Painting and things like rotation you will need to fill in. You might opt for more abstract coding, but an SVG definition of an element might help. 绘画和诸如旋转之类的东西将需要填写。您可能会选择更抽象的编码,但是元素的SVG定义可能会有所帮助。 There are at least two java SVG libraries. 至少有两个Java SVG库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM