2010-08-04 10 views
11

Mam obraz Obracam się, gdy użytkownik kliknie przycisk. Ale to nie działa.Jak obrócić obraz stopniowo w Swing?

Chciałbym, aby obraz obracał się stopniowo do 90 stopni, aż przestanie, ale nie. Obraz musi obracać się stopniowo o 90 stopni po kliknięciu przycisku.

Stworzyłem SSCCE, aby zademonstrować problem. Zastąp obraz w klasie CrossingPanelSSCE dowolnym wybranym obrazem. Po prostu umieść obraz w swoim folderze images i nadaj mu nazwę images/railCrossing.JPG.

RotateButtonSSCE

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.Action; 
import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JPanel; 

public class RotateButtonSSCE extends JPanel implements ActionListener{ 
     private JButton rotate = new JButton("Rotate"); 
     private VisualizationPanelSSCE vis = new VisualizationPanelSSCE(); 

    public RotateButtonSSCE() { 
     this.setBorder(BorderFactory.createTitledBorder("Rotate Button ")); 
     this.rotate.addActionListener(this); 
     this.add(rotate); 
    } 

    public void actionPerformed(ActionEvent ev) { 
     vis.rotatetheCrossing(); 
    } 

} 

CrossingPanelSSCE

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.Rectangle; 
import java.awt.Toolkit; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.AffineTransform; 

import javax.swing.BorderFactory; 
import javax.swing.JPanel; 
import javax.swing.border.TitledBorder; 

public class CrossingPanelSSCE extends JPanel{ 

    private static final long serialVersionUID = 1L; 

    // private data members 
    private Image crossingImage; 
    private int currentRotationAngle; 
    private int imageWidth; 
    private int imageHeight; 
    private AffineTransform affineTransform; 
    private boolean clockwise; 
    private static int ROTATE_ANGLE_OFFSET = 2; 

    private int xCoordinate; 
    private int yCoordinate; 

    private static javax.swing.Timer timer; 

    private void initialize(){ 
     this.crossingImage = Toolkit.getDefaultToolkit().getImage("images/railCrossing.JPG"); 
     this.imageWidth = this.getCrossingImage().getWidth(this); 
     this.imageHeight = this.getCrossingImage().getHeight(this); 
     this.affineTransform = new AffineTransform(); 
     currentRotationAngle = 90; 
     timer = new javax.swing.Timer(20, new MoveListener()); 
    } 

    public CrossingPanelSSCE(int x, int y) { 
     this.setxCoordinate(x); 
     this.setyCoordinate(y); 
     this.setPreferredSize(new Dimension(50, 50)); 
     this.setBackground(Color.red); 
     TitledBorder border = BorderFactory.createTitledBorder("image"); 
     this.setLayout(new FlowLayout()); 
     this.initialize(); 

    } 


    public void paintComponent(Graphics grp){ 

     Rectangle rect = this.getBounds(); 
     Graphics2D g2d = (Graphics2D)grp; 
     g2d.setColor(Color.BLACK); 
     this.getAffineTransform().setToTranslation(this.getxCoordinate(), this.getyCoordinate()); 

      //rotate with the rotation point as the mid of the image 
     this.getAffineTransform().rotate(Math.toRadians(this.getCurrentRotationAngle()), this.getCrossingImage().getWidth(this) /2, 
             this.getCrossingImage().getHeight(this)/2); 

     //draw the image using the AffineTransform 
     g2d.drawImage(this.getCrossingImage(), this.getAffineTransform(), this); 
    } 


    public void rotateCrossing(){ 
     System.out.println("CurrentRotationAngle: " + currentRotationAngle); 
     this.currentRotationAngle += ROTATE_ANGLE_OFFSET; 
     //int test = currentRotationAngle % 90; 
     if(currentRotationAngle % 90 == 0){ 
     setCurrentRotationAngle(currentRotationAngle); 
     timer.stop();   
     } 

     //repaint the image panel 
     repaint(); 
    } 


    void start() { 
     if (timer != null) { 
      timer.start(); 
     } 
    } 


    private class MoveListener implements ActionListener { 

      public void actionPerformed(ActionEvent e) { 
       rotateCrossing(); 
     } 

    } 

    public Image getCrossingImage() { 
     return crossingImage; 
    } 
    public void setCrossingImage(Image crossingImage) { 
     this.crossingImage = crossingImage; 
    } 

    public int getCurrentRotationAngle() { 
     return currentRotationAngle; 
    } 
    public void setCurrentRotationAngle(int currentRotationAngle) { 
     this.currentRotationAngle = currentRotationAngle; 
    } 

    public int getImageWidth() { 
     return imageWidth; 
    } 
    public void setImageWidth(int imageWidth) { 
     this.imageWidth = imageWidth; 
    } 

