简体   繁体   English

如何使用Graphics Class从顶点到顶点绘制一条线?

[英]How to draw a line from vertex to vertex using Graphics Class?

I am trying to draw a line from each node graphics object to another node graphics object if and only if there exists an edge between the two nodes. 我尝试从每个节点图形对象绘制一条线到另一个节点图形对象,当且仅当两个节点之间存在边缘时。

My graph is implemented inside a 2-dimensional boolean adjacency matrix. 我的图是在2维布尔邻接矩阵中实现的。

How would I implement this? 我该如何实现?

Here is what I have so far: 这是我到目前为止:

// Draw method which will draw the shape of the graph.
    public void paint(Graphics g) {

        //Define parameters to draw the graph in. Example taken from
        //http://www.zetcode.com/gfx/java2d/basicdrawing/
        Dimension size = getSize();
        Insets insets = getInsets();

        int w = size.width - insets.left - insets.right;
        int h = size.height - insets.top - insets.bottom;

        //Parameters for vertices, to be used later to draw vertices.
        int x = 0;
        int y = 0;

        // Extend to Graphics 2D
        Graphics2D graph = (Graphics2D) g;

        // Set preferences. This cleans up edges.
        graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        //Generate vertices as random points on JPanel.
        Random r = new Random();

        //Draw random points on JPanel for the vertices.
        for (int l = 0; l < adj_Matrix_Edges.length; l++){
            String str = Integer.toHexString(l);
            //Define where a specific vertex will fall on a x, y coordinate
            //inside the container.
            x = Math.abs(r.nextInt()) % w;
            y = Math.abs(r.nextInt()) % h;
            //Initialize a node graphics object to represent vertices.
            Graphics2D node = (Graphics2D)g;
            node.fillOval(x, y, 7, 7); //Creates filled ovals for nodes.
            graph.drawString(str, x, y + 20);
        }

            //Create a nexted for loop to see if there is an edge between vertices.
        for (int m = 0; m < adj_Matrix_Edges.length; m++){
            for (int n = 0; m < adj_Matrix_Edges[m].length; m++){
                if (adj_Matrix_Edges[m][n]){
                    graph.drawLine(node, y1, x2, y2);
                }
            }
        }

    }
}

As MadProgrammer already mentioned, the drawing process in a class that inherits from JComponent is usually done in the paintComponent method: 正如MadProgrammer已经提到的,继承自JComponent的类中的绘制过程通常在paintComponent方法中完成:

@Override
protected void paintComponent(Graphics gr)
{
    super.paintComponent(gr);
    Graphics2D g = (Graphics2D)g;

    // Your drawing stuff goes here....
}

But regarding the actual question: I assume that you want to draw a graph (or more precisely: A node-link diagram). 但关于实际问题:我假设你想绘制一个图形(或更确切地说:一个节点链接图)。 There are many, many sophisticated libraries for this task. 这项任务有许多很复杂的库。 And for all but the simplest application, I'd strongly recommend to use such a library, because doing this manually may become rather tricky. 除了最简单的应用程序之外,我强烈建议使用这样的库,因为手动执行此操作可能会变得相当棘手。

However, the main problem at the moment is that you are creating new random points each time that the component is repainted! 但是,目前的主要问题是每次重新绘制组件时都要创建新的随机点! I wonder what this looks like. 我想知道这是什么样的。 You should see oddly flickering points when you resize the component. 调整组件大小时,您应该会看到奇怪的闪烁点。

You'll have to somehow store the points (their coordinates), so that you may draw lines between these points later. 你必须以某种方式存储点(它们的坐标),以便稍后可以在这些点之间绘制线条。

It is possible to do this with very few modifications to your code: 只需对代码进行少量修改即可完成此操作:

//Generate vertices as random points on JPanel.
// Pass "0" as the argument to the constructor of Random, so that it 
// will always create the same sequence of random numbers
Random r = new Random(0);

// Create lists that will store the point coordinates
List<Integer> pointsX = new ArrayList<Integer>();
List<Integer> pointsY = new ArrayList<Integer>();

