userwindowlistener.java
字号:
package piy;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
/**
* Listens on windows and the underlying components. When the mouse is clicked, the relevant
* component becomes selected, or if the mode is set to add component, a component is added.
* @author David Vivash
* @version 1.0.2, 18/4/01
*/
public final class UserWindowListener implements Observer
{
protected static UserWindowListener instance = null;
//selected component border information
protected static int selectedBorderWidth = 5;
protected static Color selectedBorderColor = Color.yellow;
//selected component's regions relative to the glasspane's (0,0) coords
private Rectangle[] selectedRegion = new Rectangle[9];
//State constants denote what will happen on the next mouse click
protected static final int ADD_COMPONENT = 1; //clicking and dragging on a window will add a component/container
protected static final int SELECT = 2; //clicking on a window/component/container will select it
protected static final int RESIZE_COMPONENT = 3; //dragging the mouse resizes a component/container
protected static final int MOVE_COMPONENT = 4; //dragging the mouse moves a component/container
//current edit type from the constants above
private static int editType = SELECT;
//What has currently been selected
private Component selectedComponent = null;
private JFrame selectedWindow = null;
private JFrame oldWindow = null; //the previously selected window
/**
* Private constructor only callable from this class.
*/
private UserWindowListener() {
UserWindowListener.instance = this;
PIY.getInstance().addObserver(this);
}
/**
* Get the instance of this class that is being used.
* @return the only allowed instance of this class
*/
protected static UserWindowListener getInstance() {
if (instance == null) instance = new UserWindowListener();
return instance;
}
/**
* Listens on a particular frame and across all components on that frame.
* (Changes the frame glasspane). This should be used on <i>all</i> UserWindows
* being editted. The frame being listened on should be visible.
* @param frame the JFrame (UserWindow) to listen on
*/
public void listenOnFrame(JFrame frame) {
PIYGlassPane pane = new PIYGlassPane((UserWindow)frame);
frame.setGlassPane(pane);
frame.setVisible(true);
pane.setVisible(true); //pane has to be set visible after the frame is
pane.repaint();
}
/**
* "Selects" the specified component. That is, it places a border around the component
* which allows the user to move and resize it. Any previously selected component is
* deselected, and PIY is informed of the SELECT event. If the component specified is
* null, the currently selected component is deselected and no new component is
* selected. In this case, PIY is informed of the DESELECT event.
* @param component the component to select
*/
public void selectComponent(Component component) {
if (component != null)
selectedWindow = getWindow(component);
selectedComponent = component;
if (oldWindow != null) oldWindow.repaint();
oldWindow = selectedWindow;
if (selectedWindow != null) selectedWindow.repaint();
setupRegions();
//tell PIY of the selection
PIY.getInstance().actionPerformed(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED,
selectedComponent != null ? PIY.COMPONENT_SELECTED :
PIY.COMPONENT_DESELECTED));
}
/**
* Sets up the bounding border on the selected component
*/
private void setupRegions() {
if ((selectedComponent == null) || (selectedWindow == null)) {
//reset all regions
for (int i=0; i<6; i++) selectedRegion[i] = new Rectangle(-1,-1,0,0);
} else if (selectedWindow.isShowing()) {
Point pos = ((PIYGlassPane)selectedWindow.getGlassPane()).getPaneLocation(selectedComponent);
selectedRegion[0] = new Rectangle(pos, selectedComponent.getSize()); //centre
int w = selectedBorderWidth;
int width = selectedComponent.getWidth(), height = selectedComponent.getHeight();
selectedRegion[1] = new Rectangle(pos.x-w, pos.y-w, 2*w, 2*w); //top/left
selectedRegion[2] = new Rectangle(pos.x+width-w, pos.y-w, 2*w, 2*w); //top/right
selectedRegion[3] = new Rectangle(pos.x-w, pos.y+height-w, 2*w, 2*w); //bottom/left
selectedRegion[4] = new Rectangle(pos.x+width-w, pos.y+height-w, 2*w, 2*w); //bottom/right
selectedRegion[5] = new Rectangle(pos.x+w, pos.y-w, width-w, w); //top border
selectedRegion[6] = new Rectangle(pos.x+w, pos.y+height, width-w, w); //bottom border
selectedRegion[7] = new Rectangle(pos.x-w, pos.y+w, w, height-w); //left border
selectedRegion[8] = new Rectangle(pos.x+width, pos.y+w, w, height-w); //right border
}
}
public UserWindow getCurrentWindow() { return (UserWindow)selectedWindow; }
public void setCurrentWindow(JFrame win) { selectedWindow = win; }
public Component getSelectedComponent() { return selectedComponent; }
/**
* Reinitialises the bounding box to reflect a change in position or size of
* the currently selected component
*/
public void validateBoundingBox() {
setupRegions();
if (selectedWindow != null) selectedWindow.repaint();
}
/**
* Get the JFrame on which the specified component is situated.
* @param component the component placed on a userwindow
* @return the JFrame on which the component is placed
*/
private JFrame getWindow(Component component) {
Component parent = component;
while (!( (parent = parent.getParent()) instanceof JFrame) ) { }
return (JFrame)parent;
}
protected static int getEditType() { return editType; }
protected static void setEditType(int type) { editType = type; }
protected Rectangle[] getSelectedRegion() { return selectedRegion; }
//------------- Observer Method -------------------
public void update(Observable o, Object arg) {
ActionEvent e = (ActionEvent)arg;
if ( (e.getActionCommand().equals(PIY.COMPONENT_CHOSEN)) ||
(e.getActionCommand().equals(PIY.CONTAINER_CHOSEN)) ) {
if (selectedComponent != null) selectComponent(null); //deselect the currently selected compponent/container
editType = ADD_COMPONENT;
} else if (e.getActionCommand().equals(PIY.COMPONENT_SELECTED)) {
editType = SELECT;
} else if (e.getActionCommand().equals(PIY.COMPONENT_DESELECTED)) {
editType = SELECT;
}
}
}
/**
* This pane is placed over the top of the content pane, and acts as a sheet of glass.
* Input events are trapped by this so undelying components do not receive event
* notifications. The primary use of this class is to implement the selection,
* resizing and moving of the underlying components.
* @author David Vivash
* @version 1.3, 19/04/01
*/
final class PIYGlassPane extends JComponent implements MouseInputListener {
private int startx=0, starty=0, endx=0, endy=0, diffx=0, diffy=0;
private UserWindow window = null;
private Container clickedIn = null;
//the regions that a mouse can be over on a component
private static final int NONE = -1;
private static final int CENTRE = 0;
private static final int TOP_LEFT = 1;
private static final int TOP_RIGHT = 2;
private static final int BOTTOM_LEFT = 3;
private static final int BOTTOM_RIGHT = 4;
private static final int TOP_BORDER = 5;
private static final int BOTTOM_BORDER = 6;
private static final int LEFT_BORDER = 7;
private static final int RIGHT_BORDER = 8;
private int inside = NONE; //which region on the selected component the mouse is over
/**
* Set up a glass pane on a particular user window. The constructor sets up the pane, but
* doesn't add it to the specified window.
* @param window the user window on which to add the pane
*/
public PIYGlassPane(UserWindow window) {
addMouseListener(this);
addMouseMotionListener(this);
this.window = window;
}
/** Java 1.3 gets moody if we don't have this */
//public boolean isOpaque() { return false; }
/**
* Draws a rectangle onto the graphics context. If the width or height are negative,
* the rectangle is drawn to the left or upwards respectively.
*/
private void drawRect(Graphics g, int x, int y, int width, int height) {
if (width < 0) {
x+=width;
width = -width;
}
if (height < 0) {
y+=height;
height = -height;
}
g.drawRect(x, y, width, height);
}
/**
* Gets the position relative to this pane of the specified component.
* @param component the component whose location is to be determined
* @return the location of the component relative to (0,0) on this glass pane
*/
protected Point getPaneLocation(Component component) {
Point location = component.getLocationOnScreen();
Point thisLocation = getLocationOnScreen();
return new Point(location.x - thisLocation.x, location.y - thisLocation.y);
}
/**
* Checks to see which container contains the point specified, then returns the position
* of the point relative to the position of that container.
* @param the container in which the point should be moved relative to
* @param pos the point to be returned relative to its container
* @return the point relative to the container
*/
private Point getPointLocation(Container container, Point pos) {
int screenx = pos.x + getLocationOnScreen().x - container.getLocationOnScreen().x;
int screeny = pos.y + getLocationOnScreen().y - container.getLocationOnScreen().y;
return new Point(screenx, screeny);
}
//standard paint method which paints over the top of components. This is only called if
//this pane is "visible" - the pane can only be made visible once the frame it is contained
//within is visible.
public void paint(Graphics g) {
super.paint(g);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -