Треугольник Серпинского

 
 
 
Сообщения:4
Привет, сообщество!
Я новичок, пытаюсь написать программу, которая строит треугольник Серпинского методом хаоса. Все работает примерно до ~700 итерации, затем вываливаются ошибки.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.*;
import javax.swing.border.LineBorder;

class PointDraw extends JFrame {

    int counter;
    static List<ColorPoint> points;
    static Color pointColor;
    static JSlider pointSize;
    static JSlider speedThread;
    static DrawingPane pane;

    List<Integer> massiveX = new CopyOnWriteArrayList<>();
    List<Integer> massiveY = new CopyOnWriteArrayList<>();

    JLabel jcounter = new JLabel();

    void count() {
        String str;
        counter += 1;
        str = Integer.toString(counter);
        jcounter.setText(str);
    }

    StartGame startGame = new StartGame();
    Thread thr = new Thread(startGame);

    PointDraw() {
        setTitle("Треугольник Серпинского");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        points = new ArrayList<>();
        pointColor = Color.BLACK;
        pane = new DrawingPane();

        JPanel topPanel = new JPanel();
        JButton colorButton = new JButton();
        colorButton.setBackground(pointColor);
        colorButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                pointColor = JColorChooser.showDialog(PointDraw.this,
                        "Выберите цвет:", pointColor);
                colorButton.setBackground(pointColor);
            }
        });

        colorButton.setPreferredSize(new Dimension(40, 40));
        pointSize = new JSlider(5, 20, 5);
        speedThread = new JSlider(1, 20, 1);

        JButton startButton = new JButton("Старт");
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (massiveX.size() < 4) {
                    JOptionPane.showMessageDialog(null,
                            "Задайте необходимое количество точек!",
                            "Ахтунг!",
                            JOptionPane.WARNING_MESSAGE);
                } else {
                    thr.start();
                }
            }
        });

        JButton stopButton = new JButton("Стоп");
        stopButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                startGame.mystop();
                points.clear();
                pane.repaint();
                massiveX.clear();
                massiveY.clear();
            }
        });

        JButton pauseButton = new JButton("Пауза");
        pauseButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                startGame.mysuspended();
            }
        });

        JButton continueButton = new JButton("Продолжить");
        continueButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                startGame.myresume();
            }
        });

        topPanel.add(new JLabel("Цвет:"));
        topPanel.add(colorButton);
        topPanel.add(new JLabel("Размер точки:"));
        topPanel.add(pointSize);
        topPanel.add(new JLabel("Скорость:"));
        topPanel.add(speedThread);
        topPanel.add(startButton);
        topPanel.add(stopButton);
        topPanel.add(pauseButton);
        topPanel.add(continueButton);
        topPanel.add(new JLabel("Кол-во точек:"));
        topPanel.add(jcounter);
        add(pane);
        add(topPanel, BorderLayout.NORTH);
        pack();
    }

    public static void main(String[] args) {
        new PointDraw().setVisible(true);
    }

    class DrawingPane extends JComponent {
        public DrawingPane() {
            setPreferredSize(new Dimension(1200, 400));
            setBorder(new LineBorder(Color.GRAY));
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (points.size() < 4) {
                        ColorPoint point = new ColorPoint(e.getX(), e.getY(), pointSize.getValue(), pointColor);
                        points.add(point);
                        massiveX.add(e.getX());
                        massiveY.add(e.getY());
                    } else {
                        JOptionPane.showMessageDialog(null,
                                "Нельзя создавать больше 4-х точек!",
                                "Ахтунг!",
                                JOptionPane.WARNING_MESSAGE);
                    }
                    repaint();
                }
            });
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            for (ColorPoint p : points) {
                g2.setColor(p.getColor());
                int x = p.getX();
                int y = p.getY();
                int size = p.getSize();
                g2.fillOval(x - size / 2, y - size / 2, size, size);
            }
        }
    }

    static class ColorPoint {
        private int x;
        private int y;
        private int size;
        private Color color;

        public ColorPoint(int x, int y, int size, Color color) {
            this.x = x;
            this.y = y;
            this.size = size;
            this.color = color;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public Color getColor() {
            return color;
        }

        public int getSize() {
            return size;
        }
    }

    static class RandomPoint {
        int min;
        int max;

        static int rnd(int min, int max) {
            max -= min;
            return (int) (Math.random() * ++max) + min;
        }
    }

    class StartGame extends JComponent implements Runnable {

        volatile boolean suspended;
        volatile boolean stopped;

        synchronized void mysuspended() {
            suspended = true;
        }

        synchronized void myresume() {
            suspended = false;
            notify();
        }

        synchronized void mystop() {
            stopped = true;
        }

        StartGame() {
            suspended = false;
            stopped = false;
        }

        @Override
        public void run() {

            int n_point_x;
            int n_point_y;

            try {
                for (int i = 0; i < 50000; i++) {
                    count();
                    synchronized (this) {
                        while (suspended) {
                            JOptionPane.showMessageDialog(null,
                                    "Поток поставлен на паузу!",
                                    "Ахтунг!",
                                    JOptionPane.WARNING_MESSAGE);
                            wait();
                        }
                        if (stopped) break;
                    }
                    int next_point = RandomPoint.rnd(0, 2);
                    n_point_x = (massiveX.get(3) + massiveX.get(next_point)) / 2;
                    n_point_y = (massiveY.get(3) + massiveY.get(next_point)) / 2;
                    massiveX.remove(3);
                    massiveY.remove(3);
                    massiveX.add(n_point_x);
                    massiveY.add(n_point_y);
                    PointDraw.ColorPoint point = new PointDraw.ColorPoint(n_point_x, n_point_y, PointDraw.pointSize.getValue(), PointDraw.pointColor);
                    PointDraw.points.add(point);
                    PointDraw.pane.repaint();
                    Thread.sleep(PointDraw.speedThread.getValue() * 50);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            JOptionPane.showMessageDialog(null,
                    "Программа закончила свою работу!",
                    "Ахтунг!",
                    JOptionPane.WARNING_MESSAGE);
        }
    }
}


Лог:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
	at Homework.PointDraw$DrawingPane.paintComponent(PointDraw.java:149)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
	at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)
	at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1643)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1618)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
	at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
	at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
	at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
	at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
	at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1884)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)