for (int l = 0; l < adj_Matrix_Edges.length; l++){
    String str = Integer.toHexString(l);
    //Define where a specific vertex will fall on a x, y coordinate
    //inside the container.
    x = Math.abs(r.nextInt()) % w;
    y = Math.abs(r.nextInt()) % h;

    // Store the coordinates of the points:
    pointsX.add(x);
    pointsY.add(y);

    //Initialize a node graphics object to represent vertices.
    Graphics2D node = (Graphics2D)g;
    node.fillOval(x, y, 7, 7); //Creates filled ovals for nodes.
    graph.drawString(str, x, y + 20);
}

//Create a nexted for loop to see if there is an edge between vertices.
for (int m = 0; m < adj_Matrix_Edges.length; m++){
    for (int n = 0; m < adj_Matrix_Edges[m].length; m++){
        if (adj_Matrix_Edges[m][n]){

            // Fetch the coordinates of the points from the list
            int xm = pointsX.get(m);
            int ym = pointsY.get(m);
            int xn = pointsX.get(n);
            int yn = pointsY.get(n);
            graph.drawLine(xm,ym,xn,yn);
        }
    }
}

But I do NOT recommend to do it like this. 但我建议像这样做。 That's only a quick hack to show how this may be achieved with minimal modifications to your code. 这只是一个快速的黑客,以显示如何通过对代码的最小修改来实现这一目标。 In general, you should NOT build any data structures while painting. 在一般情况下,你应该建立在绘制任何数据结构。 The painting code should be as short and as simple as possible. 绘画代码应尽可能简短。

Instead, you should create a data structure that represents your nodes when you initialize your adjacency matrix. 相反,您应该在初始化邻接矩阵时创建表示节点的数据结构。 You could at least create some class like 你至少可以创建一些类

class Node
{
    String name;
    // Coordinates, between 0 and 1
    double x;
    double y;
}

And where the adj_Matrix_Edges is declared and initialized, you could also create a list of nodes, like this: 在声明和初始化adj_Matrix_Edges地方,您还可以创建节点列表,如下所示:

boolean adj_Matrix_Edges[][];
List<Node> nodes;

void initializeMatrix()
{
    adj_Matrix_Edges = ...;

    // Create the nodes
    Random random = new Random(0);
    nodes= new ArrayList<Node>();
    for (int m = 0; m < adj_Matrix_Edges.length; m++)
    {
        Node node= new Node();
        node.name = Integer.toHexString(m);
        node.x = random.nextDouble(); 
        node.y = random.nextDouble(); 
        nodes.add(node);
    }
}

Later, when you paint, you can access these nodes and paint them direcly: 稍后,在绘制时,您可以访问这些节点并直接绘制它们:

@Override
protected void paintComponent(Graphics gr)
{
    super.paintComponent(gr);
    Graphics2D g = (Graphics2D)g;

    for (int l = 0; l < adj_Matrix_Edges.length; l++){

        // Compute the x- and y-coordinates that the
        // node will have in this component. (That's 
        // why the coordinates that are stored in 
        // the "Node" class should always be 
        // between 0 and 1!)

        Node node = nodes.get(l);
        int ix = (int)(node.x * getWidth());
        int iy = (int)(node.y * getHeight());

        g.fillOval(ix, iy, 7, 7);
        graph.drawString(node.name, ix, iy + 20);
    }

    //Create a nested for loop to see if there is an edge between vertices.
    for (int m = 0; m < adj_Matrix_Edges.length; m++){
        for (int n = 0; m < adj_Matrix_Edges[m].length; m++){
            if (adj_Matrix_Edges[m][n]){

                Node nodeM = nodes.get(m);                    
                Node nodeN = nodes.get(n);
                int xm = (int)(nodeM.x * getWidth());
                int ym = (int)(nodeM.y * getHeight());
                int xn = (int)(nodeN.x * getWidth());
                int yn = (int)(nodeN.y * getHeight());
                graph.drawLine(xm,ym,xn,yn); 
            }
        }
    }
 }

Usually, you will also have a representation of the edges that is similar to the Node class that I sketched above, but then you are slowly approaching the complexities that justify to use a library like JUNG http://jung.sourceforge.net/ or JGraphX https://github.com/jgraph/jgraphx (There are many graph libraries out there, and these are probably two of the most popular ones, but should only be considered as examples here) 通常,您还将获得与我上面概述的Node类相似的边的表示,但是您正在慢慢接近使用像JUNG http://jung.sourceforge.net/这样的库的复杂性。 JGraphX https://github.com/jgraph/jgraphx (那里有很多图库,这些可能是最受欢迎的图库之一,但这里只应作为例子)

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

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