⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 swingdesigner.java

📁 SWING的界面UI包 SWING的界面UI包
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * BeanDesigner.java
 *
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package dyno.swing.designer.beans;

import dyno.swing.designer.beans.actions.ActionCategory;
import dyno.swing.designer.beans.actions.AlignmentAction;
import dyno.swing.designer.beans.actions.EditingAction;
import dyno.swing.designer.beans.actions.SameSizeAction;
import dyno.swing.designer.beans.actions.ViewAction;
import dyno.swing.designer.beans.events.AddingMouseListener;
import dyno.swing.designer.beans.events.DesignerEditAdapter;
import dyno.swing.designer.beans.events.DesignerEditListener;
import dyno.swing.designer.beans.events.DesignerEvent;
import dyno.swing.designer.beans.events.DesignerStateListener;
import dyno.swing.designer.beans.events.EditingMouseListener;
import dyno.swing.designer.beans.events.HotKeyProxy;
import dyno.swing.designer.beans.location.Location;
import dyno.swing.designer.beans.models.AddingModel;
import dyno.swing.designer.beans.models.SelectionModel;
import dyno.swing.designer.beans.models.StateModel;
import dyno.swing.designer.beans.toolkit.BeanInfoToggleButton;
import dyno.swing.designer.beans.events.EditListenerTable;
import dyno.swing.designer.beans.events.StateListenerTable;
import dyno.swing.designer.beans.toolkit.ComponentPalette;
import dyno.swing.designer.treeview.ComponentTree;
import dyno.swing.designer.treeview.ComponentTreeEvent;
import dyno.swing.designer.treeview.ComponentTreeListener;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.RootPaneContainer;
import javax.swing.Scrollable;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;

/**
 * 设计界面组件。该组件是界面设计工具的核心,主要负责的是被设计界面的显示,界面设计操作状态的
 * 显示,编辑状态的显示等等。
 *
 * @author William Chen
 */
public class SwingDesigner extends JComponent implements Constants, TreeSelectionListener, ComponentTreeListener, Scrollable, InvocationHandler {

    /**
     * 当前正在设计的组件树的根节点。目前只支持JPanel作为根节点。可以很容易的修改使其支持其他
     * 容器。被设计的组件其name属性都不为空,其值为该组件的变量名称。
     */
    private Component rootComponent;
    /**
     * 设计界面的左上角的坐标。目的是留出空间显示设计界面的边框。
     */
    private int leftOffset;
    private int topOffset;
    /**
     * 当前设计界面状态是否是添加模式。界面设计工具的状态可以分编辑状态和添加状态。编辑状态的
     * 设计界面可以选择组件、删除、剪切、粘帖、对其、属性编辑等等操作。添加状态是指在选择组件
     * 之后设计界面所处于的状态。添加状态和编辑状态下鼠标处理方式相差很大,所以分为此两种状态
     */
    private boolean addingMode;
    /**
     * 下面的变量都是非序列化成员,不记录设计状态,只作为设计时临时状态使用。
     */
    //编辑状态时鼠标处理器

    private transient EditingMouseListener editingMouseListener;
    //界面设计器的键盘热键处理器,主要处理编辑如复制、剪切、删除、粘帖等热键

    private transient HotKeyProxy keyListener;
    //添加组件状态下的鼠标处理器

    private transient AddingMouseListener addingMouseListener;
    //编辑状态下的model,存储编辑状态下的临时状态,比如拖拽区域、鼠标热点等等

    private transient StateModel stateModel;
    //添加状态下的model,存储添加状态下的临时状态,比如要添加的组件、当前鼠标位置等等

    private transient AddingModel addingModel;
    //当前负责额外渲染的painter,主要目的用来渲染添加组件的位置提示,它通常由外部类设置,在
    //设计器渲染时被调用渲染这些位置提示。

    private transient Painter painter;
    private boolean invalidated = true;
    //存储被选择组件和剪切板的model

    private transient SelectionModel selectionModel;
    private EditListenerTable edit;
    private StateListenerTable state;
    private VariableSpace space;
    private Border outline_border;
    private Action[] designer_actions;
    private Border inner_border;
    private ComponentPalette palette;
    private LookAndFeel designLnf;
    private LookAndFeel ideLnf;

