From 39c29ab26d386ca727efbb14eaab7466e275ee9e Mon Sep 17 00:00:00 2001 From: hades Date: Tue, 6 Jul 2021 10:15:30 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-54122=20=E8=AE=BE=E8=AE=A1=E5=99=A8?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=82=AC=E5=81=9C/=E9=80=89=E4=B8=AD/?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E7=8A=B6=E6=80=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/design/images/control/show_edit.png | Bin 0 -> 304 bytes .../fr/design/images/control/show_setting.png | Bin 0 -> 281 bytes .../designer/creator/SelectedBorderIcon.java | 47 ++++++++++ .../fr/design/designer/creator/XCreator.java | 22 +++++ .../fr/design/mainframe/ComponentTree.java | 82 +++++++++++++++++- .../mainframe/EditingMouseListener.java | 40 ++++++++- .../mainframe/FormCreatorDropTarget.java | 11 +++ .../fr/design/mainframe/FormDesignerUI.java | 39 ++++++--- .../fr/design/mainframe/FormSelection.java | 3 + 9 files changed, 230 insertions(+), 14 deletions(-) create mode 100644 designer-base/src/main/resources/com/fr/design/images/control/show_edit.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/control/show_setting.png create mode 100644 designer-form/src/main/java/com/fr/design/designer/creator/SelectedBorderIcon.java diff --git a/designer-base/src/main/resources/com/fr/design/images/control/show_edit.png b/designer-base/src/main/resources/com/fr/design/images/control/show_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..9378e76c5f5f969c782028ca87d3e8b5676c7273 GIT binary patch literal 304 zcmV-00nh%4P)%4P1gBOq>D1ND$YciMk3A+{75^A_OrqP!mxMT!4b1FsUHol@3OF zpnJL-E3K+i@7`A>{|v|dNp69D6;CbKtpFqSt*9+0QZB3lCD{V5ffseT6ClYV@C5XL zWA(H(Ajuq1NL&Z5fF1Rx3t$Kw0C$O>CN4m;VJ45t$L|(NuW=0000*q)O`A@-*y{VM!hF#{~NYIV7mh}B`s{f0F!7MOPbn#1imG$GqN*5G_QaL zFbD2|hX8&88(;wZ0NsovPmtI@E{vp~R3>cM!h1~lk7q7vSg;U*JprSf?4;&7fHR<< zv-1kPrC?7AY;S?v(%6=yuc+Suhf;kf>F#O-Y3J1~WYTO`3o(4wTVw4*3Ki8)xqLa5 fKGTI~T!0+`QonK$Q5cW*00000NkvXXu0mjfNWyQ% literal 0 HcmV?d00001 diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/SelectedBorderIcon.java b/designer-form/src/main/java/com/fr/design/designer/creator/SelectedBorderIcon.java new file mode 100644 index 000000000..fe2d839b9 --- /dev/null +++ b/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); + } +} diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java index 265fa3618..7220eafe8 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java +++ b/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 String shareId = StringUtils.EMPTY;//如果组件是共享的会有这个属性 private boolean isHelpBtnOnFocus = false;//焦点是否在帮助按钮上 + // 当前组件是否处在选中状态 + private boolean selected; + private SelectedBorderIcon selectedBorderIcon = new SelectedBorderIcon(); private static final int SHORTS_SEPARATOR_POS = 4; // 弹出菜单分割的位置 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); } + /** + * 绘制选中时右上边框图标 + * + * @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; + } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java b/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java index c9ae03272..134252487 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java +++ b/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.designer.creator.XCreator; +import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.treeview.ComponentTreeCellRenderer; import com.fr.design.designer.treeview.ComponentTreeModel; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.gui.itree.UITreeUI; +import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; 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.DropMode; import javax.swing.JPanel; @@ -370,6 +375,81 @@ public class ComponentTree extends JTree { public void mouseExited(MouseEvent e) { 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 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 { diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java index a8ad6dd58..00ba360bb 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java +++ b/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.cardlayout.XCardSwitchButton; 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.gui.ibutton.UIButton; 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.gui.GUICoreUtils; import com.fr.design.utils.gui.LayoutUtils; +import com.fr.general.ComparatorUtils; import com.fr.stable.Constants; 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) { if (component.isShared()) { 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) { xElementCase = (XElementCase) component; - component.displayCoverPane(true); + processCoverPane(component); processCoverMouseMove(component, e); } @@ -428,7 +439,7 @@ public class EditingMouseListener extends MouseInputAdapter { private void processChartEditorMouseMove(XCreator component, MouseEvent e) { if (component instanceof XChartEditor) { xChartEditor = (XChartEditor) component; - component.displayCoverPane(true); + processCoverPane(component); processCoverMouseMove(component, e); } @@ -608,10 +619,23 @@ public class EditingMouseListener extends MouseInputAdapter { return; } + XCreator oldCreator = creator; creator = processTopLayoutMouseClick(creator); 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) { UIPopupMenu cellPopupMenu = creator.createPopupMenu(designer); if (cellPopupMenu != UIPopupMenu.EMPTY) { @@ -624,6 +648,16 @@ public class EditingMouseListener extends MouseInputAdapter { 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; + } + /** * 离开 diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java b/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java index 222165a53..30b941818 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java +++ b/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.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; +import javax.swing.SwingUtilities; /** * 添加模式下鼠标事件处理器。 @@ -302,6 +303,16 @@ public class FormCreatorDropTarget extends DropTarget { public synchronized void drop(DropTargetDropEvent dtde) { Point loc = dtde.getLocation(); 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无反应 designer.requestFocus(); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java index 7cd9e2108..8df27c19f 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java +++ b/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.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); @@ -321,6 +324,10 @@ public class FormDesignerUI extends ComponentUI { resetCreatorBounds(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 by = y - XCreatorConstants.RESIZE_BOX_SIZ; - if (ArrayUtils.contains(directions, Direction.LEFT_TOP)) { + if (showBox(Direction.LEFT_TOP, direction, directions)) { drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.TOP)) { + if (showBox(Direction.TOP, direction, directions)) { bx = x + ((w - XCreatorConstants.RESIZE_BOX_SIZ) / 2); drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.RIGHT_TOP)) { + if (showBox(Direction.RIGHT_TOP, direction, directions)) { bx = x + w; drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.LEFT)) { + if (showBox(Direction.LEFT, direction, directions)) { bx = x - XCreatorConstants.RESIZE_BOX_SIZ; by = y + ((h - XCreatorConstants.RESIZE_BOX_SIZ) / 2); drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.LEFT_BOTTOM)) { + if (showBox(Direction.LEFT_BOTTOM, direction, directions)) { bx = x - XCreatorConstants.RESIZE_BOX_SIZ; by = y + h; drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.BOTTOM)) { + if (showBox(Direction.BOTTOM, direction, directions)) { bx = x + ((w - XCreatorConstants.RESIZE_BOX_SIZ) / 2); by = y + h; drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.RIGHT_BOTTOM)) { + if (showBox(Direction.RIGHT_BOTTOM, direction, directions)) { bx = x + w; by = y + h; drawBox(g, bx, by); } - if (ArrayUtils.contains(directions, Direction.RIGHT)) { + if (showBox(Direction.RIGHT, direction, directions)) { bx = x + w; by = y + ((h - XCreatorConstants.RESIZE_BOX_SIZ) / 2); 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()); + } + /** * 画每一个小拖拽框 */ diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java index 956e1cb66..3bf4b49ac 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java @@ -40,6 +40,9 @@ public class FormSelection { * 重置选中的组件 */ public void reset() { + for (XCreator xCreator : selection) { + xCreator.setSelected(false); + } selection.clear(); }