在两个java图形之间画一条可移动的线

时间:2023-02-04 15:52:08

在两个java图形之间画一条可移动的线

The stickman is connected to the bubble by a line. When I move for example, Jimmy, I want the line that connects Jimmy to the Fruits he sells to be maintained. The same goes when I drag Fruit.

粘粘剂通过一条线与气泡相连。举个例子,吉米,我想把吉米和他卖的水果联系起来。我拖水果的时候也是一样。

But somehow this is not working. When I drag the stickman or the bubble, the lines got disjointed. 在两个java图形之间画一条可移动的线

但不知何故,这行不通。当我拖动粘稠剂或气泡时,线条会脱节。

Here are my codes if anyone would like to try and run it. I've tried to include only the relevant stuffs.

这是我的代码,如果有人想尝试运行它。我尽量只写相关的资料。

Example class

示例类

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example extends JPanel {

private static List<Person> persons;
private static List<Fruit> fruits;
private static List<LineTest> lines;
private Point mousePt;
private static Font setFont;
private Random randomGenerator;
private Person person;
private Fruit bubble;
private LineTest line;
private static final int W = 640;    
private static final int H = 480; 

public Example() {
    persons = new ArrayList<Person>();  // Stores the person's names & coords
    fruits = new ArrayList<Fruit>(); // Stores the person's name and what fruits he sells & coords
    lines = new ArrayList<LineTest>(); // Stores the person's name, fruits he sells & coords
    randomGenerator = new Random();
    setFont = new Font("Sans Serif", Font.BOLD, 12);

    String person1 = "Jimmy";
    String person2 = "Sally";

    person = new Person(person1, 50,50);
    addPerson(person);
    person = new Person(person2, 50,150);
    addPerson(person);

    String fruit1 = "Banana";
    String fruit2 = "Apple";
    String fruit3 = "Orange";
    String fruit4 = "Watermelon";
    String fruit5 = "Pineapple";
    String fruit6 = "Grapes";

    bubble = new Fruit(person1, fruit1, setFont, 150, 50);
    addFruit(bubble);
    bubble = new Fruit(person1, fruit2, setFont, 150, 100);
    addFruit(bubble);
    bubble = new Fruit(person1, fruit3, setFont, 150, 150);
    addFruit(bubble);
    bubble = new Fruit(person2, fruit4, setFont, 150, 200);
    addFruit(bubble);
    bubble = new Fruit(person2, fruit5, setFont, 150, 250);
    addFruit(bubble);
    bubble = new Fruit(person2, fruit6, setFont, 150, 300);
    addFruit(bubble);

    for (int i=0; i<persons.size();i++) {
        for (int j=0; j<fruits.size();j++) {
            // If the same person in the person's list can be found in the fruits list
            // draw a line between the Person and the Fruit
            if (persons.get(i).getPerson().equals((fruits.get(j).getPerson()))) {
                int personX = persons.get(i).getCoorX();
                int personY = persons.get(i).getCoorY();
                int fruitX = fruits.get(j).getCoorX();
                int fruitY = fruits.get(j).getCoorY();
                line = new LineTest(persons.get(i).getPerson(), fruits.get(j).getFruit(), personX, personY, fruitX, fruitY);
                addLine(line);
            }
        }
    } 

    this.setFont(setFont);    
    this.addMouseListener(new MouseAdapter() {    
        @Override    
        public void mousePressed(MouseEvent e) {    
            mousePt = e.getPoint();  
            for (Person p:persons) {  
                p.select(mousePt.x, mousePt.y);
            }  

            for (Fruit f:fruits) {
                f.select(mousePt.x, mousePt.y);
            }
        }  

        public void mouseReleased(MouseEvent e) {  
            for (Person p:persons) {
                p.unselect();
            }

            for(Fruit f:fruits) {
                f.unselect();
            }
        }  
    });    
    this.addMouseMotionListener(new MouseMotionAdapter() {    

        @Override    
        public void mouseDragged(MouseEvent e) {    
            mousePt = e.getPoint();  
            for (Person s:persons) {
                s.move(mousePt.x, mousePt.y);
                int personX = mousePt.x;
                int personY = mousePt.y;
                for(int k=0; k<lines.size(); k++) {
                    // If the same person in the person's list can be found in the fruits list
                    // move the point on the Person to a new coords
                    if(s.person.equals(lines.get(k).person)) {
                        lines.get(k).move(personX, personY);
                    }
                }
            }

            for(Fruit f:fruits) {
                f.move(mousePt.x, mousePt.y);
                int fruitX = mousePt.x;
                int fruitY = mousePt.y;
                for(int k=0; k<lines.size(); k++) {
                    if(f.person.equals(lines.get(k).person)) {
                        lines.get(k).move(fruitX, fruitY);
                    }
                }
            }
            repaint();    
        }    
    }); 
}

public void addPerson(Person person) {    
    persons.add(person);  
    repaint();    
} 

public void addFruit (Fruit fruit) {    
    fruits.add(fruit);    
    repaint();    
} 

public void addLine(LineTest line) {
    lines.add(line);
    repaint();
}

@Override    
public void paintComponent(Graphics g) {    
    super.paintComponent(g);  
    Graphics2D g2 = (Graphics2D)g.create();

    for (Person p:persons) {    
        p.paint(g2); 
    }   
    for (LineTest l:lines) {
        l.paint(g2);
    }
    for (Fruit f:fruits) {    
        f.paint(g2);
    } 
}    

@Override    
public Dimension getPreferredSize() {    
    return new Dimension(W, H);    
}    

public static void main(String[] args) {    
    EventQueue.invokeLater(new Runnable() {    
        @Override    
        public void run() {    
            JFrame f = new JFrame();    
            f.add(new Example());    
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
            f.pack();    
            f.setLocationRelativeTo(null);    
            f.setVisible(true);     
        }    
    });    
}    
}