    public void setPalette(ComponentPalette palette) {
        this.palette = palette;
    }

    public VariableSpace getVariableSpace() {
        return space;
    }

    public Dimension getPreferredSize() {
        Dimension size = rootComponent.getSize();
        Insets insets = getOutlineInsets();
        size.width = 2 * leftOffset + size.width + insets.left + insets.right;
        size.height = 2 * topOffset + size.height + insets.top + insets.bottom;
        return size;
    }

    /** Creates a new instance of BeanDesigner */
    public SwingDesigner() {
        setBackground(Color.white);
        setDoubleBuffered(true);
        space = new VariableSpace();
        designLnf = UIManager.getLookAndFeel();
        ideLnf = UIManager.getLookAndFeel();
        //初始化
        leftOffset = 20;
        topOffset = 20;
        //为了处理键盘事件,需要SwingDesigner能够获取焦点
        setFocusable(true);
        edit = new EditListenerTable();
        state = new StateListenerTable();

        //初始化
        selectionModel = new SelectionModel(this);
        stateModel = new StateModel(this);
        //初始化界面设计工具的UI实例
        updateUI();
        //初始化缺省的设计组件
        initRootComponent();
        //初始化事件处理器
        initializeListener();
    }

    public EditListenerTable getEditListenerTable() {
        return edit;
    }

    public StateListenerTable getStateListenerTable() {
        return state;
    }

    private void initActionListener(Action[] actions) {
        for (Action action : actions) {
            if (action != null) {
                if (action instanceof DesignerEditListener) {
                    addDesignerEditListener((DesignerEditListener) action);
                }
                if (action instanceof DesignerStateListener) {
                    addDesignerStateListener((DesignerStateListener) action);
                }
                if (action instanceof ActionCategory) {
                    Action[] sub = ((ActionCategory) action).getSubActions();
                    initActionListener(sub);
                }
            }
        }
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Container container = (Container) rootComponent;
        Util.layoutContainer(container);
        repaint();
        return null;
    }

    /**
     * 初始化事件处理器,初始状态为编辑状态,所以下初始化并添加编辑类的事件处理器
     */
    private void initializeListener() {
        //点击
        editingMouseListener = new EditingMouseListener(this);
        //热键
        keyListener = new HotKeyProxy(this);
        addMouseMotionListener(editingMouseListener);
        addMouseListener(editingMouseListener);
        addKeyListener(keyListener);
        addInvocationHandler(this);
        addDesignerEditListener(new DesignerEditAdapter() {

                    public void componentMoved(DesignerEvent evt) {
                        setInvalidated(true);
                        repaint();
                    }

                    public void componentResized(DesignerEvent evt) {
                        setInvalidated(true);
                        repaint();
                    }

                    @Override
            public void componentCut(DesignerEvent evt) {
                        setInvalidated(true);
                    }

                    @Override
            public void componentDeleted(DesignerEvent evt) {
                        setInvalidated(true);
                    }

                    @Override
            public void componentPasted(DesignerEvent evt) {
                        setInvalidated(true);
                    }

                    public void componentAdded(DesignerEvent evt) {
                        setInvalidated(true);
                    }

                    public void componentEdited(DesignerEvent evt) {
                        setInvalidated(true);
                        Component comp = evt.getAffectedComponents().get(0);
                        Container par = comp.getParent();
                        if (par != null) {
                            LayoutManager layout = par.getLayout();
                            if (layout != null) {
                                Util.layoutContainer(par);
                            }
                        }
                    }
                });
    }

    public void addInvocationHandler(InvocationHandler h) {
        ClassLoader loader = getClass().getClassLoader();
        Class[] interfaces = new Class[]{DesignerEditListener.class, DesignerStateListener.class};
        Object proxyListener = Proxy.newProxyInstance(loader, interfaces, h);
        addDesignerEditListener((DesignerEditListener) proxyListener);
        addDesignerStateListener((DesignerStateListener) proxyListener);
    }

