2015-03-05 3 views
0

Мне нужно получить зеркало JLabel или JTextArea.Зеркалирование JLabel или JTextArea

http://www.subirimagenes.net/i/150305101716451074.jpg

Если я использую JTextArea, я буду нуждаться буквы complety зеркальными. Если я использую JLabel, мне нужен формат и зеркальные буквы.

Пример был создан в Photoshop.

Моя идея использует графику(), но у меня нет идеи, как это сделать.

ответ

0

Вот один из способов создания зеркального изображения.

В принципе, вы печатаете содержимое JTextArea на BufferedImage. Затем вы меняете пиксели BufferedImage на оси X.

package com.ggl.testing; 

import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.image.BufferedImage; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextArea; 
import javax.swing.SwingUtilities; 
import javax.swing.event.DocumentEvent; 
import javax.swing.event.DocumentListener; 

public class MirrorImage implements Runnable { 

    private JFrame frame; 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new MirrorImage()); 
    } 

    @Override 
    public void run() { 
     frame = new JFrame("Mirror Image Test"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JPanel mainPanel = new JPanel(); 
     mainPanel.setLayout(new FlowLayout()); 

     JPanel textPanel = new JPanel(); 

     JTextArea textArea = new JTextArea(15, 30); 
     textPanel.add(textArea); 

     mainPanel.add(textPanel); 

     MirrorPanel mirrorPanel = new MirrorPanel(); 
     mirrorPanel.setPreferredSize(textPanel.getPreferredSize()); 

     mainPanel.add(mirrorPanel); 

     TextListener listener = new TextListener(textArea, mirrorPanel); 
     textArea.getDocument().addDocumentListener(listener); 

     frame.add(mainPanel); 

     frame.pack(); 
     frame.setLocationByPlatform(true); 

     listener.createImage(textArea); 

     frame.setVisible(true); 
    } 

    private class MirrorPanel extends JPanel { 

     private static final long serialVersionUID = 2496058019297247364L; 

     private Image image; 

     public void setImage(Image image) { 
      this.image = image; 
      repaint(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      g.drawImage(image, (getWidth() - image.getWidth(this))/2, 
        (getHeight() - image.getHeight(this))/2, this); 
     } 
    } 

    private class TextListener implements DocumentListener { 

     private JTextArea textArea; 

     private MirrorPanel mirrorPanel; 

     public TextListener(JTextArea textArea, MirrorPanel mirrorPanel) { 
      this.textArea = textArea; 
      this.mirrorPanel = mirrorPanel; 
     } 

     @Override 
     public void insertUpdate(DocumentEvent event) { 
      createImage(textArea); 
     } 

     @Override 
     public void removeUpdate(DocumentEvent event) { 
      createImage(textArea); 
     } 

     @Override 
     public void changedUpdate(DocumentEvent event) { 
      createImage(textArea); 
     } 

     public void createImage(JTextArea textArea) { 
      BufferedImage img = new BufferedImage(textArea.getWidth(), 
        textArea.getHeight(), BufferedImage.TYPE_INT_RGB); 

      Graphics2D g2d = img.createGraphics(); 
      textArea.printAll(g2d); 
      g2d.dispose(); 

      createMirrorImage(img); 
      mirrorPanel.setImage(img); 
     } 

     private void createMirrorImage(BufferedImage img) { 
      int width = img.getWidth(); 
      int height = img.getHeight(); 

      int[][] pixels = new int[width][height]; 

      for (int i = width - 1; i >= 0; i--) { 
       int j = width - i - 1; 
       for (int k = 0; k < height; k++) { 
        pixels[j][k] = img.getRGB(i, k); 
       } 
      } 

      for (int i = 0; i < width; i++) { 
       for (int j = 0; j < height; j++) { 
        img.setRGB(i, j, pixels[i][j]); 
       } 
      } 
     } 

    } 

} 
+0

Действительно ли это действительно красиво при изменении размера? И не проще ли рисовать в перевороте, в первую очередь, вместо того, чтобы листать изображение, копируя каждый пиксель? –

+0

Вы потрясающе, я никогда бы не подумал использовать перевернутые пиксели для решения. Благодарю. –

1

Вот плохие новости: это не так прямолинейно, как мы могли бы пожелать, есть ограничение. В Swing графические преобразования применяются только к операции рисования, а не к общему оформлению и событию. Поэтому в Swing зеркальный компонент в основном «непригоден», его нельзя использовать ни для чего другого, кроме отображения зеркального изображения основного компонента. Координаты щелчков мыши и т. Д. Будут неправильными.

Таким образом, это все сложный материал, немного взломать ish.

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

Вот пример того, как сделать так, что свидетельствует о перевернутой JEditorPane:

import java.awt.*; 
import java.awt.geom.*; 
import javax.swing.*; 

public class MirrorText { 
    public static void main(final String... args) { 
     SwingUtilities.invokeLater(MirrorText::setupUI); 
    } 
    public static void setupUI() { 
     final JEditorPane editor = new JEditorPane("text/html", "<h1>Mirrored</h1><p>This is mirrored text.</p>"); 
     final JEditorPane mirroredEditor = new JEditorPane("text/html", "") { 
      protected Graphics getComponentGraphics(final Graphics g) { 
       return horizontalFlip(super.getComponentGraphics(g), getWidth()); 
      } 
     }; 
     mirroredEditor.setDocument(editor.getDocument()); 

     final JFrame frame = new JFrame("mirrored label"); 
     final JPanel mirrorPanel = new JPanel(new GridLayout(1, 2)); 
     mirrorPanel.add(new JScrollPane(editor)); 
     mirrorPanel.add(new JScrollPane(mirroredEditor)); 
     frame.add(mirrorPanel); 
     frame.pack(); 
     frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
     frame.setVisible(true); 
    } 
    public static Graphics horizontalFlip(final Graphics g, final int width) { 
     final Graphics2D g2d = (Graphics2D) g; 
     final AffineTransform tx = g2d.getTransform(); 
     tx.scale(-1.0, 1.0); 
     tx.translate(-width, 0); 
     g2d.setTransform(tx); 
     return g2d; 
    } 
} 

Преимущество этого решения заключается в том, что зеркало полностью MVC и наблюдатели исходного компонента, потому что это один и тот же тип компонента (View/Controller) на той же модели. Недостатком этого решения является то, что вы создали зеркальный компонент таким образом, который очень специфичен для зеркального компонента.

Другая возможность состоит в том, чтобы создать декораторJComponentMirror, который может отражать любую другую JComponent. Это немного сложно, как в Java, декораторы не могут переопределять методы декорированного объекта, а Mirror необходимо обновлять (перекрашивать), а также всякий раз, когда исходный компонент обновляется (перекрашивается).

Вот неполный пример, используя Mirror, который подключается к соответствующим событиям. Неполный, потому что он перехватывает только DocumentEvent, но должен также подключаться к другим событиям, например CaretEvent. Было бы неплохо, если бы у Свинг было что-то вроде PaintEvent. Насколько мне известно, это не так. (Ну, на самом деле это имеет, но нет соответствующих PaintListener и addPaintListener().) Также неполно, потому что Зеркало не учитывает атрибуты исходного компонента, такие как размер. Он работает только потому, что GridLayout на MirrorPanel сохраняет размер зеркала в синхронизации с исходным компонентом.

import java.awt.*; 
import java.awt.geom.*; 
import javax.swing.*; 
import javax.swing.event.*; 

public class MirrorText { 
    public static void main(final String... args) { 
     SwingUtilities.invokeLater(MirrorText::setupUI); 
    } 
    public static void setupUI() { 
     final JEditorPane editor = new JEditorPane("text/html", "<h1>Mirrored</h1><p>This is mirrored text.</p>"); 
     final MirrorPanel mirrorPanel = new MirrorPanel(new JScrollPane(editor)); 

     editor.getDocument().addDocumentListener(new DocumentListener() { 
      public void changedUpdate(final DocumentEvent e) { mirrorPanel.updateMirror(); } 
      public void insertUpdate(final DocumentEvent e) { mirrorPanel.updateMirror(); } 
      public void removeUpdate(final DocumentEvent e) { mirrorPanel.updateMirror(); } 
     }); 

     final JFrame frame = new JFrame("mirrored label"); 
     frame.add(mirrorPanel); 
     frame.pack(); 
     frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

class MirrorPanel extends JPanel { 
    public MirrorPanel(final JComponent c) { 
     super(new GridLayout(1, 2)); 
     add(c); 
     add(new Mirror(c)); 
    } 
    public void updateMirror() { 
     repaint(); 
    } 
} 

class Mirror extends JComponent { 
    private final JComponent mirroredComponent; 
    public Mirror(final JComponent mirroredComponent) { 
     this.mirroredComponent = mirroredComponent; 
    } 
    public static Graphics horizontalFlip(final Graphics g, final int width) { 
     final Graphics2D g2d = (Graphics2D) g; 
     final AffineTransform tx = g2d.getTransform(); 
     tx.scale(-1.0, 1.0); 
     tx.translate(-width, 0); 
     g2d.setTransform(tx); 
     return g2d; 
    } 
    public void paint(final Graphics g) { 
     mirroredComponent.paint(horizontalFlip(g, mirroredComponent.getWidth())); 
    } 
} 

Вероятно, есть больше возможностей. Например, можно переопределить метод зеркального компонента paint() для обновления компонента зеркала. Это избавит вас от уведомления, но это приведет к ненужным вызовам paint() в случае, если покраска не будет выполнена из-за изменения содержимого, а из-за разрушения буфера (т. Е. Другое окно удалено).

+0

1+ для использования методов Graphics2D scale() и translate(), которые я бы предложил, если бы правильно прочитал вопрос :) – camickr

+0

Спасибо за ответ, я пробую ваше решение. На первый взгляд может работать, спасибо за совет. Я отредактирую свой пост, если будет выполнен любой из этих двух ответов. –