Person class

Person类

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;

public class Person extends Rectangle {    
String person;
int x,y;  
int tx, ty;  
boolean isSelected = false;

public Person(String person, int x, int y) {  
    this.person = person;
    this.x = x;  
    this.y = y; 
    this.setBounds(x-10,y-10,40,90);

    isSelected = true;  
    move(x, y);  
    isSelected = false;  
}  

public void select(int x, int y){
    if(this.contains(x,y)) {
        isSelected=true; 
    } 
}  

public void unselect(){  
    isSelected = false;  
}

public void move(int x, int y) {  
    if(isSelected) {  
        LineTest.isPersonMoved = true;
        LineTest.isFruitMoved = false;
        tx = x;  
        ty= y;  
        this.translate(tx-this.x, ty-this.y); 
        this.x = tx;  
        this.y = ty;  
    }  
}  

public void paint(Graphics g) {  
    Graphics2D g2 = (Graphics2D)g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.drawOval(x, y, 20, 20); // head
    g2.drawLine(x+10,y+20,x+10,y+50); // body
    g2.drawLine(x+10,y+20,x+25,y+40); // right hand
    g2.drawLine(x+10,y+20,x-5,y+40); // left hand
    g2.drawLine(x+10,y+50,x-5,y+70); // left leg
    g2.drawLine(x+10,y+50,x+25,y+70); // right leg
    g2.drawString(person, tx-15, ty+85);
}  

public String getPerson() {
    return person;
}

public int getCoorX() {
    return x;
}

public int getCoorY() {
    return y;
}
} 

Fruit class

水果类

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;

public class Fruit extends Rectangle {

private static final long serialVersionUID = 1L;
String fruit, person;
Font _font;
int x, y, tx, ty;
public static int height, width, ovalWidth, ovalHeight;
boolean isSelected;
public static FontMetrics getMetrics;
public static Graphics2D g2;

public Fruit(String person, String fruit, Font font, int x, int y) {
    this.person = person;
    this.fruit = fruit;
    this._font = font;
    this.x = x;
    this.y = y;
    this.setBounds(x, y, ovalWidth, ovalHeight);

    isSelected = true;  
    move(x, y);  
    isSelected = false; 

}

public void select(int x, int y){
    if(this.contains(x,y)) {
        isSelected=true; 
    } 
} 

public void unselect(){  
    isSelected = false;  
}

public void move(int x, int y) {  
    if(isSelected) {  
        LineTest.isPersonMoved = false;
        LineTest.isFruitMoved = true;

        tx = x;  
        ty= y;  
        this.translate(tx-this.x, ty-this.y);
        this.x = tx;  
        this.y = ty;  
    }  
} 

public void paint(Graphics g) {
    g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    getMetrics = g2.getFontMetrics(_font);
    height = getMetrics.getHeight();
    width = getMetrics.stringWidth(fruit);

    ovalWidth = width+25;
    ovalHeight = height+25;
    g2.setColor(Color.WHITE);
    g2.fillOval(x, y, ovalWidth, ovalHeight);
    g2.setColor(Color.BLACK);
    g2.drawOval(x, y, ovalWidth, ovalHeight);

    int centreX = x + ovalWidth/2;
    int centreY = y + ovalHeight/2;
    g2.drawString(fruit, (int) (centreX - width/2), (int) (centreY + height/4));

    this.setBounds(x, y, ovalWidth, ovalHeight);
}

public String getPerson() {
    return person;
}

public String getFruit() {
    return fruit;
}

public int getCoorX() {
    return x;
}

public int getCoorY() {
    return y;
}

}