    /**
     * 开始添加状态,在用户选择面板上的组件时启动
     *
     * @param beanInfo 当前选中组件的BeanInfo对象
     */
    public void startAddingState(BeanInfo beanInfo) {
        //删除编辑状态的事件处理器
        removeMouseListener(editingMouseListener);
        removeMouseMotionListener(editingMouseListener);
        removeKeyListener(keyListener);
        //根据所选择的组件的BeanInfo生成相应的AddingModel
        //AddingModel和StateModel不一样,适合当前选择的组件相关的
        addingModel = new AddingModel(this, beanInfo);
        addingMouseListener = new AddingMouseListener(this, beanInfo);
        //添加事件
        addMouseListener(addingMouseListener);
        addMouseMotionListener(addingMouseListener);
        //设置当前模式位添加模式
        setAddingMode(true);
        //触发状态添加模式事件
        fireStartDesigning();
        repaint();
    }

    /**
     * 停止添加模式、返回编辑模式
     */
    public void stopAddingState() {
        //删除添加模式下的鼠标处理器
        removeMouseListener(addingMouseListener);
        removeMouseMotionListener(addingMouseListener);
        //恢复为空,UI类根据addingModel是否空决定是否停止渲染要添加的组件
        addingModel = null;
        addingMouseListener = null;
        painter = null;
        //添加编辑状态下的鼠标事件处理器和键盘事件处理器
        //由于他们是无状态,是和组件无关的,因此不需要重新生成
        addMouseMotionListener(editingMouseListener);
        addMouseListener(editingMouseListener);
        addKeyListener(keyListener);
        //设置模式为编辑模式
        setAddingMode(false);
        //触发停止添加模式的事件
        fireStopDesigning();
        repaint();
    }

    //设置其UI类为DesignerUI,负责渲染

    @Override
    public void updateUI() {
        setUI(new DesignerUI());
    }

    /**
     * 在拖拽区域选择方式鼠标释放时调用此函数来更新所选择的组件
     * @param e 当前鼠标事件,用来和起始点构成选择框,计算被圈入的组件
     */
    public void selectComponents(MouseEvent e) {
        //调用stateModel的selectComponent更新被选择的组件,stateModel定义了拖拽起始点
        stateModel.selectComponents(e);
        //清除stateModel为非拖拽状态
        stateModel.reset();
        repaint();
    }

    /**
     * 鼠标拖拽组件改变其位置和尺寸,释放鼠标时调用
     */
    public void releaseComponentsDragging(MouseEvent e) {
        setInvalidated(true);

        //恢复初始状态,改变被拖拽组件的位置和尺寸
        stateModel.releaseDragging(e);
        //触发拖拽事件
        fireComponentDragged(stateModel.getHotspotComponents());
        repaint();
    }

    /**
     * 从root组件递归查找x,y所在的组件,注意是正在被设计的组件,因此其name属性必须不为空
     */
    private Component componentAt(int x, int y, Component root) {
        if (!(root instanceof RootPaneContainer) && !root.isVisible()) {
            return null;
        }

        x -= root.getX();
        y -= root.getY();

        if (root instanceof Container) {
            Container rootContainer = (Container) root;
            int count = rootContainer.getComponentCount();

            if (count > 0) {
                for (int i = 0; i < count; i++) {
                    Component child = rootContainer.getComponent(i);

                    //只有name不为空的组件才是搜索范围,这儿递归下溯调用
                    Component dest = componentAt(x, y, child);

                    if (dest != null) {
                        return dest;
                    }
                }
            }
        }

        Rectangle rect = Util.computeVisibleRect(root);
        if (Util.isDesigning(root) && (x >= rect.getX()) && (x <= (rect.getX() + rect.getWidth())) && (y >= rect.getY()) && (y <= (rect.getY() + rect.getHeight()))) {
            //判断是否处于交叉区域
            return root;
        }

        return null;
    }

    /**
     * 根据当前stateModel中所标识的鼠标位置状态数据更新鼠标的形状
     */
    public void updateCursor() {
        Location location = stateModel.getLocation();

        //调用位置枚举的多态方法getCursor获取鼠标形状

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -