运行线程时,旋转变换在重绘时无法正常工作

时间:2012-12-20 02:31:01

标签: java multithreading swing awt graphics2d

我一直在努力使这个程序工作,即使我似乎无法找到问题所在。这个程序由以下2个类组成,不多也不少。基本上应该在绘图区域中的每次点击上绘制一个点,并在第3次点击时连接所有点。我仍然需要努力使它更漂亮,更准确,但这一部分有效。什么不起作用应该遵循:在第四次点击线程应该开始(并开始),三角形本身应该旋转给定一个任意刷新率,恰好80重绘。在动画完成之前,下一次单击不应该起作用,只有在动画停止后(线程消失)有一次点击时,才会显示一个新点并重新开始。

是否有可能所有的绘制调用都被堆叠到我的线程结束之前?我知道可能会发生所有事件都堆叠在事件队列中并视为一个事件。使用带有时间参数的重绘无济于事。我添加了评论以帮助澄清,因为所有变量都是法语单词(它们已被解释)。我很难弄清楚是否在我的代码中找到问题,如果它与线程相关甚至类型相关。我只是在调试模式下无处可去(使用 Eclipse )。我完全忽略了一些明显的东西吗?

虽然我的方法可能不是最有效的方法,但旋转是我的主要问题。我可以处理编写代码中未写入的剩余部分。 谢谢你的帮助!这是两个类:

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;


public class Application extends JFrame {

private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JButton btnTerminer;
private Triangle triangle;
private int totalClics = 0;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Application frame = new Application();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public Application() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 453, 692);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    btnTerminer = new JButton("Terminer");
    btnTerminer.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            System.exit(0);
        }
    });
    btnTerminer.setBounds(138, 622, 132, 23);
    contentPane.add(btnTerminer);

    triangle = new Triangle();
    //Adds points for every mouse click
    triangle.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if(totalClics < 3){
                triangle.ajouterPoint(e.getX(), e.getY());
                totalClics++;
            } else {
                triangle.getAnim().start();
                totalClics = 0;
            }
        }
    });
    triangle.setBounds(10, 11, 400, 600);
    contentPane.add(triangle);
}
}

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;


import javax.swing.JPanel;


public class Triangle extends JPanel implements Runnable,Serializable{

private static final long serialVersionUID = 1L;
private ArrayList<Point> points = null;
//Animation thread
private Thread anim;
private Color couleurPrin;
private Color couleurBoite;
//A point's diameter
private int diametre = 8;
//The rectangle's width
private int largeur;
//The rectangle's height
private int hauteur;
//The rectangle's top-left corner
private int minX;
private int minY;
//Angle incrementation multiplier
private int nbAng = 0 ;
//Thread stopping variable
private boolean continuer = true;


public Triangle() {
    setPreferredSize(new Dimension(400, 600));
    setBackground(Color.BLACK);
    couleurPrin = Color.GREEN;
    couleurBoite = Color.RED;
    setAnim(new Thread(this));
    points = new ArrayList<Point>();


}
/**
 * Repaints this component
 */
@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    int i = 0;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int[] coorX = new int[points.size()+1];
    int[] coorY = new int[points.size()+1];
    Iterator<Point> iter = points.iterator();
    while(iter.hasNext()){
        Point p = iter.next();
        coorX[i] = p.getX();
        coorY[i]= p.getY();
        i++;
    }
    coorX[points.size()] = coorX[0];
    coorY[points.size()] = coorY[0];
    if(points.size() != 0){
        g2d.setColor(Color.white);
        g2d.fillOval(minX+largeur/2, minY+hauteur/2, 6, 6);
        g2d.setColor(couleurPrin);
        for(i =0; i<points.size(); i++){
            g2d.drawLine(coorX[i], coorY[i], coorX[i+1], coorY[i+1]);
        }
        for(i = 0; i<points.size(); i++){
            g2d.fillOval(coorX[i]-diametre/2, coorY[i]-diametre/2, diametre, diametre);
        }
        g2d.setColor(couleurBoite);
        g2d.drawRect(minX, minY, largeur, hauteur);
        g2d.rotate(15.0*nbAng, (largeur+getWidth())/2, (hauteur+getWidth())/2); 


    }

}
/**
 * Adds a point. Stops at 3.
 * @param x
 * @param y
 * 
 * 
 */
