Verschiebbare Elemente in einem rollbaren Container: Unterschied zwischen den Versionen
(kein Unterschied)
|
Version vom 4. April 2010, 09:35 Uhr
Vielleicht möchtest du dieses Beispiel als Ausgangspunkt nehmen, um verschiebbare Elemente in einem Rollbaren Container zu implementieren: <code=java>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(); }
}</code=java>
<code=java>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; }
}</code=java>
<code=java>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); } }
}</code=java>
<code=java>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);
}
}</code=java>
<code=java>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); }
}</code=java>