LineTest class

未漂亚麻衬布类

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;

/*
 * Draw line that connect between Person and Fruit
 */
public class LineTest {
int x1, y1, x2, y2, tx, ty;
String fruit, person;
public static boolean isPersonMoved, isFruitMoved;

public LineTest(String person, String fruit, int x1, int y1, int x2, int y2) {
    this.person = person;
    this.fruit = fruit;

    // Get x, y coordinates from person bound
    this.x1 = x1+35;
    this.y1 = y1+35;

    // Get x, y coordinates from fruit bound
    this.x2 = x2+30;
    this.y2 = y2+30;  
}

public void move(int x, int y) {
    if (isPersonMoved) {
        System.out.println("LineTest - isPersonMoved: " + isPersonMoved);
        tx = x;
        ty = y;
        this.x1 = tx+35;
        this.y1 = ty+35;
    } else if (isFruitMoved) {
        System.out.println("LineTest - isFruitMoved: " + isFruitMoved);
        tx = x;
        ty = y;
        this.x2 = tx+30;
        this.y2 = ty+30;
    }
}

public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g.create();
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.drawLine(x1, y1, x2, y2);
}

public String getPerson() {
    return person;
}

public String getFruit() {
    return fruit;
}

public Point getFstCoor() {
    return new Point (x1, y1);
}

public Point getSndCoor() {
    return new Point(x2, y2);
}
}

2 个解决方案

#1


3  

The basic idea is, you need to generate some kind of relationship between the objects you want to link. You could make this relationship implicit (Person contains Fruit) or non-implicit, where the relationship is stored/managed externally, which you do is up to you (I like the implicit approach as it sets out your intentions)

基本思想是,您需要在想要链接的对象之间生成某种关系。你可以使这种关系隐式(人包含水果)或非隐式的,关系是在外部存储/管理的,这取决于你(我喜欢隐含的方法,因为它阐明了你的意图)

Your codes a bit, odd, sorry, but it is, so I've made some modifications. I did think of using a Path2D for a lot of it, but that would mean everything code painted in the same color. The main point is to define some kind of commonality between the objects, while strictly speaking not required, because almost all the work between them is the same, why not...

你的代码有点奇怪,不好意思,我做了一些修改。我确实想过为它使用Path2D,但这意味着所有代码都使用相同的颜色。重点是在对象之间定义某种共性,但严格地说不是必需的,因为它们之间的工作几乎都是相同的,为什么不……

public interface Paintable {
    public void paint(JComponent parent, Graphics2D g2d);
    public boolean contains(Point p);
    public void moveTo(Point2D p);
    public Rectangle2D getBounds();
}

Then I created a class to manage the relationships...

然后我创建了一个类来管理关系……

public class Relationship {

    private Paintable parent;
    private Paintable child;

    public Relationship(Paintable parent, Paintable child) {
        this.parent = parent;
        this.child = child;
    }

    public Paintable getChild() {
        return child;
    }

    public Paintable getParent() {
        return parent;
    }

}

Now, this means that your fruits could belong to more then one person (or other fruits), so if this goes against your rules, you will need to devise a different relationship algorithm (maybe something more implicit)

现在,这意味着你的水果可能属于更多的人(或其他水果),所以如果这违反了你的规则,你需要设计一个不同的关系算法(也许是更含蓄的)

Now, when ever you update the UI, you simply paint the relationships and the objects...

现在,当你更新UI时,你只需要绘制关系和对象……

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g.create();

    for (Relationship relationship : relationships) {

        Point2D p1 = new Point2D.Double(relationship.getParent().getBounds().getCenterX(), relationship.getParent().getBounds().getCenterY());
        Point2D p2 = new Point2D.Double(relationship.getChild().getBounds().getCenterX(), relationship.getChild().getBounds().getCenterY());

        g2.draw(new Line2D.Double(p1, p2));

    }

    for (Person p : persons) {
        p.paint(this, g2);
    }
    for (Fruit f : fruits) {
        f.paint(this, g2);
    }

    g2.dispose();
}

在两个java图形之间画一条可移动的线

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example extends JPanel {

    private List<Person> persons;
    private List<Fruit> fruits;
    private Point2D offset;
    private static Font baseFont;
    private Random randomGenerator;
    private Person person;
    private Fruit bubble;
    private static final int W = 640;
    private static final int H = 480;

    private Paintable selectedShape;

    private List<Relationship> relationships;

    public Example() {
        persons = new ArrayList<>();  // Stores the person's names & coords
        fruits = new ArrayList<>(); // Stores the person's name and what fruits he sells & coords
        relationships = new ArrayList<>(25);

        randomGenerator = new Random();
        baseFont = new Font("Sans Serif", Font.BOLD, 12);

        String person1 = "Jimmy";
        String person2 = "Sally";


        String fruit1 = "Banana";
        String fruit2 = "Apple";
        String fruit3 = "Orange";
        String fruit4 = "Watermelon";
        String fruit5 = "Pineapple";
        String fruit6 = "Grapes";

        Person person = new Person(person1, 50, 50);
        addPerson(person);

        Fruit bubble = new Fruit(fruit1, baseFont, 150, 50);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit2, baseFont, 150, 100);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit3, baseFont, 150, 150);
        addFruit(bubble);
        relate(person, bubble);

        person = new Person(person2, 50, 150);
        addPerson(person);

        bubble = new Fruit(fruit4, baseFont, 150, 200);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit5, baseFont, 150, 250);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit6, baseFont, 150, 300);
        addFruit(bubble);
        relate(person, bubble);

        this.setFont(baseFont);
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                for (Paintable p : getShapes()) {
                    if (p.contains(e.getPoint())) {
                        // Selected
                        selectedShape = p;
                        offset = new Point2D.Double(e.getX() - p.getBounds().getX(), e.getY() - p.getBounds().getY());
                        break;
                    }
                }
            }

            public void mouseReleased(MouseEvent e) {
                selectedShape = null;
            }
        });
        this.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent e) {
                if (selectedShape != null) {

                    Point2D p = new Point2D.Double(e.getX() - offset.getX(), e.getY() - offset.getX());

                    selectedShape.moveTo(p);
                }
                repaint();
            }
        });
    }

    protected List<Paintable> getShapes() {
        ArrayList<Paintable> shapes = new ArrayList<>(fruits);
        shapes.addAll(persons);
        return shapes;
    }

    public void addPerson(Person person) {
        persons.add(person);
        repaint();
    }

    public void addFruit(Fruit fruit) {
        fruits.add(fruit);
        repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();

        for (Relationship relationship : relationships) {

            Point2D p1 = new Point2D.Double(relationship.getParent().getBounds().getCenterX(), relationship.getParent().getBounds().getCenterY());
            Point2D p2 = new Point2D.Double(relationship.getChild().getBounds().getCenterX(), relationship.getChild().getBounds().getCenterY());

            g2.draw(new Line2D.Double(p1, p2));

        }

        for (Person p : persons) {
            p.paint(this, g2);
        }
        for (Fruit f : fruits) {
            f.paint(this, g2);
        }

        g2.dispose();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(W, H);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame();
                f.add(new Example());
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }

    protected void relate(Person person, Fruit bubble) {
        relationships.add(new Relationship(person, bubble));
    }

    public class Relationship {

        private Paintable parent;
        private Paintable child;

        public Relationship(Paintable parent, Paintable child) {
            this.parent = parent;
            this.child = child;
        }

        public Paintable getChild() {
            return child;
        }

        public Paintable getParent() {
            return parent;
        }

    }

    public interface Paintable {

        public void paint(JComponent parent, Graphics2D g2d);

        public boolean contains(Point p);

        public void moveTo(Point2D p);

        public Rectangle2D getBounds();

    }

    public class Fruit implements Paintable {

        private static final long serialVersionUID = 1L;
        String fruit;
        Font font;

        private Ellipse2D bounds;

        public Fruit(String fruit, Font font, int x, int y) {
            this.fruit = fruit;
            this.font = font;
            bounds = new Ellipse2D.Double(x, y, 40, 90);
        }

        public String getFruit() {
            return fruit;
        }

        @Override
        public boolean contains(Point p) {
            return bounds.contains(p);
        }

        @Override
        public void moveTo(Point2D p) {
            bounds = new Ellipse2D.Double(p.getX(), p.getY(), 40, 90);
        }

        @Override
        public void paint(JComponent parent, Graphics2D g) {
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setFont(font);
            FontMetrics fm = g2.getFontMetrics();
            int height = fm.getHeight();
            int width = fm.stringWidth(fruit);

            g2.setColor(Color.WHITE);
            g2.fill(bounds);
            g2.setColor(Color.BLACK);
            g2.draw(bounds);

            double centreX = bounds.getX() + bounds.getWidth() / 2d;
            double centreY = bounds.getY() + bounds.getHeight() / 2d;
            g2.drawString(fruit, (int) (centreX - width / 2), (int) (centreY + height / 4));

            g2.dispose();
        }

        @Override
        public Rectangle2D getBounds() {
            return bounds.getBounds2D();
        }

    }

    public class Person implements Paintable {

        String person;
        private Rectangle2D bounds;

        public Person(String person, int x, int y) {
            this.person = person;
            bounds = new Rectangle2D.Double(x, y, 40, 90);
        }

        @Override
        public void paint(JComponent parent, Graphics2D g) {
            Graphics2D g2 = (Graphics2D) g.create();
            g2.translate(bounds.getX(), bounds.getY());
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.drawOval(0, 0, 20, 20); // head
            g2.drawLine(10, 20, 10, 50); // bodbounds.getY()
            g2.drawLine(10, 20, 25, 40); // right hand
            g2.drawLine(10, 20, 0 - 5, 40); // left hand
            g2.drawLine(10, 50, 0 - 5, 70); // left leg
            g2.drawLine(10, 50, 25, 70); // right leg
            g2.drawString(person, 0 - 15, 85);
            g2.dispose();
        }

        public String getPerson() {
            return person;
        }

        @Override
        public boolean contains(Point p) {
            return bounds.contains(p);
        }

        @Override
        public void moveTo(Point2D p) {
            bounds = new Rectangle2D.Double(p.getX(), p.getY(), 40, 90);
        }

        @Override
        public Rectangle2D getBounds() {
            return bounds.getBounds2D();
        }
    }

}

I would encourage you to have a look at Path2D, at least for the stick figure, it will make life eaiser

我鼓励你们去看一下Path2D,至少对于这个棍形图来说,它会让生活变得更美好。

#2


0  

Save the positions of a the stick man within itself and the position of the fruits within their objects. Relate each objects which are together. When a repaint() is started get the position information of the stick man and the position information of the fruit and draw a line between these two points. If a move is done then a repaint of the line should done also.

保存一个棍棒手的位置和水果的位置。把所有的物体联系在一起。当重新绘制()时,就会得到木棍人的位置信息和水果的位置信息,并在这两点之间画一条线。如果移动完成了,那么重新绘制线也应该完成。

#1


3  

The basic idea is, you need to generate some kind of relationship between the objects you want to link. You could make this relationship implicit (Person contains Fruit) or non-implicit, where the relationship is stored/managed externally, which you do is up to you (I like the implicit approach as it sets out your intentions)

基本思想是,您需要在想要链接的对象之间生成某种关系。你可以使这种关系隐式(人包含水果)或非隐式的,关系是在外部存储/管理的,这取决于你(我喜欢隐含的方法,因为它阐明了你的意图)

Your codes a bit, odd, sorry, but it is, so I've made some modifications. I did think of using a Path2D for a lot of it, but that would mean everything code painted in the same color. The main point is to define some kind of commonality between the objects, while strictly speaking not required, because almost all the work between them is the same, why not...

你的代码有点奇怪,不好意思,我做了一些修改。我确实想过为它使用Path2D,但这意味着所有代码都使用相同的颜色。重点是在对象之间定义某种共性,但严格地说不是必需的,因为它们之间的工作几乎都是相同的,为什么不……

public interface Paintable {
    public void paint(JComponent parent, Graphics2D g2d);
    public boolean contains(Point p);
    public void moveTo(Point2D p);
    public Rectangle2D getBounds();
}