    public int getImageHeight() { 
     return imageHeight; 
    } 
    public void setImageHeight(int imageHeight) { 
     this.imageHeight = imageHeight; 
    } 

    public AffineTransform getAffineTransform() { 
     return affineTransform; 
    } 
    public void setAffineTransform(AffineTransform affineTransform) { 
     this.affineTransform = affineTransform; 
    } 

    public boolean isClockwise() { 
     return clockwise; 
    } 
    public void setClockwise(boolean clockwise) { 
     this.clockwise = clockwise; 
    } 

    public int getxCoordinate() { 
     return xCoordinate; 
    } 
    public void setxCoordinate(int xCoordinate) { 
     this.xCoordinate = xCoordinate; 
    } 

    public int getyCoordinate() { 
     return yCoordinate; 
    } 
    public void setyCoordinate(int yCoordinate) { 
     this.yCoordinate = yCoordinate; 
    } 

    public javax.swing.Timer getTimer() { 
     return timer; 
    } 
    public void setTimer(javax.swing.Timer timer) { 
     this.timer = timer; 
    } 



} 

VisualizationPanelSSCE

import gui.CrossingPanel; 
import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.Shape; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.GeneralPath; 

import javax.swing.BorderFactory; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.border.TitledBorder; 

import application.Robot2; 

public class VisualizationPanelSSCE extends JPanel{ 


     //private data members 
     private GeneralPath path; 
     private Shape horizontalRail; 
     private Shape verticalRail; 
     private static int LENGTH = 350; 
     private CrossingPanelSSCE crossingP; 



     private void initializeComponents(){ 
      this.path = new GeneralPath(); 
      this.horizontalRail = this.createHorizontalRail(); 
      this.verticalRail = this.createVerticalRail(); 
      this.crossingP = new CrossingPanelSSCE(328,334); 
     } 

     public VisualizationPanelSSCE(){ 
      this.initializeComponents(); 
      this.setPreferredSize(new Dimension(400,400)); 
      TitledBorder border = BorderFactory.createTitledBorder("Rotation"); 
      this.setBorder(border); 

     } 

     public GeneralPath getPath() { 
      return path; 
     } 
     public void setPath(GeneralPath path) { 
      this.path = path; 
     } 


     private Shape createHorizontalRail(){ 
      this.getPath().moveTo(5, LENGTH); 
      this.getPath().lineTo(330, 350); 
      this.getPath().closePath(); 
      return this.getPath(); 
     } 

     private Shape createVerticalRail(){ 
      this.getPath().moveTo(350, 330); 
      this.getPath().lineTo(350,10); 
      this.getPath().closePath(); 
      return this.getPath(); 
     } 


     public void paintComponent(Graphics comp){ 
      super.paintComponent(comp); 
      Graphics2D comp2D = (Graphics2D)comp; 
      BasicStroke pen = new BasicStroke(15.0F, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND); 

      comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON); 
      comp2D.setPaint(Color.black); 
      comp2D.setBackground(Color.WHITE); 
      comp2D.draw(this.horizontalRail); 
      this.crossingP.paintComponent(comp2D); 
     } 


     public CrossingPanelSSCE getCrossingP() { 
      return crossingP; 
     } 
     public void setCrossingP(CrossingPanelSSCE crossingP) { 
      this.crossingP = crossingP; 
     } 

     public void rotatetheCrossing(){ 

      Runnable rotateCrossing1 = new Runnable(){ 
       public void run() { 
        crossingP.start(); 
       } 
      }; 
      SwingUtilities.invokeLater(rotateCrossing1); 
     } 


    } 

TestGUISSCE zawiera główne metody.

import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.Random; 

import javax.swing.*; 

public class TestGUISSCE{ 
    private RotateButtonSSCE rotate = new RotateButtonSSCE(); 
    private VisualizationPanelSSCE vision = new VisualizationPanelSSCE(); 

    public void createGui(){ 

     JFrame frame = new JFrame("Example"); 
     frame.setSize(new Dimension(500, 500)); 


     JPanel pane = new JPanel(); 
     pane.add(this.vision); 
     pane.add(rotate); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(pane); 
     frame.setVisible(true); 

    } 

    public static void main(String[] args) { 
     new TestGUISSCE().createGui(); 
    } 
} 
+0

