Verschiebbare Elemente in einem rollbaren Container
Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springenVielleicht möchtest du dieses Beispiel als Ausgangspunkt nehmen, um verschiebbare Elemente in einem Rollbaren Container zu implementieren:
package graphic;
/**
* Model.java
*/
import java.awt.*;
import java.util.*;
import java.util.List;
public class Model {
private List<Element> elements;
private Rectangle bounds;
private Element activeElement;
public Model() {
elements = new ArrayList<Element>();
bounds = new Rectangle();
}
public List<Element> getElements() {
return elements;
}
public void setElements(final List<Element> elements) {
this.elements = elements;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Element getActiveElement() {
return activeElement;
}
public void setActiveElement(final Element activeElement) {
this.activeElement = activeElement;
}
/**
*
* @param rect The bounds of any element
* @return The smallest rectangle enclosing all elements
*/
protected Rectangle getBounds(final Rectangle rect) {
bounds = new Rectangle(rect);
for (Element element : elements) {
Rectangle elementBounds = new Rectangle(element.getBounds());
elementBounds.x -= 5;
elementBounds.y -= 5;
elementBounds.width += 10;
elementBounds.height += 10;
bounds = bounds.union(elementBounds);
}
for (Element element : elements) {
Rectangle elementBounds = element.getBounds();
elementBounds.translate(-bounds.x, -bounds.y);
}
return bounds;
}
/**
*
* @param hitPoint the location to be analized for intersection with any element
* @return the list of elements containing hitPoint within their bounds
*/
protected List<Element> getElementsAt(final Point hitPoint) {
List<Element> elementsAt = new ArrayList<Element>();
for (Element element : elements) {
Rectangle elementBounds = element.getBounds();
if (elementBounds.contains(hitPoint)) {
elementsAt.add(element);
}
}
return elementsAt;
}
/**
*
* @param location the location of the element
* @return the element added to this Model
*/
protected Element add(final Point location) {
Element newElement = new Element();
Rectangle newBounds;
newBounds = new Rectangle(location.x, location.y, 0, 0);
newElement.setBounds(newBounds);
newElement.getBounds().width = newElement.getMinimumSize().width;
newElement.getBounds().height = newElement.getMinimumSize().height;
elements.add(newElement);
return newElement;
}
@Override
public String toString() {
return "number of elements: " + elements.size();
}
}
package graphic;
/**
* Element.java
*/
import java.awt.*;
import javax.swing.JDialog;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Element {
private Rectangle bounds;
private String text;
private Dimension minimumSize;
private Color color;
private JTextArea tTemp;
private JDialog dTemp;
public Element() {
bounds = new Rectangle();
text = "";
minimumSize = new Dimension(113, 50);
color = Color.WHITE;
tTemp = new JTextArea();
dTemp = new JDialog();
dTemp.add(new JScrollPane(tTemp));
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(final Rectangle bounds) {
this.bounds = bounds;
}
public String getText() {
return text;
}
public void setText(final String text) {
this.text = text;
}
public Dimension getMinimumSize() {
return minimumSize;
}
public void setMinimumSize(final Dimension minimumSize) {
this.minimumSize = minimumSize;
}
/**
*
* @return the background color of this element
*/
public Color getColor() {
return color;
}
/**
*
* @param color the background color of this element
*/
public void setColor(final Color color) {
this.color = color;
}
/**
*
* resize the element according to its text bounds
*/
protected void pack() {
// tTemp and dTemp are used for size calculation only:
tTemp.setText(this.getText());
dTemp.pack();
Rectangle textBounds = new Rectangle(tTemp.getBounds());
//respecting minimum size:
if (textBounds.width < this.getMinimumSize().width) {
textBounds.width = this.getMinimumSize().width;
}
if (textBounds.height < this.getMinimumSize().height) {
textBounds.height = this.getMinimumSize().height;
}
//this coordinates:
textBounds.x = this.getBounds().x;
textBounds.y = this.getBounds().y;
this.setBounds(textBounds);
}
@Override
public String toString() {
return text;
}
}
package graphic;
/**
* Graphic.java
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.List;
public class Graphic extends JComponent {
private Model model;
private JTextArea renderer;
private transient Stroke normalStroke, activeStroke;
private Controller controller;
//
private Dimension preferredSize;
public Graphic() {
setFocusable(true);
setControl(new Controller());
setModel(new Model());
controller.setView(this);
normalStroke = new BasicStroke(1);
activeStroke = new BasicStroke(3);
renderer = new JTextArea();
renderer.setFocusable(false);
preferredSize = new Dimension();
}
public Model getModel() {
return model;
}
/**
* Use this method to set the model that you loaded from file
* @param model the model to be used by this graphic
*/
public void setModel(final Model model) {
this.model = model;
controller.setModel(model);
}
public Stroke getActiveStroke() {
return activeStroke;
}
public void setActiveStroke(final Stroke activeStroke) {
this.activeStroke = activeStroke;
}
public Stroke getNormalStroke() {
return normalStroke;
}
public void setNormalStroke(final Stroke normalStroke) {
this.normalStroke = normalStroke;
}
/**
*
* @return the controller for user interactions
*/
public Controller getController() {
return controller;
}
private void setControl(Controller controller) {
this.controller = controller;
InputMap map = new ComponentInputMap(this);
map.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.ALT_MASK), "add");
ActionMap am = new ActionMap();
am.put("add", controller.getAction(Controller.ADD));
setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, map);
setActionMap(am);
}
@Override
public Dimension getPreferredSize() {
Rectangle bounds = null;
List<Element> elements = model.getElements();
if (elements.size() == 0) {
bounds = new Rectangle();
} else {
bounds = model.getBounds(elements.get(0).getBounds());
}
preferredSize.width = bounds.width;
preferredSize.height = bounds.height;
return preferredSize;
}
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Element element : model.getElements()) {
g2d.setStroke(normalStroke);
renderer.setText(element.getText());
Rectangle bounds = element.getBounds();
g2d.setColor(element.getColor());
g2d.fillRect(bounds.x - 3, bounds.y, bounds.width + 6, bounds.height);
g2d.setColor(Color.BLACK);
renderer.setBackground(element.getColor());
SwingUtilities.paintComponent(g2d, renderer, this, bounds);
if (element == model.getActiveElement()) {
g2d.setStroke(activeStroke);
}
g2d.drawRect(bounds.x - 3, bounds.y, bounds.width + 6, bounds.height);
}
}
}
package graphic;
/**
* Controller.java
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.List;
import java.beans.*;
import java.io.*;
public class Controller extends MouseInputAdapter {
private WindowListener saveOnClose = (WindowListener) EventHandler.create(
WindowListener.class, this, "saveModel", null, "windowClosing");
private DocumentListener documentHandler = (DocumentListener) EventHandler.create(
DocumentListener.class, this, "processText", null);
private Action addAction;
private Model model;
private Graphic graphic;
private JTextArea editor;
//
private Point hitPoint;
private String filename = "Graphic.xml";
private boolean userEditing;
public final static int ADD = 0;
public Controller() {
hitPoint = new Point(20, 20);
userEditing = true;
//
addAction = new AbstractAction("Element") {
public void actionPerformed(ActionEvent e) {
addElement();
}
};
}
/**
*
* @return a WindowListener for saving the model on windowClosing
*/
public WindowListener getSaveOnClose() {
return saveOnClose;
}
/**
* Use this method to set actions to buttons and menu items
* @param action the constant identifying the action
* @return the action identified by the parameter
*/
public Action getAction(final int action) {
switch (action) {
case ADD:
return addAction;
default:
return null;
}
}
protected void setModel(final Model model) {
this.model = model;
Element activeElement = model.getActiveElement();
if (activeElement != null) {
editor.setText(activeElement.getText());
}
}
protected void setView(final Graphic graphic) {
this.graphic = graphic;
graphic.addMouseListener(this);
graphic.addMouseMotionListener(this);
}
/**
* This method should be called after the model is set
* @param editor the JTextArea used for text editing
*/
public void setEditor(final JTextArea editor) {
if (model == null) {
throw new RuntimeException("Model ist not set");
}
this.editor = editor;
editor.getDocument().addDocumentListener(documentHandler);
Element activeElement = model.getActiveElement();
if (activeElement != null) {
editor.setText(activeElement.getText());
}
}
@Override
public void mouseDragged(final MouseEvent evt) {
Element activeElement = model.getActiveElement();
if (activeElement != null) {
Point dragPoint = evt.getPoint();
int dx = dragPoint.x - hitPoint.x;
int dy = dragPoint.y - hitPoint.y;
activeElement.getBounds().translate(dx, dy);
hitPoint = dragPoint;
graphic.repaint();
}
}
@Override
public void mousePressed(final MouseEvent evt) {
hitPoint = evt.getPoint();
List<Element> hitElements = model.getElementsAt(hitPoint);
Element hitElement = null;
if (hitElements.size() > 0) {
hitElement = hitElements.get(0);
}
model.setActiveElement(hitElement);
editText(hitElement);
}
@Override
public void mouseReleased(final MouseEvent evt) {
graphic.revalidate();
graphic.repaint();
}
private void scrollToVisible(final Element element) {
if (element != null) {
Rectangle bounds = new Rectangle(element.getBounds());
bounds.x -= 10;
bounds.y -= 10;
bounds.width += 20;
bounds.height += 20;
graphic.scrollRectToVisible(bounds);
}
}
private void addElement() {
Element added = model.add(hitPoint);
graphic.revalidate();
scrollToVisible(added);
graphic.repaint();
}
/**
* Save the Model to file
*/
public void saveModel() {
try {
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(filename)));
encoder.writeObject(model);
encoder.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Load the Model from file
* @return the Model loaded
*/
public Model loadModel() {
XMLDecoder decoder = null;
Object result = null;
try {
decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream(filename)));
result = decoder.readObject();
decoder.close();
} catch (FileNotFoundException ex) {
}
return (Model) result;
}
/**
* Update the active element while the user is typing text into editor area.
* Called by internal DocumentListener.
* Generally there is no reason to call this method from client application.
*
*/
public void processText() {
if (userEditing) {
Element activeElement = model.getActiveElement();
if (activeElement != null) {
activeElement.setText(editor.getText());
activeElement.pack();
//refresh the view:
graphic.revalidate();
scrollToVisible(activeElement);
graphic.repaint();
} else {
JOptionPane.showMessageDialog(graphic, "Please select an element " +
"before typing text,\n or else the text will be lost.",
"Controller message", JOptionPane.ERROR_MESSAGE);
}
}
}
/**
*
* @param element the element whose text is to be displayed in the editor area
*/
private void editText(final Element element) {
userEditing = false;
editor.setText(element == null ? "" : element.getText());
graphic.repaint();
Runnable action = new Runnable() {
public void run() {
userEditing = true;
}
};
SwingUtilities.invokeLater(action);
}
}
package sample;
/*
* GraphicDemo.java
*
*/
import java.awt.*;
import javax.swing.*;
import graphic.*;
public class GraphicDemo extends JFrame {
private JButton btAdd;
private JTextArea editor;
private JScrollPane scrollEditor;
private JScrollPane scroller;
private JSplitPane splitPane;
private JToolBar toolbar;
private Graphic graphic;
private Controller controller;
public GraphicDemo() {
super("GraphicDemo");
graphic = new Graphic();
controller = graphic.getController();
addWindowListener(controller.getSaveOnClose());
initComponents();
scroller.setViewportView(graphic);
controller.setEditor(editor);
Model modelLoaded = controller.loadModel();
if (modelLoaded != null) {
//set the model loaded from file:
graphic.setModel(modelLoaded);
}
splitPane.setResizeWeight(1);//1 = top component gets all extra space
Runnable setDividerLocation = new Runnable() {
public void run() {
splitPane.setDividerLocation(0.8d);
editor.requestFocusInWindow();
}
};
SwingUtilities.invokeLater(setDividerLocation);
}
private void initComponents() {
toolbar = new JToolBar();
btAdd = new JButton();
splitPane = new JSplitPane();
scroller = new JScrollPane();
scrollEditor = new JScrollPane();
editor = new JTextArea();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
toolbar.setRollover(true);
btAdd.setAction(controller.getAction(Controller.ADD));
btAdd.setText("Element");
btAdd.setFocusable(false);
btAdd.setHorizontalTextPosition(SwingConstants.CENTER);
btAdd.setVerticalTextPosition(SwingConstants.BOTTOM);
toolbar.add(btAdd);
getContentPane().add(toolbar, BorderLayout.PAGE_START);
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setTopComponent(scroller);
scrollEditor.setViewportView(editor);
splitPane.setBottomComponent(scrollEditor);
getContentPane().add(splitPane, BorderLayout.CENTER);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((screenSize.width-800)/2, (screenSize.height-600)/2, 800, 600);
}
public static void main(final String[] args) {
Runnable gui = new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
new GraphicDemo().setVisible(true);
}
};
//GUI must start on EventDispatchThread:
SwingUtilities.invokeLater(gui);
}
}