Browse Source

REPORT-54122 设计器组件悬停/选中/编辑状态优化

feature/10.0
hades 3 years ago
parent
commit
39c29ab26d
  1. BIN
      designer-base/src/main/resources/com/fr/design/images/control/show_edit.png
  2. BIN
      designer-base/src/main/resources/com/fr/design/images/control/show_setting.png
  3. 47
      designer-form/src/main/java/com/fr/design/designer/creator/SelectedBorderIcon.java
  4. 22
      designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
  5. 82
      designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java
  6. 40
      designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
  7. 11
      designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java
  8. 39
      designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
  9. 3
      designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java

BIN
designer-base/src/main/resources/com/fr/design/images/control/show_edit.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

BIN
designer-base/src/main/resources/com/fr/design/images/control/show_setting.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

47
designer-form/src/main/java/com/fr/design/designer/creator/SelectedBorderIcon.java

@ -0,0 +1,47 @@
package com.fr.design.designer.creator;
import com.fr.design.form.util.XCreatorConstants;
import com.fr.general.IOUtils;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
/**
* @author hades
* @version 10.0
* Created by hades on 2021/06/30
*/
public class SelectedBorderIcon {
private static final Image EDIT_ICON = IOUtils.readImage("/com/fr/design/images/control/show_edit.png");
private static final Image SETTING_ICON = IOUtils.readImage("/com/fr/design/images/control/show_setting.png");
private static final float ALPHA = 0.7F;
private static final int TIP_WIDTH = 20;
private static final int TIP_HEIGHT = 40;
private static final int ARC_VALUE = 4;
// 组件到整个提示之间的空隙
private static final int CREATOR_TO_TIP_GAP = 5;
// icon在整个提示背景下缩进
private static final int TIP_ICON_GAP = 2;
/**
* 在bounds范围的右上角绘制特定图标
*
* @param g
* @param bounds
*/
public void paint(Graphics g, Rectangle bounds) {
Graphics2D g2d = (Graphics2D) g;
AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ALPHA);
g2d.setColor(XCreatorConstants.EDIT_COLOR);
g2d.setComposite(alphaComposite);
g2d.fillRoundRect(bounds.x + bounds.width + CREATOR_TO_TIP_GAP, bounds.y, TIP_WIDTH, TIP_HEIGHT, ARC_VALUE, ARC_VALUE);
g2d.drawImage(EDIT_ICON, bounds.x + bounds.width + CREATOR_TO_TIP_GAP + TIP_ICON_GAP, bounds.y + TIP_ICON_GAP, EDIT_ICON.getWidth(null), EDIT_ICON.getHeight(null), null);
g2d.drawImage(SETTING_ICON, bounds.x + bounds.width + CREATOR_TO_TIP_GAP + TIP_ICON_GAP, bounds.y + CREATOR_TO_TIP_GAP + EDIT_ICON.getHeight(null), SETTING_ICON.getWidth(null), SETTING_ICON.getHeight(null), null);
g2d.setColor(Color.WHITE);
g2d.drawLine(bounds.x + bounds.width + CREATOR_TO_TIP_GAP + TIP_ICON_GAP, bounds.y + TIP_WIDTH, bounds.x + bounds.width + CREATOR_TO_TIP_GAP + TIP_ICON_GAP + EDIT_ICON.getWidth(null), bounds.y + TIP_WIDTH);
}
}

22
designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java