public void ajouterPoint(int x, int y){
    Point p = new Point(x,y);
    System.out.println(p.toString());
    if(points.size()>=0 && points.size()<3){
        points.add(p);
        minX = p.getX()-3;
        minY = p.getY()-3;
    }
    if(points.size() == 3){
        rectanguler(points);
    }
    repaint();

}

public Color getCouleurPrin() {
    return couleurPrin;
}
public void setCouleurPrin(Color c) {
    this.couleurPrin = c;
    repaint();
}
public int getDiametre() {
    return diametre;
}
public void setDiametre(int d) {
    this.diametre = d;
    repaint();
}
/**
 * Sets rectangle's values to the largest bounds possible
 * @param points
 */
private void rectanguler(ArrayList<Point> points){
    Iterator<Point> iter = points.iterator();
    Point p1, p2, p3;
    p1 = iter.next();
    p2 = iter.next();
    p3 = iter.next();
    int dLarg;
    int dLong;
    if(p2 != null && p3 != null){
        minX = Math.min(p1.getX(), p2.getX());
        minY = Math.min(p1.getY(), p2.getY());
        largeur = Math.abs(p1.getX()-p2.getX());
        hauteur = Math.abs(p1.getY()-p2.getY());
        if(p3 != null){
            minX = Math.min(minX, p3.getX());
            minY = Math.min(minY, p3.getY());
            dLarg = Math.max(Math.abs(p3.getX()-p2.getX()), Math.abs(p3.getX()-p1.getX()));
            dLong = Math.max(Math.abs(p3.getY()-p2.getY()), Math.abs(p3.getY()-p1.getY()));
            largeur = Math.max(dLarg, largeur);
            hauteur = Math.max(dLong, hauteur);
        }       
    }
}
/**
 * Custom point class
 * Stores an x and y value
 *
 */
private class Point{
    @Override
    public String toString() {
        return "Point [x=" + x + ", y=" + y + "]";
    }
    private int x,y;
    public Point(){
        setX(0);
        setY(0);
    }
    public Point(int x,int y){
        setX(x);
        setY(y);
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }

}
/**
 * Starts the rotation
 * 
 */
@Override
public void run() {
    int i =1;
    while(continuer){

        nbAng = i;
        repaint();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            System.out.println("Erreur dans le thread");
            e.printStackTrace();
        }
        i++;
        if(i== 80){
            continuer = false;
        }
    }
    anim = new Thread(this);

}
public Thread getAnim() {
    return anim;
}
public void setAnim(Thread anim) {
    this.anim = anim;
    repaint();
}

}

2 个答案:

答案 0 :(得分:3)

第一个问题是你永远不会在动画线程上调用start()

第二个问题是你应该从不在EDT之外做gui事情。正如@AndrewThompson在评论中提到的那样,你应该使用摆动Timer而不是线程。

答案 1 :(得分:3)

Thread对于您想要达到的目标而言过于苛刻。 javax.swing.Timer更简单易用,与Thread不同,它也可以重复使用。

Graphics2D#rotate将翻译应用于所有后续渲染,这意味着您需要在绘制任何内容之前应用它。

您的鼠标点击逻辑也有点偏离,它不会在允许点击继续之前检查线程的状态。

我稍微修改了你的代码作为一个例子(对不起,我将鼠标单击处理移动到Triangle类,但你应该能够删除它;)

public class TestRotation01 {

    public static void main(String[] args) {
        new TestRotation01();
    }