Then I created a class to manage the relationships...

然后我创建了一个类来管理关系……

public class Relationship {

    private Paintable parent;
    private Paintable child;

    public Relationship(Paintable parent, Paintable child) {
        this.parent = parent;
        this.child = child;
    }

    public Paintable getChild() {
        return child;
    }

    public Paintable getParent() {
        return parent;
    }

}

Now, this means that your fruits could belong to more then one person (or other fruits), so if this goes against your rules, you will need to devise a different relationship algorithm (maybe something more implicit)

现在,这意味着你的水果可能属于更多的人(或其他水果),所以如果这违反了你的规则,你需要设计一个不同的关系算法(也许是更含蓄的)

Now, when ever you update the UI, you simply paint the relationships and the objects...

现在,当你更新UI时,你只需要绘制关系和对象……

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g.create();

    for (Relationship relationship : relationships) {

        Point2D p1 = new Point2D.Double(relationship.getParent().getBounds().getCenterX(), relationship.getParent().getBounds().getCenterY());
        Point2D p2 = new Point2D.Double(relationship.getChild().getBounds().getCenterX(), relationship.getChild().getBounds().getCenterY());

        g2.draw(new Line2D.Double(p1, p2));

    }

    for (Person p : persons) {
        p.paint(this, g2);
    }
    for (Fruit f : fruits) {
        f.paint(this, g2);
    }

    g2.dispose();
}

