Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
544 views
in Technique[技术] by (71.8m points)

swing - Java rotating non-square JPanel component

I am attempting to rotate a GridLayout filled with text labels to simulate a portrait orientation view due to an OS restriction. The JPanel they are inside of is not square, so when rotating 90 degrees the labels cut off based on dimensions of the JPanel. Is it possible to resize the layout based on the rotation to still fit within the JPanel? Researching into this showed many options for rotations, but only for square JPanels.

To further explain my problem: when I rotate the labels painted inside they stay formatted to the normal oriented x,y, and I want it to format the layout to fit into the 90 degree rotated x,y (so basically y and x are flipped). currently a portion of my grid is cut off after rotating. Also the final display should fit all 13 by 24 letters filled in the current JPnel.

edit: Using vague comments shows I need to paint after rotating, but doing so crops the grid and does not fill back to my preferred size.

JPanel code:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Screen extends JPanel {

   private JLabel[][] labels = new JLabel[13][24];
   private GridLayout layout;

   public Screen() {

      //setLocation(315,35);
      layout = new GridLayout(13, 24);
      layout.preferredLayoutSize(this);
      //setBounds(315, 65, 243, 350);
      setBounds(315, 65, 243, 350);
      setLayout(layout);

      for (int i = 0; i < 13; i++) {
         for (int j = 0; j < 24; j++) {
            labels[i][j] = new JLabel();
            labels[i][j].setBackground(Color.BLACK);
            add(labels[i][j]);
         }
      }

      //testing new letter
      for (int i = 0; i < 13; i++) {
         for (int j = 0; j < 24; j++) {
            labels[i][j].setText("T");
            labels[i][j].setForeground(Color.GREEN);
         }
      }

      setBackground(Color.black);
      setVisible(true);
      repaint();
   }

   @Override
   public void paintComponent(Graphics g) {
      //Rotates screen graphics to correct orientation
      Graphics2D g2d = (Graphics2D) g;
      int w2 = getWidth() / 2;
      int h2 = getHeight() / 2;
      g2d.rotate(Math.PI / 2, w2, h2);

      super.paintComponent(g);
      setSize(243,350);

   }
}

test code:

import javax.swing.JFrame;
import javax.swing.JLayeredPane;

public class RotateTest {

   public static class Frame extends JFrame {

      public Frame() {
         Screen screen = new Screen();

         JLayeredPane pane = new JLayeredPane();
         setUndecorated(false);
         setSize(800, 480);

         setVisible(true);
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         pane.add(screen, 0, 0);
         pane.setVisible(true);
         add(pane);
      }
   }

   public static void main(String[] args) {
      Frame frame = new Frame();
   }

}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The process of rotating a component is more complicated then just painting the rotated image. There are a number of interconnected layers which generate contractual obligations.

For example, the size of the clipping rectangle set to the Graphics context that is passed to your component for painting is determined by the current size of the component, this size is calculated by the layout manager, but may consider the preferred size of the individual component...

That's a lot of re-wiring that needs to be considered...call my lazy, but if I can find a ready made solution, I'd prefer to use it, so based on this example, I can generate the following...

Rotate

The red LineBorder around the field panel is there to show that the entire component is been rotated, not just it's children. The use of pack also demonstrates that this solution is still honouring it's contractual obligations to the rest of the API

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;

public class RotateExample {

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

    public RotateExample() {
        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 ExamplePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ExamplePane extends JPanel {

        private FieldPane fieldPane;
        private DefaultTransformModel transformModel;

        private JButton rotate;
        private double angle;

        public ExamplePane() {

            setLayout(new BorderLayout());

            rotate = new JButton("Rotate");
            rotate.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    transformModel.setRotation(Math.toRadians((angle += 90)));
                    SwingUtilities.getWindowAncestor(ExamplePane.this).pack();
                }
            });


            fieldPane = new FieldPane();

            transformModel = new DefaultTransformModel();
            transformModel.setRotation(Math.toRadians(0));
            transformModel.setScaleToPreferredSize(true);
            JXLayer<JComponent> rotatePane = TransformUtils.createTransformJXLayer(fieldPane, transformModel);

            JPanel content = new JPanel(new GridBagLayout());
            content.add(rotatePane);

            add(rotate, BorderLayout.SOUTH);
            add(content);

        }
    }

    public class FieldPane extends JPanel {

        public FieldPane() {
            setBorder(new LineBorder(Color.RED));
            setLayout(new GridBagLayout());

            JTextField field = new JTextField(10);
            field.setText("Hello world");

            add(field);

        }
    }
}

Caveats

This requires JXLayer (I was using version 3), SwingX (I was using version 1.6.4) and Piet Blok's excellent examples, which no longer seem to be available on the net...

I've put all the source code of JXLayer (version 3) and Piet's examples into a single zip and I would suggest, if you are interested, you grab a copy and store it some where safe.

You will also need JHLabs filters

Updated

And using your Screen panel (without the custom painting)...

Rotate


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...