Предполагаю, что проблема в методе repaint(), который находится в цикле...
ЧТО Я ДЕЛАЮ НЕ ТАК? :)
Изменен:12 дек 2019 19:16
 
 
Сообщения:298
По идее вся работа с объектами swing должна вестить из специального потока EventQueue.
Попробуй в мэйне запускать приложение не напрямую, а через SwingUtilites.invokeLater.

"Мы же профессионалы! Мы всегда делаем чуть больше, чем требуется!" (с)
 
 
Сообщения:4
MuH3gPaB:
По идее вся работа с объектами swing должна вестить из специального потока EventQueue.
Попробуй в мэйне запускать приложение не напрямую, а через SwingUtilites.invokeLater.


MuH3gPaB, спасибо, что отозвался. Попробовал так:
 public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new PointDraw().setVisible(true);
            }
        });
    }


Ничего не изменилось...
 
 
Сообщения:298
Посмотрел чуть ближе :)

У тебя список points меняется в тот момент, когда ты по нему итерируешься в paintComponent
Нужно как-то это разрушить)

"Мы же профессионалы! Мы всегда делаем чуть больше, чем требуется!" (с)
 
 
Сообщения:4
MuH3gPaB:
Посмотрел чуть ближе :)

У тебя список points меняется в тот момент, когда ты по нему итерируешься в paintComponent
Нужно как-то это разрушить)

Большое спасибо тебе за наводку!
points = new CopyOnWriteArrayList<>();
- решение проблемы. :)
 
 
Сообщения:4
MuH3gPaB, через некоторое время точки начинают отрисовываться не по одной, а сразу некоторым количеством. Метод repaint() не успевает за итерациями?
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет