I'm trying to create a canvas(JPanel
) that can have text Boxes(JTextArea
) on it and I can also drag the canvas or the text boxes around. Now the dragging text boxes functions are ok. I can use setBounds()
to set the location for the JTextArea
.
However, when it comes to dragging the canvas, problems come. I use Graphics2D.transform
to move the canvas. After the canvas is moving, there will be a visual text area and a hidden real text area. I have reset the bounds of JTextArea
to fit the moving offset of the canvas but it doesn't work.
Below is an example,
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
/**
* @author Zhijie Lan<p>
* create date: 2020/11/25<p>
**/
public class TranslateJPanel extends JFrame
{
public TranslateJPanel() throws HeadlessException
{
Canvas canvas = new Canvas();
add(canvas,BorderLayout.CENTER);
this.setSize(1280, 720);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args)
{
new TranslateJPanel();
}
}
class Canvas extends JPanel
{
private final JTextArea jTextArea;
private int offset = 0;
public Canvas()
{
setLayout(null);
jTextArea = new JTextArea("hello!!!!!!!!!!!");
jTextArea.setBounds(0,0,100,100);
jTextArea.setBorder(BorderFactory.createLineBorder(Color.BLACK));
add(jTextArea);
this.addMouseMotionListener(new MouseMotionAdapter()
{
@Override
public void mouseDragged(MouseEvent e)
{
super.mouseDragged(e);
offset++;
revalidate();
repaint();
}
});
this.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
super.mouseClicked(e);
System.out.println("M: "+ e.getX()+" "+e.getY());
}
});
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
at.translate(offset, offset);
g2.transform(at);
jTextArea.setBounds(offset,offset,100,100);
System.out.println(offset);
System.out.println(jTextArea.getX()+" "+jTextArea.getY());
System.out.println("***************************");
}
}
I suggest the following for draggable text areas:
For example:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class DraggingBoxesPanel extends JPanel {
public DraggingBoxesPanel() {
int w = 900;
int h = 600;
setPreferredSize(new Dimension(w, h));
setLayout(null); // I usually avoid doing this
add(createTextBox()); // add first "box" to this JPanel
}
// exposed method to allow adding a new "box" to GUI
public void newBox() {
add(createTextBox());
revalidate(); // The JScrollPane requires this
repaint();
}
private JComponent createTextBox() {
int rows = 10; // jtextarea property
int cols = 20; // jtextarea property
// create text area and scroll pane
JTextArea textArea = new JTextArea(rows, cols);
JScrollPane scrollPane = new JScrollPane(textArea);
// let scrollpane size itself
scrollPane.setSize(scrollPane.getPreferredSize());
// scrollpane's mouse listeners
MyMouse myMouse = new MyMouse();
scrollPane.addMouseListener(myMouse);
scrollPane.addMouseMotionListener(myMouse);
// mouse adapter that forwards mouse actions in
// text area into its containing scrollpane
MouseAdapter textAreaMouseAdapter = new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
// make sure source is correct
e.setSource(scrollPane);
myMouse.mouseReleased(e);
}
@Override
public void mousePressed(MouseEvent e) {
e.setSource(scrollPane);
myMouse.mousePressed(e);
}
@Override
public void mouseDragged(MouseEvent e) {
e.setSource(scrollPane);
myMouse.mouseDragged(e);
}
};
textArea.addMouseListener(textAreaMouseAdapter);
textArea.addMouseMotionListener(textAreaMouseAdapter);
return scrollPane;
}
// code that allows a component to be dragged
private class MyMouse extends MouseAdapter {
private Point mousePt1;
private Point compPt1;
@Override
public void mousePressed(MouseEvent e) {
mousePt1 = e.getLocationOnScreen();
Component comp = (Component) e.getSource();
compPt1 = comp.getLocation();
Container container = comp.getParent();
container.setComponentZOrder(comp, 0);
container.revalidate();
container.repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
if (mousePt1 == null) {
return;
}
dragComponent(e);
}
@Override
public void mouseReleased(MouseEvent e) {
dragComponent(e);
mousePt1 = null;
}
private void dragComponent(MouseEvent e) {
Point mousePt2 = e.getLocationOnScreen();
int x = compPt1.x + mousePt2.x - mousePt1.x;
int y = compPt1.y + mousePt2.y - mousePt1.y;
Component comp = (Component) e.getSource();
comp.setLocation(x, y);
Container container = comp.getParent();
container.revalidate();
container.repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
final DraggingBoxesPanel mainPanel = new DraggingBoxesPanel();
JButton newBoxBtn = new JButton("New Box");
newBoxBtn.addActionListener(e -> mainPanel.newBox());
JPanel bottomPanel = new JPanel();
bottomPanel.add(newBoxBtn);
JFrame frame = new JFrame("DraggingBoxesPanel");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}