JComponentBounds

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen

Die Klasse und ein Anwendungsbeispiel

JComponentBounds

Die Klasse JComponentBounds erlaubt es, JComponents zu verschieben und in der Grösse zu verändern. Die Klasse "PictureDemo" weiter unten zeigt ein Anwendungsbeispiel.

/*
 * JComponentBounds.java
 *
 * This class aims at making any JComponent resizable
 * simply by putting it inside a JInternalFrame.
 * The wrapped JComponent is made moveable
 * by means of a MouseInputAdapter.
 * The class includes a "snap to grid" option.
 *
 * author: Andre Uhres
 * update April 15, 2010 at 6:00
 * update December 21, 2010 at 15:00
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.*;

public class JComponentBounds extends JInternalFrame {

    public static final int FOCUS_GAINED = 97531;
    private JComponent componentsContainer;
    private boolean focused;
    private JComponent comp;
    private static final Color TRANSPARENT = new Color(0.0f, 0.0f, 0.0f, 0.0f);
    public static final int MARGIN = 5;
    private KeyAdapter kl;
    private MouseInputAdapter ml;
    private ComponentAdapter cl;
    private boolean snapToGrid;

    public JComponentBounds() {
        this(new JLabel("jComponentBounds"));
    }

    public JComponentBounds(final JComponent comp) {
        this(comp, 0, 0, false);
    }

    public JComponentBounds(final JComponent comp, final boolean focused) {
        this(comp, 0, 0, focused);
    }

    public JComponentBounds(final JComponent comp, final int x, final int y,
            final boolean focused) {
        super();
        this.comp = comp;
        this.focused = focused;
        setBounds(x, y,
                comp.getPreferredSize().width, comp.getPreferredSize().height);
        setResizable(true);
        setVisible(true);
        setOpaque(false);
        setBackground(TRANSPARENT);
        ((BasicInternalFrameUI) getUI()).setNorthPane(null);
        setBorder(BorderFactory.createEmptyBorder(
                MARGIN, MARGIN, MARGIN, MARGIN));
        comp.setFocusable(true);
        add(comp);
        ml = new MouseInputAdapter() {

            private Point p1;

            @Override
            public void mousePressed(final MouseEvent e) {
                p1 = e.getPoint();
                componentsContainer = (JComponent) getParent();
                e.setSource(JComponentBounds.this);
                //componentsContainer might use the mousePressed event
                //to take hidden components to the top:
                componentsContainer.dispatchEvent(e);
            }

            @Override
            public void mouseReleased(final MouseEvent e) {
                componentsContainer = (JComponent) getParent();
                e.setSource(JComponentBounds.this);
                //componentsContainer might use the mouseReleased event
                //to take hidden components to the top:
                componentsContainer.dispatchEvent(e);
            }

            @Override
            public void mouseDragged(final MouseEvent e) {
                if (!JComponentBounds.this.isFocused()) {
                    return;
                }
                //drag operation:
                Point p2 = e.getPoint();
                Point loc = getLocation();
                loc.translate(p2.x - p1.x, p2.y - p1.y);
                setLocation(loc);
                componentsContainer = (JComponent) getParent();
                //auto scroll:
                componentsContainer.scrollRectToVisible(
                        new Rectangle(loc.x, loc.y, getWidth(), getHeight()));
                //componentsContainer might use the focusGained event
                //to keep the dragged component in front:
                FocusListener[] focusListeners = componentsContainer.getFocusListeners();
                if (focusListeners != null && focusListeners.length > 0) {
                    FocusListener fl = focusListeners[0];
                    fl.focusGained(
                            new FocusEvent(JComponentBounds.this,
                            JComponentBounds.FOCUS_GAINED));
                }
            }
        };
        kl = new KeyAdapter() {

            @Override
            public void keyPressed(final KeyEvent e) {
                componentsContainer = (JComponent) getParent();
                //componentsContainer might use the keyPressed event
                //to delete the component:
                componentsContainer.dispatchEvent(e);
            }
        };
        cl = new ComponentAdapter() {

            @Override
            public void componentResized(final ComponentEvent e) {
                ((JComponent) e.getSource()).revalidate();
                componentsContainer = (JComponent) getParent();
                //componentsContainer might use the componentResized event
                //to transfer focus to the resizing component:
                if(componentsContainer != null){
                    componentsContainer.dispatchEvent(e);
                }
            }

            @Override
            public void componentMoved(final ComponentEvent e) {
                ((JComponent) e.getSource()).revalidate();
            }
        };
        addAllListeners();
    }

    /* Move and resize this component.
     * This method has been overridden to implement the "snap to grid" option.
     */
    @Override
    public void reshape(final int x, final int y,
            final int width, final int height) {
        if (snapToGrid) {
            //convert all parameters to multiples of MARGIN:
            int gridx = x / MARGIN * MARGIN;
            int gridy = y / MARGIN * MARGIN;
            int gridwidth = width / MARGIN * MARGIN;
            int gridheight = height / MARGIN * MARGIN;
            //if not horizontally on the grid, round up the grid width:
            if (gridx != x && gridwidth != width) {
                gridwidth += MARGIN;
            }
            //if not vertically on the grid, round up the grid height:
            if (gridy != y && gridheight != height) {
                gridheight += MARGIN;
            }
            //snap to the grid:
            super.reshape(gridx, gridy, gridwidth, gridheight);
        } else {
            super.reshape(x, y, width, height);
        }
    }

    public boolean isSnapToGrid() {
        return snapToGrid;
    }

    public void setSnapToGrid(final boolean snapToGrid) {
        this.snapToGrid = snapToGrid;
    }

    private void addAllListeners() {
        comp.addMouseListener(ml);
        comp.addMouseMotionListener(ml);
        comp.addKeyListener(kl);
        addComponentListener(cl);
    }

    public void removeAllListeners() {
        comp.removeMouseListener(ml);
        comp.removeMouseMotionListener(ml);
        comp.removeKeyListener(kl);
        removeComponentListener(cl);
    }

    public void setComponent(final JComponent comp) {
        //remove old component:
        removeAllListeners();
        remove(this.comp);
        //add new component:
        this.comp = comp;
        comp.setFocusable(true);
        add(comp);
        addAllListeners();
    }

    public void setFocused(final boolean focused) {
        this.focused = focused;
        repaint();
    }

    public boolean isFocused() {
        return focused;
    }

    public Rectangle getComponentRect() {
        Insets insets = getInsets();
        Rectangle rect = getBounds();
        rect.x += insets.left;
        rect.y += insets.top;
        rect.width -= (insets.right + insets.left);
        rect.height -= (insets.top + insets.bottom);
        return rect;
    }
}

