问题
I'm currently working on a project in which I need a very simple editor for GUI-like objects. This editor would be a canvas on which well known GUI widgets can be placed. For example one can place a button and a textfield on there, move them around and resize them. No interaction with the widgets themselves is needed.
I've been trying to accomplish this by adapting a very simple paint tutorial, I thought it would be easy to implement it this way, yet I bump into many problems with drawing custom shapes and text on a canvas and dragging and dropping those shapes.
I was wondering if I could reuse real Swing widgets on a JPanel and let the user place, move around and resize them. If so, what are the things I should look into?
I know this might seem very little information but I'm honestly stuck in searching for a solution.
回答1:
I thought I should remember the good old Swing days and have a little bit of fun writing you a proof of concept for this. It supports adding a button to the main panel and then move and some basic resize.
It is just a proof of concept, but it answers a lot of the questions you already have. I added a few TODOs there, such as you will know what to do next.
Enjoy...
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
public class UIBuilder {
private static final int NONE = -1;
private static final int BORDER = 3;
private JFrame frame = new JFrame("Builder");
private JToolBar toolbar = new JToolBar();
private JPanel main = new JPanel();
private int startX = NONE;
private int startY = NONE;
private int prevX = NONE;
private int prevY = NONE;
private boolean resize = false;
public UIBuilder() {
frame.setBounds(100, 100, 600, 450);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(toolbar, BorderLayout.PAGE_START);
frame.getContentPane().add(main, BorderLayout.CENTER);
frame.setVisible(true);
buildToolbox();
buildMainPanel();
}
private void buildToolbox() {
JButton button = new JButton("Button");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton btn = new JButton("Button");
addComponent(btn);
}
});
toolbar.add(button);
}
private void buildMainPanel() {
main.setLayout(null);
}
private void addComponent(JComponent comp) {
comp.setBounds(10, 10, 80, 24);
comp.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
startX = NONE;
startY = NONE;
((JComponent) e.getSource()).setCursor(Cursor.getDefaultCursor());
}
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
});
comp.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
JComponent source = (JComponent) e.getSource();
int x = e.getX();
int y = e.getY();
Rectangle bounds = source.getBounds();
resize = x < BORDER || y < BORDER || Math.abs(bounds.width - x) < BORDER || Math.abs(bounds.height - y) < BORDER;
if (resize) {
// TODO: there are a lot of resize cursors here, this is just of proof of concept
source.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
} else {
source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
}
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (startX != NONE && startY != NONE) {
JComponent source = (JComponent) e.getSource();
Rectangle bounds = source.getBounds();
int deltaX = x - startX;
int deltaY = y - startY;
if (resize) {
// TODO: handle all resize cases, left, right,...
source.setSize(Math.max(10, bounds.width + x - prevX), Math.max(10, bounds.height + y - prevY));
} else {
source.setLocation(bounds.x + deltaX, bounds.y + deltaY);
}
// TODO: make sure you don't resize it as much as it disappears
// TODO: make sure you don't move it outside the main panel
} else {
startX = x;
startY = y;
}
prevX = x;
prevY = y;
}
});
main.add(comp);
main.validate();
main.repaint();
}
public static void main(String[] args) {
new UIBuilder();
}
}
回答2:
This sounds like a fun project.
I would definitely go on the JPanel as the container, with a layout set to null. In order to be able to move the components like JButton, JLabel in the container, you would have to listen for MouseListener and MouseMotionListener events on the added components and handle them accordingly. You would have to call validate() and repaint() on the container whenever one component is moved or resized.
回答3:
I would implement this in a mixed approach: Create a class that implements the mouse responses (dragging, resizing). This class has the responsibility of managing the user interaction.
For the actual painting of the components, use real Swing components (the user interaction class would have a reference to the component its supposed to represent and delegate the actual rendering to that component).
This approach avoids most of the complexities that arise when extending the original Swing components, yet you can still reuse all their painting code.
来源:https://stackoverflow.com/questions/11990045/make-a-simple-gui-editor-in-java-swing-using-swing-components