在两个java图形之间画一条可移动的线

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example extends JPanel {

    private List<Person> persons;
    private List<Fruit> fruits;
    private Point2D offset;
    private static Font baseFont;
    private Random randomGenerator;
    private Person person;
    private Fruit bubble;
    private static final int W = 640;
    private static final int H = 480;

    private Paintable selectedShape;

    private List<Relationship> relationships;

    public Example() {
        persons = new ArrayList<>();  // Stores the person's names & coords
        fruits = new ArrayList<>(); // Stores the person's name and what fruits he sells & coords
        relationships = new ArrayList<>(25);

        randomGenerator = new Random();
        baseFont = new Font("Sans Serif", Font.BOLD, 12);

        String person1 = "Jimmy";
        String person2 = "Sally";


        String fruit1 = "Banana";
        String fruit2 = "Apple";
        String fruit3 = "Orange";
        String fruit4 = "Watermelon";
        String fruit5 = "Pineapple";
        String fruit6 = "Grapes";

        Person person = new Person(person1, 50, 50);
        addPerson(person);

        Fruit bubble = new Fruit(fruit1, baseFont, 150, 50);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit2, baseFont, 150, 100);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit3, baseFont, 150, 150);
        addFruit(bubble);
        relate(person, bubble);

        person = new Person(person2, 50, 150);
        addPerson(person);

        bubble = new Fruit(fruit4, baseFont, 150, 200);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit5, baseFont, 150, 250);
        addFruit(bubble);
        relate(person, bubble);
        bubble = new Fruit(fruit6, baseFont, 150, 300);
        addFruit(bubble);
        relate(person, bubble);

        this.setFont(baseFont);
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                for (Paintable p : getShapes()) {
                    if (p.contains(e.getPoint())) {
                        // Selected
                        selectedShape = p;
                        offset = new Point2D.Double(e.getX() - p.getBounds().getX(), e.getY() - p.getBounds().getY());
                        break;
                    }
                }
            }

            public void mouseReleased(MouseEvent e) {
                selectedShape = null;
            }
        });
        this.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent e) {
                if (selectedShape != null) {

                    Point2D p = new Point2D.Double(e.getX() - offset.getX(), e.getY() - offset.getX());

                    selectedShape.moveTo(p);
                }
                repaint();
            }
        });
    }

    protected List<Paintable> getShapes() {
        ArrayList<Paintable> shapes = new ArrayList<>(fruits);
        shapes.addAll(persons);
        return shapes;
    }

    public void addPerson(Person person) {
        persons.add(person);
        repaint();
    }

    public void addFruit(Fruit fruit) {
        fruits.add(fruit);
        repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();

        for (Relationship relationship : relationships) {

            Point2D p1 = new Point2D.Double(relationship.getParent().getBounds().getCenterX(), relationship.getParent().getBounds().getCenterY());
            Point2D p2 = new Point2D.Double(relationship.getChild().getBounds().getCenterX(), relationship.getChild().getBounds().getCenterY());

            g2.draw(new Line2D.Double(p1, p2));

        }

        for (Person p : persons) {
            p.paint(this, g2);
        }
        for (Fruit f : fruits) {
            f.paint(this, g2);
        }

        g2.dispose();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(W, H);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame();
                f.add(new Example());
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }

    protected void relate(Person person, Fruit bubble) {
        relationships.add(new Relationship(person, bubble));
    }

    public class Relationship {

        private Paintable parent;
        private Paintable child;

        public Relationship(Paintable parent, Paintable child) {
            this.parent = parent;
            this.child = child;
        }

        public Paintable getChild() {
            return child;
        }

        public Paintable getParent() {
            return parent;
        }

    }

    public interface Paintable {

        public void paint(JComponent parent, Graphics2D g2d);

        public boolean contains(Point p);

        public void moveTo(Point2D p);

        public Rectangle2D getBounds();

    }

    public class Fruit implements Paintable {

        private static final long serialVersionUID = 1L;
        String fruit;
        Font font;

        private Ellipse2D bounds;

        public Fruit(String fruit, Font font, int x, int y) {
            this.fruit = fruit;
            this.font = font;
            bounds = new Ellipse2D.Double(x, y, 40, 90);
        }

        public String getFruit() {
            return fruit;
        }

        @Override
        public boolean contains(Point p) {
            return bounds.contains(p);
        }

        @Override
        public void moveTo(Point2D p) {
            bounds = new Ellipse2D.Double(p.getX(), p.getY(), 40, 90);
        }

        @Override
        public void paint(JComponent parent, Graphics2D g) {
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setFont(font);
            FontMetrics fm = g2.getFontMetrics();
            int height = fm.getHeight();
            int width = fm.stringWidth(fruit);

            g2.setColor(Color.WHITE);
            g2.fill(bounds);
            g2.setColor(Color.BLACK);
            g2.draw(bounds);

            double centreX = bounds.getX() + bounds.getWidth() / 2d;
            double centreY = bounds.getY() + bounds.getHeight() / 2d;
            g2.drawString(fruit, (int) (centreX - width / 2), (int) (centreY + height / 4));

            g2.dispose();
        }

        @Override
        public Rectangle2D getBounds() {
            return bounds.getBounds2D();
        }

    }

    public class Person implements Paintable {

        String person;
        private Rectangle2D bounds;

        public Person(String person, int x, int y) {
            this.person = person;
            bounds = new Rectangle2D.Double(x, y, 40, 90);
        }

        @Override
        public void paint(JComponent parent, Graphics2D g) {
            Graphics2D g2 = (Graphics2D) g.create();
            g2.translate(bounds.getX(), bounds.getY());
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.drawOval(0, 0, 20, 20); // head
            g2.drawLine(10, 20, 10, 50); // bodbounds.getY()
            g2.drawLine(10, 20, 25, 40); // right hand
            g2.drawLine(10, 20, 0 - 5, 40); // left hand
            g2.drawLine(10, 50, 0 - 5, 70); // left leg
            g2.drawLine(10, 50, 25, 70); // right leg
            g2.drawString(person, 0 - 15, 85);
            g2.dispose();
        }

        public String getPerson() {
            return person;
        }

        @Override
        public boolean contains(Point p) {
            return bounds.contains(p);
        }

        @Override
        public void moveTo(Point2D p) {
            bounds = new Rectangle2D.Double(p.getX(), p.getY(), 40, 90);
        }

        @Override
        public Rectangle2D getBounds() {
            return bounds.getBounds2D();
        }
    }

}

I would encourage you to have a look at Path2D, at least for the stick figure, it will make life eaiser

我鼓励你们去看一下Path2D,至少对于这个棍形图来说,它会让生活变得更美好。

#2


0  

Save the positions of a the stick man within itself and the position of the fruits within their objects. Relate each objects which are together. When a repaint() is started get the position information of the stick man and the position information of the fruit and draw a line between these two points. If a move is done then a repaint of the line should done also.

保存一个棍棒手的位置和水果的位置。把所有的物体联系在一起。当重新绘制()时,就会得到木棍人的位置信息和水果的位置信息,并在这两点之间画一条线。如果移动完成了,那么重新绘制线也应该完成。