PictureDemo

Die Klasse "PictureDemo" ermöglicht das Laden eines Bildes durch einen Klick auf das Fenster.

PictureDemo1.jpg

Das geladene Bild kann man anschließend in der Größe und Position verändern.

PictureDemo.jpg

/*
 * PictureDemo.java
 */

import container.JComponentBounds;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import javax.imageio.*;
import javax.swing.*;


//Model
class PictureStorage extends Observable {

    private BufferedImage data;

    public PictureStorage() {
    }

    public void loadPicture(final String filename) {
        System.out.println("loading " + filename);
        SwingWorker<BufferedImage, Void> loadPicture = new SwingWorker<BufferedImage, Void>() {

            @Override
            protected BufferedImage doInBackground() throws Exception {
                try {
                    data = ImageIO.read(new File(filename));
                } catch (IOException ex) {
                    System.out.println(ex);
                }
                return data;
            }

            @Override
            protected void done() {
                setChanged();
                notifyObservers(data); //sends change notification to the view
            }
        };
        loadPicture.execute();
    }
}

//View
class GUI extends JFrame implements Observer {

    private PictureDemo demo;
    private JComponent picture;
    private JComponentBounds pictureBounds;
    private GUI frame;
    private Image image;

    public GUI(final PictureDemo demo) {
        super();
        this.demo = demo;
        this.init();
    }

    private void init() {
        frame = this;
        setTitle("Demo: click to load picture");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(800, 600);
        setLocationRelativeTo(null);
        addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(final MouseEvent e) {
                FileDialog fileDialog = new FileDialog(frame);
                fileDialog.setVisible(true);
                String dir = fileDialog.getDirectory();
                String file = fileDialog.getFile();
                if (dir != null && file != null) {
                    demo.loadPicture(dir + file);
                }
            }
        });
        //configure picture:
        setLayout(null);
        picture = new JLabel() {

            @Override
            protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
//                g.drawImage(image, 0, 0, this);
                g.drawImage(image, 0, 0, pictureBounds.getWidth(), pictureBounds.getHeight(), this);
            }
        };
        picture.setPreferredSize(new Dimension(100, 100));
        pictureBounds = new JComponentBounds(picture, 10, 10, true);
        pictureBounds.setMinimumSize(new Dimension(40, 20));
//        pictureBounds.setSnapToGrid(true);
        add(pictureBounds);
    }

    public void update(final Observable observable, final Object arg) {
        image = (Image) arg;
        if (image == null) {
            JOptionPane.showMessageDialog(this, "Picture not found");
        } else {
            pictureBounds.setSize(image.getWidth(null), image.getHeight(null));
            picture.setOpaque(true);
            picture.setBackground(Color.LIGHT_GRAY);
            picture.repaint();
        }
    }
}

//Controller
public class PictureDemo {

    private PictureStorage model;

    public PictureDemo() {
        model = new PictureStorage();
        GUI gui = new GUI(this);
        model.addObserver(gui);
        gui.setVisible(true);
    }

    public void loadPicture(final String file) {
        model.loadPicture(file);
    }

    public static void main(final String[] args) {
        Runnable gui = new Runnable() {

            @Override
            public void run() {
                PictureDemo pictureDemo = new PictureDemo();
            }
        };
        //GUI must start on EventDispatchThread:
        SwingUtilities.invokeLater(gui);
    }
}