możliwy duplikat [Potrzebujesz pomocy w rozwiązywaniu problemu z obrotem obrazu] (http://stackoverflow.com/questions/3371227/need-help-in-solving-rotation-image-problem) – finnw

+0

Wszystkie klasy muszą być w oddzielne pliki. Wysłałem odpowiedź i dali ją -1. Nie rozumiem, co znaczy -1. –

+0

@Kap: przeczytaj: http://stackoverflow.com/faq – BalusC

Odpowiedz

4
this.crossingP.paintComponent(comp2D); 

Nigdy nie rób tego! Twój CrossingPane nie jest dodawany do żadnego komponentu, więc repaint() nie ma żadnego efektu. Możesz to sprawdzić, dodając wydruki w metodzie paintComponent(). Więc trzeba dodać CrossingPane do VisualizationPane:

setLayout(new BorderLayout()); 
add(crossingP, BorderLayout.CENTER); 

Są pewne problemy z centrowanie obrazu, ale nie powinno to być trudne do naprawienia.

PS. Przeczytaj jeszcze raz o układach i malowaniu.

24

Oprócz pomocnych uwag @ tulskiy za, chciałbym dodać dwa punkty:

  1. Zawsze konstruować swoje GUI na event dispatch thread, jak pokazano poniżej.

  2. An sscce powinny być krótkie, autonomiczny, właściwej (compilable) Przykład. Dla wygody nie wymagaj od innych tworzenia wielu klas publicznych; użyj klas najwyższego poziomu (pakiet-prywatny) lub zagnieżdżonych. Ponieważ jest to problem graficzny, użyj publicznego lub syntetycznego obrazu, który odzwierciedla Twój problem.

W poniższym przykładzie paintComponent() zmienia przekształcenie kontekstu graficznego, aby wykonać obrót. Zauważ, że operacje są wykonywane na (pozornym) rewersie kolejności deklaracji: Najpierw centrum obrazu jest tłumaczone na pochodzenie; po drugie obraz jest obracany; po trzecie, środek obrazu jest tłumaczony na środek panelu. Efekt można zobaczyć, zmieniając rozmiar panelu.

Dodatek: Zobacz również tę alternatywę approach przy użyciu AffineTransform.

image

package overflow; 

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

/** 
* @see https://stackoverflow.com/questions/3371227 
* @see https://stackoverflow.com/questions/3405799 
*/ 
public class RotateApp { 

    private static final int N = 3; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame frame = new JFrame(); 
       frame.setLayout(new GridLayout(N, N, N, N)); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       for (int i = 0; i < N * N; i++) { 
        frame.add(new RotatePanel()); 
       } 
       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 


class RotatePanel extends JPanel implements ActionListener { 

    private static final int SIZE = 256; 
    private static double DELTA_THETA = Math.PI/90; 
    private final Timer timer = new Timer(25, this); 
    private Image image = RotatableImage.getImage(SIZE); 
    private double dt = DELTA_THETA; 
    private double theta; 

    public RotatePanel() { 
     this.setBackground(Color.lightGray); 
     this.setPreferredSize(new Dimension(
      image.getWidth(null), image.getHeight(null))); 
     this.addMouseListener(new MouseAdapter() { 

      @Override 
      public void mousePressed(MouseEvent e) { 
       image = RotatableImage.getImage(SIZE); 
       dt = -dt; 
      } 
     }); 
     timer.start(); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2d = (Graphics2D) g; 
     g2d.translate(this.getWidth()/2, this.getHeight()/2); 
     g2d.rotate(theta); 
     g2d.translate(-image.getWidth(this)/2, -image.getHeight(this)/2); 
     g2d.drawImage(image, 0, 0, null); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     theta += dt; 
     repaint(); 
    } 

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

} 

class RotatableImage { 

    private static final Random r = new Random(); 

    static public Image getImage(int size) { 
     BufferedImage bi = new BufferedImage(
      size, size, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2d = bi.createGraphics(); 
     g2d.setRenderingHint(
      RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setPaint(Color.getHSBColor(r.nextFloat(), 1, 1)); 
     g2d.setStroke(new BasicStroke(size/8)); 
     g2d.drawLine(0, size/2, size, size/2); 
     g2d.drawLine(size/2, 0, size/2, size); 
     g2d.dispose(); 
     return bi; 
    } 
} 
+0

Dzięki za twój wpis. Doceniam to. –

+0

+1 nice:) ..... –

+0

@trashgod: Absolutnie WOW! + 100! – ron

5

Kod dla Rotated Icon używa AffineTransform obracać się wokół jego centrum.

+0

+1 Jest to również miły przykład implementacji' Interfejs ikony. – trashgod

+0

@trashgod, Ups, pisałem w tym wątku przez pomyłkę. Zamierzałem odpowiedzieć w tym poście (http://stackoverflow.com/questions/5722058/rotate-a-picture-around-its-center/5722166#5722166). Ale widzę, że odpowiedź zawiera dwa przykłady. – camickr

+1

Najbardziej losowe! To ładnie uzupełnia moją odpowiedź i dodałem link powyżej. Pytanie mogło zostać porzucone, ale jeszcze przez jakiś czas będę chłostał odpowiedzi. :-) – trashgod