    public TestRotation01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new Triangle());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Triangle extends JPanel {

        private static final long serialVersionUID = 1L;
        private ArrayList<Point> points = null;
//Animation thread
//        private Thread anim;
        private Color couleurPrin;
        private Color couleurBoite;
//A point's diameter
        private int diametre = 8;
//The rectangle's width
        private int largeur;
//The rectangle's height
        private int hauteur;
//The rectangle's top-left corner
        private int minX;
        private int minY;
//Angle incrementation multiplier
        private int nbAng = 0;
//Thread stopping variable
        private boolean continuer = true;
        private int totalClics = 0;
        private Timer timer;
        private int cycle;

        public Triangle() {
            setPreferredSize(new Dimension(400, 600));
            setBackground(Color.BLACK);
            couleurPrin = Color.GREEN;
            couleurBoite = Color.RED;
            points = new ArrayList<Point>();
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (!timer.isRunning()) {
                        if (totalClics < 3) {
                            nbAng = 0;
                            ajouterPoint(e.getX(), e.getY());
                            totalClics++;
                        } else {
                            cycle = 0;
                            totalClics = 0;
                            timer.restart();
                        }
                    }
                }
            });

            timer = new Timer(200, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    nbAng += 5;
                    repaint();
                    cycle++;
                    if (cycle == 80) {
                        timer.stop();
                    }
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
        }

        /**
         * Repaints this component
         */
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            if (timer.isRunning()) {

                g2d.rotate(15.0 * nbAng, (largeur + getWidth()) / 2, (hauteur + getWidth()) / 2);

            }

            int i = 0;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            int[] coorX = new int[points.size() + 1];
            int[] coorY = new int[points.size() + 1];
            Iterator<Point> iter = points.iterator();
            while (iter.hasNext()) {
                Point p = iter.next();
                coorX[i] = p.getX();
                coorY[i] = p.getY();
                i++;
            }
            coorX[points.size()] = coorX[0];
            coorY[points.size()] = coorY[0];
            if (points.size() != 0) {
                g2d.setColor(Color.white);
                g2d.fillOval(minX + largeur / 2, minY + hauteur / 2, 6, 6);
                g2d.setColor(couleurPrin);
                for (i = 0; i < points.size(); i++) {
                    g2d.drawLine(coorX[i], coorY[i], coorX[i + 1], coorY[i + 1]);
                }
                for (i = 0; i < points.size(); i++) {
                    g2d.fillOval(coorX[i] - diametre / 2, coorY[i] - diametre / 2, diametre, diametre);
                }
                g2d.setColor(couleurBoite);
                g2d.drawRect(minX, minY, largeur, hauteur);
            }

            g2d.dispose();

        }

        /**
         * Adds a point. Stops at 3.
         *
         * @param x
         * @param y
         *
         *
         */
        public void ajouterPoint(int x, int y) {
            Point p = new Point(x, y);
            System.out.println(p.toString());
            if (points.size() >= 0 && points.size() < 3) {
                points.add(p);
                minX = p.getX() - 3;
                minY = p.getY() - 3;
            }
            if (points.size() == 3) {
                rectanguler(points);
            }
            repaint();

        }

        public Color getCouleurPrin() {
            return couleurPrin;
        }

        public void setCouleurPrin(Color c) {
            this.couleurPrin = c;
            repaint();
        }

        public int getDiametre() {
            return diametre;
        }

        public void setDiametre(int d) {
            this.diametre = d;
            repaint();
        }

        /**
         * Sets rectangle's values to the largest bounds possible
         *
         * @param points
         */
        private void rectanguler(ArrayList<Point> points) {
            Iterator<Point> iter = points.iterator();
            Point p1, p2, p3;
            p1 = iter.next();
            p2 = iter.next();
            p3 = iter.next();
            int dLarg;
            int dLong;
            if (p2 != null && p3 != null) {
                minX = Math.min(p1.getX(), p2.getX());
                minY = Math.min(p1.getY(), p2.getY());
                largeur = Math.abs(p1.getX() - p2.getX());
                hauteur = Math.abs(p1.getY() - p2.getY());
                if (p3 != null) {
                    minX = Math.min(minX, p3.getX());
                    minY = Math.min(minY, p3.getY());
                    dLarg = Math.max(Math.abs(p3.getX() - p2.getX()), Math.abs(p3.getX() - p1.getX()));
                    dLong = Math.max(Math.abs(p3.getY() - p2.getY()), Math.abs(p3.getY() - p1.getY()));
                    largeur = Math.max(dLarg, largeur);
                    hauteur = Math.max(dLong, hauteur);
                }
            }
        }

        /**
         * Custom point class Stores an x and y value
         *
         */
        private class Point {

            @Override
            public String toString() {
                return "Point [x=" + x + ", y=" + y + "]";
            }
            private int x, y;

            public Point() {
                setX(0);
                setY(0);
            }

            public Point(int x, int y) {
                setX(x);
                setY(y);
            }

            public int getX() {
                return x;
            }

            public void setX(int x) {
                this.x = x;
            }

            public int getY() {
                return y;
            }

            public void setY(int y) {
                this.y = y;
            }
        }
    }
}