Reputation: 2176
I've created a board game with 8x8 GridLayout
where in each grid, there is a button which is opaque. I've created to show in the form of a 8x8 table and when user clicks on any cell, it should do some action. Right now, the grid looks like :
I want it to re-position this through animation at an angle to look like this:
Is it possible to do this in Swing
using repaint
? If not, is there a better toolkit to use other than Swing
so that I can animate this?
Upvotes: 1
Views: 394
Reputation: 347332
Changing the state of a live component requires more then just painting...
For example, based on Boann's example...
Painting in Swing is a complex and optimised process, which isn't always done in a linear fashion.
Having said that, there is a way, but you are going to need to work for it.
This is based on the JXLayer API and pbjar examples
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;
public class Twister02 {
public static void main(String[] args) {
new Twister02();
}
public Twister02() {
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 JSlider slider;
private FieldPane fieldPane;
private DefaultTransformModel transformModel;
public ExamplePane() {
setLayout(new BorderLayout());
slider = new JSlider(0, 360);
slider.setValue(0);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
transformModel.setRotation(Math.toRadians(slider.getValue()));
}
});
fieldPane = new FieldPane();
transformModel = new DefaultTransformModel();
transformModel.setRotation(Math.toRadians(0));
transformModel.setScaleToPreferredSize(true);
JXLayer<JComponent> rotatePane = TransformUtils.createTransformJXLayer(fieldPane, transformModel);
add(slider, BorderLayout.NORTH);
add(rotatePane);
}
}
public class FieldPane extends JPanel {
public FieldPane() {
setLayout(new GridLayout(8, 8));
for (int i = 0; i < 64; i++) {
add(new JButton("" + i));
}
}
}
}
Now, the problem is, the pbjar examples seem to have vanished off the face of the internet, to our great disappointment.
However, you can grab a copy from here
Add because it's fun...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;
public class Twister02 {
public static void main(String[] args) {
new Twister02();
}
public Twister02() {
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 JSlider rotateSlider;
private JSlider shearXSlider;
private JSlider shearYSlider;
private FieldPane fieldPane;
private DefaultTransformModel transformModel;
public ExamplePane() {
setLayout(new BorderLayout());
rotateSlider = new JSlider(0, 180);
rotateSlider.setValue(0);
rotateSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
transformModel.setRotation(Math.toRadians(rotateSlider.getValue()));
}
});
shearXSlider = new JSlider(-100, 100);
shearXSlider.setValue(0);
shearXSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
double value = shearXSlider.getValue() / 200d;
transformModel.setShearX(value);
}
});
shearYSlider = new JSlider(-100, 100);
shearYSlider.setValue(0);
shearYSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
double value = shearYSlider.getValue() / 200d;
transformModel.setShearY(value);
}
});
fieldPane = new FieldPane();
transformModel = new DefaultTransformModel();
transformModel.setRotation(Math.toRadians(0));
transformModel.setScaleToPreferredSize(true);
JXLayer<JComponent> rotatePane = TransformUtils.createTransformJXLayer(fieldPane, transformModel);
JPanel sliders = new JPanel(new GridLayout(3, 0));
sliders.add(rotateSlider);
sliders.add(shearXSlider);
sliders.add(shearYSlider);
add(sliders, BorderLayout.NORTH);
add(rotatePane);
}
}
public class FieldPane extends JPanel {
public FieldPane() {
setLayout(new GridLayout(8, 8));
for (int i = 0; i < 64; i++) {
add(new JButton("" + i));
}
}
}
}
Upvotes: 3
Reputation: 50061
Override the container's paintChildren
method to apply a transform to the Graphics object, then call super.paintChildren
with it. Simple example that rotates a button grid a bit about its center:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout(8, 8)) {
@Override
public void paintChildren(Graphics g1) {
Graphics2D g = (Graphics2D)g1;
g.rotate(0.3, getWidth() / 2, getHeight() / 2);
super.paintChildren(g);
}
};
frame.add(panel);
for (int i = 0; i < 64; i++) panel.add(new JButton("" + i));
frame.pack();
frame.setVisible(true);
What it looks like (before/after):
Edit: Although it looks clever, you can't actually click these buttons in their rotated positions; it's probably possible to use an AffineTransform object to transform mouse events and redirect them to the correct child correct component, but I haven't tried it. There might be issues with the repaint region too. ... Maybe drawing your own grid (@Masud's answer) would avoid trying to hack this functionality on top of Swing.
Upvotes: 1
Reputation: 21981
Is it possible to do this in Swing using repaint? If not, is there a better toolkit to use other than Swing so that I can animate this?
No, It is not possible with GridLayout
. Use graphics on a JPanel
with drawLine
and animate it with Timer
.
Upvotes: 0