@ -68,6 +68,9 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
private Rectangle backupBound; private Rectangle backupBound;
private String shareId = StringUtils.EMPTY;//如果组件是共享的会有这个属性 private String shareId = StringUtils.EMPTY;//如果组件是共享的会有这个属性
private boolean isHelpBtnOnFocus = false;//焦点是否在帮助按钮上 private boolean isHelpBtnOnFocus = false;//焦点是否在帮助按钮上
// 当前组件是否处在选中状态
private boolean selected;
private SelectedBorderIcon selectedBorderIcon = new SelectedBorderIcon();
private static final int SHORTS_SEPARATOR_POS = 4; // 弹出菜单分割的位置 private static final int SHORTS_SEPARATOR_POS = 4; // 弹出菜单分割的位置
public XCreator(Widget ob, Dimension initSize) { public XCreator(Widget ob, Dimension initSize) {
@ -760,6 +763,18 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
GraphHelper.draw(g, bounds, Constants.LINE_MEDIUM); GraphHelper.draw(g, bounds, Constants.LINE_MEDIUM);
} }
/**
* 绘制选中时右上边框图标
*
* @param g
* @param bounds
*/
public void paintSelectedBorderIcon(Graphics g, Rectangle bounds) {
if (selected) {
selectedBorderIcon.paint(g, bounds);
}
}
/** /**
* 创建右击弹出菜单 * 创建右击弹出菜单
* *
@ -797,5 +812,12 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
} }
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
} }

82
designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java

@ -2,15 +2,20 @@ package com.fr.design.mainframe;
import com.fr.design.constants.UIConstants; import com.fr.design.constants.UIConstants;
import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XCreator;
import com.fr.design.designer.creator.XCreatorUtils;
import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.creator.XLayoutContainer;
import com.fr.design.designer.treeview.ComponentTreeCellRenderer; import com.fr.design.designer.treeview.ComponentTreeCellRenderer;
import com.fr.design.designer.treeview.ComponentTreeModel; import com.fr.design.designer.treeview.ComponentTreeModel;
import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.gui.itree.UITreeUI; import com.fr.design.gui.itree.UITreeUI;
import com.fr.design.utils.ComponentUtils;
import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.log.FineLoggerFactory; import com.fr.stable.ArrayUtils;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import java.awt.Rectangle;
import java.awt.event.MouseListener;
import java.util.Stack;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.DropMode; import javax.swing.DropMode;
import javax.swing.JPanel; import javax.swing.JPanel;
@ -370,6 +375,81 @@ public class ComponentTree extends JTree {
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
hidePreviewPane(); hidePreviewPane();
} }
@Override
public void mouseClicked(MouseEvent e) {
// 鼠标左键 双击
if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1 && !designer.isFormParaDesigner()) {
Point p = e.getPoint();
// 解析组件树路径 获取选中的组件
int selRow = tree.getRowForLocation(p.x, p.y);
TreePath path = tree.getPathForRow(selRow);
Rectangle bounds = tree.getPathBounds(path);
if (bounds != null) {
Point point = bounds.getLocation();
SwingUtilities.convertPointToScreen(point, tree);
XCreator comp = (XCreator) path.getLastPathComponent();
startEditing(comp, e);
}
}
}
/**
* 组件进入编辑状态
*
* @param comp
* @param e
*/
private void startEditing(XCreator comp, MouseEvent e) {
designer.getSelectionModel().selectACreator(comp);
Rectangle rectangle = getRelativeBounds(comp);
int x = rectangle.x + rectangle.width / 2;
int y = rectangle.y + rectangle.height / 2;
XCreator creator = comp.getEditingChildCreator();
MouseListener[] listeners = designer.getMouseListeners();
if (ArrayUtils.isNotEmpty(listeners) && listeners[0] instanceof EditingMouseListener) {
responseClickAll(creator, (EditingMouseListener) listeners[0], new MouseEvent(creator, MouseEvent.MOUSE_CLICKED, e.getWhen(), e.getModifiers(), x, y, e.getClickCount(), false));
}
}
/**
* 自父容器到子组件 每一层的都响应click事件
*
*
* @param creator
* @param editingMouseListener
* @param mouseEvent
*/
public void responseClickAll(XCreator creator, EditingMouseListener editingMouseListener, MouseEvent mouseEvent) {
Stack<XCreator> stack = new Stack<>();
stack.push(creator);
while (creator.getParent() instanceof XCreator) {
creator = (XCreator) creator.getParent();
stack.push(creator);
}
while (!stack.isEmpty()) {
stack.pop().respondClick(editingMouseListener, mouseEvent);
}
}
/**
* 获取组件范围坐标
*
* @param creator
* @return
*/
private Rectangle getRelativeBounds(XCreator creator) {
Rectangle bounds = creator.getBounds();
XLayoutContainer parent = XCreatorUtils.getParentXLayoutContainer(creator);
if (parent == null) {
return bounds;
}
Rectangle rec = ComponentUtils.getRelativeBounds(parent);
bounds.x += rec.x;
bounds.y += rec.y;
return bounds;
}
} }
private class PopupPreviewPane extends JPopupMenu { private class PopupPreviewPane extends JPopupMenu {

40
designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java

@ -21,6 +21,7 @@ import com.fr.design.designer.creator.XLayoutContainer;
import com.fr.design.designer.creator.XWFitLayout; import com.fr.design.designer.creator.XWFitLayout;
import com.fr.design.designer.creator.cardlayout.XCardSwitchButton; import com.fr.design.designer.creator.cardlayout.XCardSwitchButton;
import com.fr.design.designer.creator.cardlayout.XWCardLayout; import com.fr.design.designer.creator.cardlayout.XWCardLayout;
import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout;
import com.fr.design.form.util.XCreatorConstants; import com.fr.design.form.util.XCreatorConstants;
import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.gui.imenu.UIPopupMenu;
@ -29,6 +30,7 @@ import com.fr.design.icon.IconPathConstants;
import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.ComponentUtils;
import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.utils.gui.LayoutUtils; import com.fr.design.utils.gui.LayoutUtils;
import com.fr.general.ComparatorUtils;
import com.fr.stable.Constants; import com.fr.stable.Constants;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
@ -353,6 +355,15 @@ public class EditingMouseListener extends MouseInputAdapter {
} }
private void processCoverPane(XCreator component) {
// selected状态 不展示封面
XCreator xCreator = selectionModel.getSelection().getSelectedCreator();
boolean accept = xCreator == null || !ComparatorUtils.equals(xCreator.toData().getWidgetName(), component.toData().getWidgetName()) ||!xCreator.isSelected();
if (accept) {
component.displayCoverPane(true);
}
}
private boolean isShareConfigButton(MouseEvent e, XCreator component, Insets insets) { private boolean isShareConfigButton(MouseEvent e, XCreator component, Insets insets) {
if (component.isShared()) { if (component.isShared()) {
int minX = getParentPositionX(component, component.getX()) + component.getWidth() - insets.right - CoverReportPane.SHARE_CONF_BTN_W - designer.getHorizontalScaleValue(); int minX = getParentPositionX(component, component.getX()) + component.getWidth() - insets.right - CoverReportPane.SHARE_CONF_BTN_W - designer.getHorizontalScaleValue();
@ -387,7 +398,7 @@ public class EditingMouseListener extends MouseInputAdapter {
private void elementCaseMouseMoved(MouseEvent e, XCreator component) { private void elementCaseMouseMoved(MouseEvent e, XCreator component) {
xElementCase = (XElementCase) component; xElementCase = (XElementCase) component;
component.displayCoverPane(true); processCoverPane(component);
processCoverMouseMove(component, e); processCoverMouseMove(component, e);
} }
@ -428,7 +439,7 @@ public class EditingMouseListener extends MouseInputAdapter {
private void processChartEditorMouseMove(XCreator component, MouseEvent e) { private void processChartEditorMouseMove(XCreator component, MouseEvent e) {
if (component instanceof XChartEditor) { if (component instanceof XChartEditor) {
xChartEditor = (XChartEditor) component; xChartEditor = (XChartEditor) component;
component.displayCoverPane(true); processCoverPane(component);
processCoverMouseMove(component, e); processCoverMouseMove(component, e);
} }
@ -608,10 +619,23 @@ public class EditingMouseListener extends MouseInputAdapter {
return; return;
} }
XCreator oldCreator = creator;
creator = processTopLayoutMouseClick(creator); creator = processTopLayoutMouseClick(creator);
if (creator != null) { if (creator != null) {
creator.respondClick(this, e); if (e.getClickCount() == 1 && designer.getCursor().getType() != Cursor.HAND_CURSOR) {
setCoverPaneNotDisplay(creator, e, false);
selectionModel.selectACreatorAtMouseEvent(e);
refreshTopXCreator();
XCreator[] xCreators = selectionModel.getSelection().getSelectedCreators();
for (XCreator xCreator : xCreators) {
xCreator.setSelected(true);
}
} else if (responseTabLayout(oldCreator, e)) {
// do nothing
} else {
creator.respondClick(this, e);
}
if (e.getButton() == MouseEvent.BUTTON3) { if (e.getButton() == MouseEvent.BUTTON3) {
UIPopupMenu cellPopupMenu = creator.createPopupMenu(designer); UIPopupMenu cellPopupMenu = creator.createPopupMenu(designer);
if (cellPopupMenu != UIPopupMenu.EMPTY) { if (cellPopupMenu != UIPopupMenu.EMPTY) {
@ -624,6 +648,16 @@ public class EditingMouseListener extends MouseInputAdapter {
LayoutUtils.layoutRootContainer(designer.getRootComponent()); LayoutUtils.layoutRootContainer(designer.getRootComponent());
} }
private boolean responseTabLayout(XCreator creator, MouseEvent e) {
if (creator.acceptType(XWCardMainBorderLayout.class) ) {
creator.respondClick(this, e);
return true;
} else if (creator.getParent() instanceof XCreator) {
return responseTabLayout((XCreator) creator.getParent(), e);
}
return false;
}
/** /**
* 离开 * 离开

11
designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java

@ -49,6 +49,7 @@ import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetEvent;
import javax.swing.SwingUtilities;
/** /**
* 添加模式下鼠标事件处理器 * 添加模式下鼠标事件处理器
@ -302,6 +303,16 @@ public class FormCreatorDropTarget extends DropTarget {
public synchronized void drop(DropTargetDropEvent dtde) { public synchronized void drop(DropTargetDropEvent dtde) {
Point loc = dtde.getLocation(); Point loc = dtde.getLocation();
this.adding(designer.getRelativeX(loc.x), designer.getRelativeY(loc.y)); this.adding(designer.getRelativeX(loc.x), designer.getRelativeY(loc.y));
// 放到事件末尾执行
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// 拖拽释放后标记未选中
for (XCreator xCreator : designer.getSelectionModel().getSelection().getSelectedCreators()) {
xCreator.setSelected(true);
}
}
});
//针对在表单中拖入一个控件直接ctrl+s无反应 //针对在表单中拖入一个控件直接ctrl+s无反应
designer.requestFocus(); designer.requestFocus();
} }

39
designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java

@ -307,7 +307,10 @@ public class FormDesignerUI extends ComponentUI {
bounds.x -= designer.getHorizontalScaleValue(); bounds.x -= designer.getHorizontalScaleValue();
bounds.y -= designer.getVerticalScaleValue(); bounds.y -= designer.getVerticalScaleValue();
drawResizingThumbs(g, selectionModel.getSelection().getDirections(), bounds.x, bounds.y, bounds.width, bounds.height); // 绘制调整框线
if (designer.getStateModel().getDirection() != null) {
drawResizingThumbs(g, selectionModel.getSelection().getDirections(), bounds.x, bounds.y, bounds.width, bounds.height, designer.getStateModel().getDirection().getActual());
}
//选中时边框颜色 //选中时边框颜色
g.setColor(XCreatorConstants.FORM_BORDER_COLOR); g.setColor(XCreatorConstants.FORM_BORDER_COLOR);
@ -321,6 +324,10 @@ public class FormDesignerUI extends ComponentUI {
resetCreatorBounds(creatorBounds); resetCreatorBounds(creatorBounds);
} }
creator.paintBorder(g, creatorBounds); creator.paintBorder(g, creatorBounds);
// 拖拽时不绘制
if (!designer.getStateModel().isDragging()) {
creator.paintSelectedBorderIcon(g, creatorBounds);
}
} }
} }
@ -357,48 +364,60 @@ public class FormDesignerUI extends ComponentUI {
/** /**
* 画出八个拖拽框 * 画出八个拖拽框
*/ */
private void drawResizingThumbs(Graphics g, int[] directions, int x, int y, int w, int h) { private void drawResizingThumbs(Graphics g, int[] directions, int x, int y, int w, int h, int direction) {
int bx = x - XCreatorConstants.RESIZE_BOX_SIZ; int bx = x - XCreatorConstants.RESIZE_BOX_SIZ;
int by = y - XCreatorConstants.RESIZE_BOX_SIZ; int by = y - XCreatorConstants.RESIZE_BOX_SIZ;
if (ArrayUtils.contains(directions, Direction.LEFT_TOP)) { if (showBox(Direction.LEFT_TOP, direction, directions)) {
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.TOP)) { if (showBox(Direction.TOP, direction, directions)) {
bx = x + ((w - XCreatorConstants.RESIZE_BOX_SIZ) / 2); bx = x + ((w - XCreatorConstants.RESIZE_BOX_SIZ) / 2);
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.RIGHT_TOP)) { if (showBox(Direction.RIGHT_TOP, direction, directions)) {
bx = x + w; bx = x + w;
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.LEFT)) { if (showBox(Direction.LEFT, direction, directions)) {
bx = x - XCreatorConstants.RESIZE_BOX_SIZ; bx = x - XCreatorConstants.RESIZE_BOX_SIZ;
by = y + ((h - XCreatorConstants.RESIZE_BOX_SIZ) / 2); by = y + ((h - XCreatorConstants.RESIZE_BOX_SIZ) / 2);
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.LEFT_BOTTOM)) { if (showBox(Direction.LEFT_BOTTOM, direction, directions)) {
bx = x - XCreatorConstants.RESIZE_BOX_SIZ; bx = x - XCreatorConstants.RESIZE_BOX_SIZ;
by = y + h; by = y + h;
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.BOTTOM)) { if (showBox(Direction.BOTTOM, direction, directions)) {
bx = x + ((w - XCreatorConstants.RESIZE_BOX_SIZ) / 2); bx = x + ((w - XCreatorConstants.RESIZE_BOX_SIZ) / 2);
by = y + h; by = y + h;
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.RIGHT_BOTTOM)) { if (showBox(Direction.RIGHT_BOTTOM, direction, directions)) {
bx = x + w; bx = x + w;
by = y + h; by = y + h;
drawBox(g, bx, by); drawBox(g, bx, by);
} }
if (ArrayUtils.contains(directions, Direction.RIGHT)) { if (showBox(Direction.RIGHT, direction, directions)) {
bx = x + w; bx = x + w;
by = y + ((h - XCreatorConstants.RESIZE_BOX_SIZ) / 2); by = y + ((h - XCreatorConstants.RESIZE_BOX_SIZ) / 2);
drawBox(g, bx, by); drawBox(g, bx, by);
} }
} }
/**
* 是否展示某个方位的调整框
*
* @param currentDirection
* @param actualDirection
* @param directions
* @return
*/
private boolean showBox(int currentDirection, int actualDirection, int[] directions) {
return ArrayUtils.contains(directions, currentDirection) && (currentDirection == actualDirection || !designer.getStateModel().isDragging());
}
/** /**
* 画每一个小拖拽框 * 画每一个小拖拽框
*/ */

3
designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java

@ -40,6 +40,9 @@ public class FormSelection {
* 重置选中的组件 * 重置选中的组件
*/ */
public void reset() { public void reset() {
for (XCreator xCreator : selection) {
xCreator.setSelected(false);
}
selection.clear(); selection.clear();
} }

Loading…
Cancel
Save