Динамическое рисование графических объектов

Попытка найти лучший способ сделать это (и без пересечения каких-либо особенностей, о которых я не знаю).

Я работаю над визуальным отображением графика (различные узлы с соединяющими их ребрами) с кругами и линиями для их представления. Каждый узел будет добавлен во время выполнения, и я не могу жестко закодировать это. Насколько я понимаю, все рисование должно быть выполнено в методе paint(Graphics g) - что не очень полезно, так как я не могу изменить параметры, и кажется, что это вызывается только во время первоначального создания?

Прямо сейчас я думал о том, чтобы он вызывал различные другие методы, передавая объект Graphics и в зависимости от других переменных - я решу, хочу ли я вообще это вызывать (поскольку метод paint() - единственный, который я могу вызвать ).

Я говорю об этом совершенно неправильно? Никогда раньше этим не заморачивался.

Чтобы дать вам лучшее представление о том, что я хочу получить в итоге: я хочу иметь возможность передавать координаты фигуры, которую я хочу добавить для узла, а затем добавлять ее ко всему, что у меня есть на графике. И то же самое с краями, я хочу иметь возможность передать начальную и конечную точки линии, чтобы перерисовать поверх того, что существует в то время.

Не совсем то, что я хочу прямо сейчас, но вы получите представление о том, что я до сих пор исправлял:

import java.awt.*;
import javax.swing.*;
public class MyCanvas extends Canvas
{
    public MyCanvas()
    {
    }
    public void paint(Graphics graphics)
    {
        // Keep this until I figured out if it's painted on load or not.
        graphics.drawLine(10, 20, 350, 380);
    }
    public static void main(String[] args)
    {
        MyCanvas canvas = new MyCanvas();
        JFrame frame = new JFrame();
        int vertexes = 0;
        // Change this next part later to be dynamic.
        vertexes = 10;
        int canvasSize = vertexes * vertexes;
        frame.setSize(canvasSize, canvasSize);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(canvas);
        frame.setVisible(true);
    }
    public void drawNode(int x, int y, Graphics g)
    {
            // Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5 
            int xLoc = (x*10) - 5;
            int yLoc = (y*10) - 5;
            g.setColor(Color.white);
            g.fillOval(xLoc, yLoc, 8, 8);
            g.drawOval(xLoc, yLoc, 8, 8);
    }
    public void drawArc(int x, int y, int xx, int yy, Graphics g)
    {
            int xLoc = (x*10) - 5;
            int yLoc = (y*10) - 5;
            int xxLoc = (xx*10) - 5;
            int yyLoc = (yy*10) - 5;
            g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
    }

}

Изменить: (Ответ для Эндрю)

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyCanvas extends JPanel
{

    public MyCanvas() {

    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
    }

    public static void main(String[] args)
    { 
        int vertexes = 0;
        // Change this next part later to be dynamic.
        vertexes = 10;
        int canvasSize = vertexes * vertexes;

        JFrame frame = new JFrame();
        JLabel label = new JLabel();
        BufferedImage bImage = new BufferedImage(canvasSize, canvasSize, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = bImage.createGraphics();
        g2d.drawLine(50, 50, 300, 300);
        ImageIcon iIcon = new ImageIcon(bImage); 
        label.setIcon(iIcon);
        frame.add(label);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        g2d = drawNode(1,1,g2d);
        label.repaint();
    }

    public static Graphics2D drawNode(int x, int y,Graphics2D g2d)
    {
            // Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5 
            int xLoc = (x*10) - 5;
            int yLoc = (y*10) - 5;
            g2d.setColor(Color.white);
            g2d.fillOval(xLoc, yLoc, 8, 8);
            g2d.drawOval(xLoc, yLoc, 8, 8);
            return g2d;
    }
    public static void drawArc(int x, int y, int xx, int yy)
    {
            int xLoc = (x*10) - 5;
            int yLoc = (y*10) - 5;
            int xxLoc = (xx*10) - 5;
            int yyLoc = (yy*10) - 5;
           // g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
    }

}

person TJ Biddle    schedule 17.05.2012    source источник
comment
Не смешивайте компоненты Swing (например, JFrame) и AWT (например, Canvas). Вместо Canvas используйте JPanel и замените paintComponent(Graphics).   -  person Andrew Thompson    schedule 17.05.2012


Ответы (1)


Существуют различные стратегии, которые вы можете использовать для этого.

  1. If the objects are never removed from the drawing once done, use a BufferedImage, put it in a (ImageIcon in a) JLabel. When it comes time to update:
    1. Get the graphics instance of the image and draw the new element.
    2. Избавьтесь от графического объекта.
    3. Назовите repaint() на этикетке.
  2. Ведите список нарисованных элементов. В методе рисования раскрасьте их все. При добавлении нового элемента вызовите repaint() в компоненте рендеринга.

Вот пример 1-й техники:

MyCanvas

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

public class MyCanvas
{
    JLabel view;
    BufferedImage surface;
    Random random = new Random();

    public MyCanvas()
    {
        surface = new BufferedImage(600,400,BufferedImage.TYPE_INT_RGB);
        view = new JLabel(new ImageIcon(surface));
        Graphics g = surface.getGraphics();
        g.setColor(Color.ORANGE);
        g.fillRect(0,0,600,400);
        g.setColor(Color.BLACK);
        // Keep this until I figured out if it's painted on load or not.
        g.drawLine(10, 20, 350, 380);
        g.dispose();

        ActionListener listener = new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                addNewElement();
            }
        };
        Timer timer = new Timer(200, listener);
        timer.start();
    }

    public void addNewElement() {
        boolean drawArc = random.nextBoolean();
        int x = random.nextInt(60);
        int y = random.nextInt(40);
        Graphics g = surface.getGraphics();
        if (drawArc) {
            g.setColor(Color.BLUE);
            int xx = random.nextInt(60);
            int yy = random.nextInt(40);
            drawArc(x,y,xx,yy,g);
        } else {
            drawNode(x,y,g);
        }
        g.dispose();
        view.repaint();
    }

    public static void main(String[] args)
    {
        MyCanvas canvas = new MyCanvas();
        JFrame frame = new JFrame();
        int vertexes = 0;
        // Change this next part later to be dynamic.
        vertexes = 10;
        int canvasSize = vertexes * vertexes;
        frame.setSize(canvasSize, canvasSize);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(canvas.view);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public void drawNode(int x, int y, Graphics g)
    {
            // Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5
            int xLoc = (x*10) - 5;
            int yLoc = (y*10) - 5;
            g.setColor(Color.white);
            g.fillOval(xLoc, yLoc, 8, 8);
            g.drawOval(xLoc, yLoc, 8, 8);
    }

    public void drawArc(int x, int y, int xx, int yy, Graphics g)
    {
            int xLoc = (x*10) - 5;
            int yLoc = (y*10) - 5;
            int xxLoc = (xx*10) - 5;
            int yyLoc = (yy*10) - 5;
            g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
    }
}

