|
|
Строка 1: |
Строка 1: |
- | In this part of the Java Swing tutorial, we will create a resizable component.
| |
| | | |
- | == Resizable component ==
| |
- |
| |
- | Resizable components are most often used when creating charts, diagrams and similar. The most common resizable component is a chart in a spreadsheet application. For example, when we create a chart in a OpenOffice application. The chart can be moved over the grid widget of the application and resized.
| |
- |
| |
- | In order to create a component that can be freely dragged over a panel, we need a panel with absolute positioning enabled.
| |
- | We must not use a layout manager.
| |
- | In our example, we will create a component (a JPanel) that we can freely move over a parent window and resize.
| |
- |
| |
- | In order to distinguish which component has a focus, we draw 8 small rectangles on the border of our resizable component.
| |
- | This way we know, that the component has focus. The rectangles serve as a dragging points, where we can draw the component and start resizing. I have learnt to use resizable components from <a href="http://www.jroller.com/santhosh/category/Swing">this</a> blog.
| |
- |
| |
- | <source lang="java">
| |
- | package resizablecomponent;
| |
- |
| |
- | import java.awt.Color;
| |
- | import java.awt.Dimension;
| |
- | import java.awt.event.MouseAdapter;
| |
- | import java.awt.event.MouseEvent;
| |
- |
| |
- | import javax.swing.JFrame;
| |
- | import javax.swing.JPanel;
| |
- |
| |
- |
| |
- | /* ResizableComponent.java */
| |
- |
| |
- | public class ResizableComponent extends JFrame {
| |
- |
| |
- | private JPanel panel = new JPanel(null);
| |
- | private Resizable resizer;
| |
- |
| |
- |
| |
- | public ResizableComponent() {
| |
- |
| |
- | add(panel);
| |
- |
| |
- | JPanel area = new JPanel();
| |
- | area.setBackground(Color.white);
| |
- | resizer = new Resizable(area);
| |
- | resizer.setBounds(50, 50, 200, 150);
| |
- | panel.add(resizer);
| |
- |
| |
- |
| |
- | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
| |
- | setSize(new Dimension(350, 300));
| |
- | setTitle("Resizable Component");
| |
- | setLocationRelativeTo(null);
| |
- |
| |
- | addMouseListener(new MouseAdapter() {
| |
- | public void mousePressed(MouseEvent me) {
| |
- |
| |
- | requestFocus();
| |
- | resizer.repaint();
| |
- | }
| |
- | });
| |
- | }
| |
- |
| |
- | public static void main(String[] args) {
| |
- | ResizableComponent rc = new ResizableComponent();
| |
- | rc.setVisible(true);
| |
- | }
| |
- | }
| |
- | </source>
| |
- |
| |
- | The <b>ResizableComponent</b> sets up the panel and the component.
| |
- |
| |
- | <source lang="java">
| |
- | private JPanel panel = new JPanel(null);
| |
- | </source>
| |
- |
| |
- | We have already mentioned, that we cannot use any layout manager. We must use absolute positioning for resizable component.
| |
- | By providing null to the constructor, we create a panel with absolute positioning.
| |
- |
| |
- | <source lang="java">
| |
- | addMouseListener(new MouseAdapter() {
| |
- | public void mousePressed(MouseEvent me) {
| |
- |
| |
- | requestFocus();
| |
- | resizer.repaint();
| |
- | }
| |
- | });
| |
- | </source>
| |
- |
| |
- | If we press on the parent panel, e.g outside the resizable component, we grab focus and repaint the component. The rectangles over the border will disappear.
| |
- |
| |
- | <source lang="java">
| |
- | package resizablecomponent;
| |
- |
| |
- | import java.awt.Color;
| |
- | import java.awt.Component;
| |
- | import java.awt.Cursor;
| |
- | import java.awt.Graphics;
| |
- | import java.awt.Insets;
| |
- | import java.awt.Rectangle;
| |
- | import java.awt.event.MouseEvent;
| |
- |
| |
- | import javax.swing.SwingConstants;
| |
- | import javax.swing.border.Border;
| |
- |
| |
- | // ResizableBorder.java
| |
- |
| |
- | public class ResizableBorder implements Border {
| |
- | private int dist = 8;
| |
- |
| |
- | int locations[] =
| |
- | {
| |
- | SwingConstants.NORTH, SwingConstants.SOUTH, SwingConstants.WEST,
| |
- | SwingConstants.EAST, SwingConstants.NORTH_WEST,
| |
- | SwingConstants.NORTH_EAST, SwingConstants.SOUTH_WEST,
| |
- | SwingConstants.SOUTH_EAST
| |
- | };
| |
- |
| |
- | int cursors[] =
| |
- | {
| |
- | Cursor.N_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR,
| |
- | Cursor.E_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR,
| |
- | Cursor.SW_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR
| |
- | };
| |
- |
| |
- | public ResizableBorder(int dist) {
| |
- | this.dist = dist;
| |
- | }
| |
- |
| |
- | public Insets getBorderInsets(Component component) {
| |
- | return new Insets(dist, dist, dist, dist);
| |
- | }
| |
- |
| |
- | public boolean isBorderOpaque() {
| |
- | return false;
| |
- | }
| |
- |
| |
- | public void paintBorder(Component component, Graphics g, int x, int y,
| |
- | int w, int h) {
| |
- | g.setColor(Color.black);
| |
- | g.drawRect(x + dist / 2, y + dist / 2, w - dist, h - dist);
| |
- |
| |
- | if (component.hasFocus()) {
| |
- |
| |
- |
| |
- | for (int i = 0; i < locations.length; i++) {
| |
- | Rectangle rect = getRectangle(x, y, w, h, locations[i]);
| |
- | g.setColor(Color.WHITE);
| |
- | g.fillRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
| |
- | g.setColor(Color.BLACK);
| |
- | g.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
| |
- | }
| |
- | }
| |
- | }
| |
- |
| |
- | private Rectangle getRectangle(int x, int y, int w, int h, int location) {
| |
- | switch (location) {
| |
- | case SwingConstants.NORTH:
| |
- | return new Rectangle(x + w / 2 - dist / 2, y, dist, dist);
| |
- | case SwingConstants.SOUTH:
| |
- | return new Rectangle(x + w / 2 - dist / 2, y + h - dist, dist,
| |
- | dist);
| |
- | case SwingConstants.WEST:
| |
- | return new Rectangle(x, y + h / 2 - dist / 2, dist, dist);
| |
- | case SwingConstants.EAST:
| |
- | return new Rectangle(x + w - dist, y + h / 2 - dist / 2, dist,
| |
- | dist);
| |
- | case SwingConstants.NORTH_WEST:
| |
- | return new Rectangle(x, y, dist, dist);
| |
- | case SwingConstants.NORTH_EAST:
| |
- | return new Rectangle(x + w - dist, y, dist, dist);
| |
- | case SwingConstants.SOUTH_WEST:
| |
- | return new Rectangle(x, y + h - dist, dist, dist);
| |
- | case SwingConstants.SOUTH_EAST:
| |
- | return new Rectangle(x + w - dist, y + h - dist, dist, dist);
| |
- | }
| |
- | return null;
| |
- | }
| |
- |
| |
- | public int getCursor(MouseEvent me) {
| |
- | Component c = me.getComponent();
| |
- | int w = c.getWidth();
| |
- | int h = c.getHeight();
| |
- |
| |
- | for (int i = 0; i < locations.length; i++) {
| |
- | Rectangle rect = getRectangle(0, 0, w, h, locations[i]);
| |
- | if (rect.contains(me.getPoint()))
| |
- | return cursors[i];
| |
- | }
| |
- |
| |
- | return Cursor.MOVE_CURSOR;
| |
- | }
| |
- | }
| |
- |
| |
- | </source>
| |
- |
| |
- | The <b>ResizableBorder</b> is responsible for drawing the border of the component and determining the type of the cursor to use.
| |
- |
| |
- | <source lang="java">
| |
- | int locations[] =
| |
- | {
| |
- | SwingConstants.NORTH, SwingConstants.SOUTH, SwingConstants.WEST,
| |
- | SwingConstants.EAST, SwingConstants.NORTH_WEST,
| |
- | SwingConstants.NORTH_EAST, SwingConstants.SOUTH_WEST,
| |
- | SwingConstants.SOUTH_EAST
| |
- | };
| |
- | </source>
| |
- |
| |
- | These are locations, where we will draw rectangles. These locations are grabbing points, where we can grab the
| |
- | component and resize it.
| |
- |
| |
- | <source lang="java">
| |
- | g.setColor(Color.black);
| |
- | g.drawRect(x + dist / 2, y + dist / 2, w - dist, h - dist);
| |
- | </source>
| |
- |
| |
- | In the <b>paintBorder()</b> method, we draw the border of the resizable component.
| |
- | The upper code draws the outer border of the component.
| |
- |
| |
- | <source lang="java">
| |
- | if (component.hasFocus()) {
| |
- |
| |
- | for (int i = 0; i < locations.length; i++) {
| |
- | Rectangle rect = getRectangle(x, y, w, h, locations[i]);
| |
- | g.setColor(Color.WHITE);
| |
- | g.fillRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
| |
- | g.setColor(Color.BLACK);
| |
- | g.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
| |
- | }
| |
- | }
| |
- |
| |
- | </source>
| |
- |
| |
- | The eight rectangles are drawn only in case that the resizable component has currently focus.
| |
- |
| |
- | Finally, the <b>getCursor()</b> methods gets the cursor type for the grab point in question.
| |
- |
| |
- | <source lang="java">
| |
- | package resizablecomponent;
| |
- |
| |
- | import java.awt.BorderLayout;
| |
- | import java.awt.Component;
| |
- | import java.awt.Cursor;
| |
- | import java.awt.Point;
| |
- | import java.awt.Rectangle;
| |
- | import java.awt.event.MouseEvent;
| |
- |
| |
- | import javax.swing.JComponent;
| |
- | import javax.swing.event.MouseInputAdapter;
| |
- | import javax.swing.event.MouseInputListener;
| |
- |
| |
- | // Resizable.java
| |
- |
| |
- | public class Resizable extends JComponent {
| |
- |
| |
- | public Resizable(Component comp) {
| |
- | this(comp, new ResizableBorder(8));
| |
- | }
| |
- |
| |
- | public Resizable(Component comp, ResizableBorder border) {
| |
- | setLayout(new BorderLayout());
| |
- | add(comp);
| |
- | addMouseListener(resizeListener);
| |
- | addMouseMotionListener(resizeListener);
| |
- | setBorder(border);
| |
- | }
| |
- |
| |
- | private void resize() {
| |
- | if (getParent() != null) {
| |
- | ((JComponent)getParent()).revalidate();
| |
- | }
| |
- | }
| |
- |
| |
- | MouseInputListener resizeListener = new MouseInputAdapter() {
| |
- | public void mouseMoved(MouseEvent me) {
| |
- | if (hasFocus()) {
| |
- | ResizableBorder border = (ResizableBorder)getBorder();
| |
- | setCursor(Cursor.getPredefinedCursor(border.getCursor(me)));
| |
- | }
| |
- | }
| |
- |
| |
- | public void mouseExited(MouseEvent mouseEvent) {
| |
- | setCursor(Cursor.getDefaultCursor());
| |
- | }
| |
- |
| |
- | private int cursor;
| |
- | private Point startPos = null;
| |
- |
| |
- | public void mousePressed(MouseEvent me) {
| |
- | ResizableBorder border = (ResizableBorder)getBorder();
| |
- | cursor = border.getCursor(me);
| |
- | startPos = me.getPoint();
| |
- | requestFocus();
| |
- | repaint();
| |
- | }
| |
- |
| |
- | public void mouseDragged(MouseEvent me) {
| |
- |
| |
- | if (startPos != null) {
| |
- |
| |
- | int x = getX();
| |
- | int y = getY();
| |
- | int w = getWidth();
| |
- | int h = getHeight();
| |
- |
| |
- | int dx = me.getX() - startPos.x;
| |
- | int dy = me.getY() - startPos.y;
| |
- |
| |
- | switch (cursor) {
| |
- | case Cursor.N_RESIZE_CURSOR:
| |
- | if (!(h - dy < 50)) {
| |
- | setBounds(x, y + dy, w, h - dy);
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.S_RESIZE_CURSOR:
| |
- | if (!(h + dy < 50)) {
| |
- | setBounds(x, y, w, h + dy);
| |
- | startPos = me.getPoint();
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.W_RESIZE_CURSOR:
| |
- | if (!(w - dx < 50)) {
| |
- | setBounds(x + dx, y, w - dx, h);
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.E_RESIZE_CURSOR:
| |
- | if (!(w + dx < 50)) {
| |
- | setBounds(x, y, w + dx, h);
| |
- | startPos = me.getPoint();
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.NW_RESIZE_CURSOR:
| |
- | if (!(w - dx < 50) && !(h - dy < 50)) {
| |
- | setBounds(x + dx, y + dy, w - dx, h - dy);
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.NE_RESIZE_CURSOR:
| |
- | if (!(w + dx < 50) && !(h - dy < 50)) {
| |
- | setBounds(x, y + dy, w + dx, h - dy);
| |
- | startPos = new Point(me.getX(), startPos.y);
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.SW_RESIZE_CURSOR:
| |
- | if (!(w - dx < 50) && !(h + dy < 50)) {
| |
- | setBounds(x + dx, y, w - dx, h + dy);
| |
- | startPos = new Point(startPos.x, me.getY());
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.SE_RESIZE_CURSOR:
| |
- | if (!(w + dx < 50) && !(h + dy < 50)) {
| |
- | setBounds(x, y, w + dx, h + dy);
| |
- | startPos = me.getPoint();
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | case Cursor.MOVE_CURSOR:
| |
- | Rectangle bounds = getBounds();
| |
- | bounds.translate(dx, dy);
| |
- | setBounds(bounds);
| |
- | resize();
| |
- | }
| |
- |
| |
- |
| |
- | setCursor(Cursor.getPredefinedCursor(cursor));
| |
- | }
| |
- | }
| |
- |
| |
- | public void mouseReleased(MouseEvent mouseEvent) {
| |
- | startPos = null;
| |
- | }
| |
- | };
| |
- | }
| |
- |
| |
- | </source>
| |
- |
| |
- | The <b>Resizable</b> class represents the component, that is being resized and moved on the window.
| |
- |
| |
- | <source lang="java">
| |
- | private void resize() {
| |
- | if (getParent() != null) {
| |
- | ((JComponent)getParent()).revalidate();
| |
- | }
| |
- | }
| |
- | </source>
| |
- |
| |
- | The <b>revalidate()</b> method
| |
- | will cause the component to be redrawn.
| |
- |
| |
- |
| |
- | <source lang="java">
| |
- | MouseInputListener resizeListener = new MouseInputAdapter() {
| |
- | public void mouseMoved(MouseEvent me) {
| |
- | if (hasFocus()) {
| |
- | ResizableBorder border = (ResizableBorder)getBorder();
| |
- | setCursor(Cursor.getPredefinedCursor(border.getCursor(me)));
| |
- | }
| |
- | }
| |
- | </source>
| |
- |
| |
- | We change the cursor type, when we hover the cursor over the grip points. The cursor type changes only if the component has focus.
| |
- |
| |
- | <source lang="java">
| |
- | public void mousePressed(MouseEvent me) {
| |
- | ResizableBorder border = (ResizableBorder)getBorder();
| |
- | cursor = border.getCursor(me);
| |
- | startPos = me.getPoint();
| |
- | requestFocus();
| |
- | repaint();
| |
- | }
| |
- | </source>
| |
- |
| |
- | If we click on the resizable component, we change the cursor, get the starting point of dragging, give focus to the component and redraw it.
| |
- |
| |
- | <source lang="java">
| |
- | int x = getX();
| |
- | int y = getY();
| |
- | int w = getWidth();
| |
- | int h = getHeight();
| |
- |
| |
- | int dx = me.getX() - startPos.x;
| |
- | int dy = me.getY() - startPos.y;
| |
- | </source>
| |
- |
| |
- | In the <b>mouseDragged()</b> method, we determine the x, y coordinates of the cursor, width and height of the
| |
- | component. We calculate the distances, that we make during the mouse drag event.
| |
- |
| |
- | <source lang="java">
| |
- | case Cursor.N_RESIZE_CURSOR:
| |
- | if (!(h - dy < 50)) {
| |
- | setBounds(x, y + dy, w, h - dy);
| |
- | resize();
| |
- | }
| |
- | break;
| |
- |
| |
- | </source>
| |
- |
| |
- | For all resizing we ensure, that the component is not smaller than 50 px. Otherwise, we could make it so small, that we would eventually hide the component. The <b>setBounds()</b> method relocates and resizes the component.
| |
- |
| |
- | [[image: java_swing_resizablecomponent.png | center]]
| |
- |
| |
- | [[Категория:Java]]
| |