Дальнейший совет

Вы могли заметить, что линии выглядят довольно «зубчатыми» и некрасивыми. И BufferedImage, и JComponent имеют доступ к более полезному объекту Graphics2D (для JComponent необходимо бросить его в paintComponent()). Экземпляр Graphics2D принимает подсказки рендеринга, которые можно использовать для сглаживания (дизеринга) нарисованных элементов.

person Andrew Thompson    schedule 17.05.2012
comment
Вау, хорошо, вы буквально отредактировали это 12 секунд назад, но как раз собирались спросить, не это ли вы имели в виду: pastebin.com/ tsgVeshn Я быстро прочитаю то, что ты сказал. - person TJ Biddle; 17.05.2012
comment
Не переходите по ссылке pastebin. Если он достаточно короткий, добавьте его в качестве редактирования. - person Andrew Thompson; 17.05.2012
comment
Отредактировано. Из любопытства - по какой причине вы не пойдете по ссылке pastebin? - person TJ Biddle; 17.05.2012
comment
@trashgod - Вы комментируете размещение ссылки на pastebin? Вы также можете скопировать необработанный код из pastebin (плюс красивая подсветка синтаксиса: p) - person TJ Biddle; 17.05.2012
comment
Обычно я так и делаю, хотя сегодня мне лень. Однако в целом люди считают, что если код достаточно короток для публикации в SO, они его посмотрят, если нет. Также а) некоторые люди боятся «иностранных ссылок» (хорошо, не так много с pastebin) и б) если pastebin исчезнет, ​​у нас будет код для дальнейшего использования. Лучше, если вопрос будет «автономным» без «внешних зависимостей». c) См. также пункт трэшбога. - person Andrew Thompson; 17.05.2012
comment
Кроме того .. Я не совсем «вижу» смысл последнего кода. Кажется, что он движется в правильном направлении, но не делает ничего (красивого или) полезного. - person Andrew Thompson; 17.05.2012
comment
1) См. также «дальнейший совет» в редактировании. 2) Я предлагаю вам основывать любые дальнейшие примеры кода с использованием техники меток на моем источнике (хотя бы потому, что он «что-то делает»). - person Andrew Thompson; 17.05.2012
comment
Да, на данный момент это ничего не делает, ха, просто добавил то, что было необходимо для визуализации, чтобы я знал, что делаю все правильно. А что касается pastebin, ладно, это имеет больше смысла — я думал, что у вас проблемы с внешними ссылками, как вы сказали, — что меня удивило, поскольку это был pastebin. Но здорово - спасибо за помощь! - person TJ Biddle; 17.05.2012
comment
@AndrewThompson: +1, то, что я собирался спросить, вы ответили на это в разделе Further Tips :-) - person nIcE cOw; 21.07.2013