Browse Source

Merge pull request #15959 in DESIGN/design from fbp/release to fbp/feature

* commit '2e7e21b79fffd0f4f0b1d9ba696d09c1395b2a8d':
  无jira任务 代码质量
  无jira任务 多提交
  REPORT-145101 模板树UI操作位于非DET
  REPORT-145101 卡顿工具-UI操作严格EDT检测
fbp/feature
superman 1 month ago
parent
commit
4d45d576d1
  1. 30
      designer-base/src/main/java/com/fr/design/debug/edt/StrictEDTException.java
  2. 130
      designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtListeners.java
  3. 135
      designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtManager.java
  4. 15
      designer-base/src/main/java/com/fr/design/debug/ui/UIMonitorPane.java
  5. 5
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java

30
designer-base/src/main/java/com/fr/design/debug/edt/StrictEDTException.java

@ -0,0 +1,30 @@
package com.fr.design.debug.edt;
/**
* Swing组件严格限制EDT运行
*
* @author vito
* @since 11.0
* Created on 2023/8/9
*/
public class StrictEDTException extends RuntimeException {
public StrictEDTException() {
}
public StrictEDTException(String message) {
super(message);
}
public StrictEDTException(String message, Throwable cause) {
super(message, cause);
}
public StrictEDTException(Throwable cause) {
super(cause);
}
public StrictEDTException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

130
designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtListeners.java

@ -0,0 +1,130 @@
package com.fr.design.debug.edt;
import com.fr.design.ui.util.EdtInvocationManager;
import com.fr.log.FineLoggerFactory;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* Swing组件严格限制EDT运行监听器
*
* @author vito
* @since 11.0
* Created on 2023/8/9
*/
public class StrictEdtListeners implements HierarchyListener, PropertyChangeListener, ComponentListener, MouseListener,
MouseWheelListener, MouseMotionListener, KeyListener {
@Override
public void componentResized(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void componentMoved(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void componentShown(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void componentHidden(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void hierarchyChanged(HierarchyEvent e) {
checkEventDispatchThread();
}
@Override
public void keyTyped(KeyEvent e) {
checkEventDispatchThread();
}
@Override
public void keyPressed(KeyEvent e) {
checkEventDispatchThread();
}
@Override
public void keyReleased(KeyEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseClicked(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mousePressed(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseReleased(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseEntered(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseExited(MouseEvent e) {
checkEventDispatchThread();
// redispatchMouseEvent(e);
}
@Override
public void mouseDragged(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseMoved(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
checkEventDispatchThread();
}
@Override
public void propertyChange(PropertyChangeEvent e) {
checkEventDispatchThread();
}
/**
* 检查当前是否处于EDT中并发出告警
*/
public static void checkEventDispatchThread() {
if (!EdtInvocationManager.getInstance().isEventDispatchThread()) {
String s = String.format(
"[StrictEDT] The current operation can only be in an EDT (Event Dispatch Thread). Current thread is: %s",
Thread.currentThread().getName()
);
StrictEDTException strictEdtException = new StrictEDTException(s);
FineLoggerFactory.getLogger().warn(s, strictEdtException);
}
}
}

135
designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtManager.java

@ -0,0 +1,135 @@
package com.fr.design.debug.edt;
import com.fanruan.gui.InspectorWindow;
import com.fr.design.mainframe.DesignerContext;
import com.fr.log.FineLoggerFactory;
import org.jetbrains.annotations.NotNull;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.ContainerEvent;
/**
* 严格UI线程运行管理器
*
* @author vito
* @since 11.0
* Created on 2024/12/20
*/
public class StrictEdtManager {
private static final StrictEdtListeners LISTENERS = new StrictEdtListeners();
private static void installContainerEDTCheckers(@NotNull final Container component, int level) {
if (FineLoggerFactory.getLogger().isDebugEnabled()) {
for (int i = 0; i < level; i++) {
FineLoggerFactory.getLogger().debug(" ");
}
FineLoggerFactory.getLogger().debug(component.toString());
}
int count = component.getComponentCount();
level += 1;
for (int i = 0; i < count; i++) {
Component comp = component.getComponent(i);
addEDTCheckersListener(comp);
if (comp instanceof Container) {
installContainerEDTCheckers((Container) comp, level);
}
}
}
private static void addEDTCheckersListener(Component comp) {
comp.addHierarchyListener(LISTENERS);
comp.addPropertyChangeListener(LISTENERS);
comp.addComponentListener(LISTENERS);
comp.addMouseListener(LISTENERS);
comp.addMouseMotionListener(LISTENERS);
comp.addKeyListener(LISTENERS);
}
private static void installEDTCheckers(Container container, int level) {
installContainerEDTCheckers(container, level);
level += 1;
if (container instanceof Window) {
Window[] children = ((Window) container).getOwnedWindows();
for (Window child : children) {
if (child instanceof InspectorWindow) {
continue;
}
installEDTCheckers(child, level);
}
}
}
private static final AWTEventListener AWT_EVENT_LISTENER = (AWTEvent event) -> {
if (event instanceof ContainerEvent) {
Component child = event.getID() == ContainerEvent.COMPONENT_ADDED ? ((ContainerEvent) event).getChild() : null;
if (child != null) {
addEDTCheckersListener(child);
}
}
};
/**
* 监听组件警告不在EDT中执行的UI操作
*/
public static void install() {
// 监听当前的组件
installEDTCheckers(DesignerContext.getDesignerFrame(), 0);
// 监听新增的组件
Toolkit.getDefaultToolkit().addAWTEventListener(AWT_EVENT_LISTENER, AWTEvent.CONTAINER_EVENT_MASK);
FineLoggerFactory.getLogger().info("[StrictEDT] install Strict EDT Checkers");
}
private static void uninstallContainerEDTCheckers(@NotNull final Container component, int level) {
int count = component.getComponentCount();
level += 1;
for (int i = 0; i < count; i++) {
Component comp = component.getComponent(i);
removeEDTCheckersListener(comp);
if (comp instanceof Container) {
uninstallContainerEDTCheckers((Container) comp, level);
}
}
}
private static void removeEDTCheckersListener(Component comp) {
comp.removeHierarchyListener(LISTENERS);
comp.removePropertyChangeListener(LISTENERS);
comp.removeComponentListener(LISTENERS);
comp.removeMouseListener(LISTENERS);
comp.removeMouseMotionListener(LISTENERS);
comp.removeKeyListener(LISTENERS);
}
private static void removeEDTCheckers(Container container, int level) {
uninstallContainerEDTCheckers(container, level);
level += 1;
if (container instanceof Window) {
Window[] children = ((Window) container).getOwnedWindows();
for (Window child : children) {
if (child instanceof InspectorWindow) {
continue;
}
removeEDTCheckers(child, level);
}
}
}
/**
* 监听组件警告不在EDT中执行的UI操作
*/
public static void uninstall() {
// 取消监听新增的组件
Toolkit.getDefaultToolkit().removeAWTEventListener(AWT_EVENT_LISTENER);
// 解除监听当前的组件
removeEDTCheckers(DesignerContext.getDesignerFrame(), 0);
FineLoggerFactory.getLogger().info("[StrictEDT] uninstall Strict EDT Checkers");
}
}

15
designer-base/src/main/java/com/fr/design/debug/ui/UIMonitorPane.java

@ -8,6 +8,7 @@ import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.base.extension.FileExtension;
import com.fr.design.border.FineBorderFactory;
import com.fr.design.carton.latency.LatencyLevel;
import com.fr.design.debug.edt.StrictEdtManager;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.ibutton.UIButton;
@ -61,6 +62,7 @@ public class UIMonitorPane extends JPanel {
private DefaultTableModel model;
private UICheckBox inspector;
private UICheckBox strictEDTChecker;
private UICheckBox monitor;
public UIMonitorPane() {
@ -73,6 +75,7 @@ public class UIMonitorPane extends JPanel {
UITableScrollPane tablePane = initLatencyTable();
Row topSettingRow = initTopSettingRow();
inspector = new UICheckBox("Open UI Inspector");
strictEDTChecker = new UICheckBox("Open Strict EDT Checker");
monitor = new UICheckBox("Open Latency Monitor");
JPanel monitorPane = column(10,
@ -81,6 +84,7 @@ public class UIMonitorPane extends JPanel {
add(column(10,
cell(FineUIUtils.wrapComponentWithTitle(inspector, "UI Inspector")),
cell(FineUIUtils.wrapComponentWithTitle(strictEDTChecker, "Strict EDT Checker")),
cell(FineUIUtils.wrapComponentWithTitle(monitorPane, "UI Latency Monitor"))
).getComponent(), BorderLayout.CENTER);
@ -94,14 +98,21 @@ public class UIMonitorPane extends JPanel {
inspector.setSelected(UIInspectorHolder.getInstance().isInstalled());
monitor.setSelected(UILatencyWorker.getInstance().isMonitoring());
// 注册事件监听
inspector.addChangeListener(e -> {
inspector.addActionListener(e -> {
if (inspector.isSelected()) {
UIInspectorHolder.getInstance().install();
} else {
UIInspectorHolder.getInstance().uninstall();
}
});
monitor.addChangeListener(e -> {
strictEDTChecker.addActionListener(e -> {
if (strictEDTChecker.isSelected()) {
StrictEdtManager.install();
} else {
StrictEdtManager.uninstall();
}
});
monitor.addActionListener(e -> {
topSettingRow.setVisible(monitor.isSelected());
tablePane.setVisible(monitor.isSelected());
if (monitor.isSelected()) {

5
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java

@ -108,17 +108,18 @@ public abstract class RefreshableJTree extends CheckBoxTree {
for (int i = 0; i < nodes.length; i++) {
treeNode.add(nodes[i]);
}
DefaultTreeModel treeModel = (DefaultTreeModel) RefreshableJTree.this.getModel();
// 主要耗时是用在了treeUI的渲染上了,所以把这个放到工作线程里面
if (treeNode.getChildCount() >= 1 && ((ExpandMutableTreeNode) treeNode.getFirstChild()).getUserObject() == PENDING) {
treeNode.remove(0);
}
treeModel.nodeStructureChanged(treeNode);
return System.currentTimeMillis() - startTime;
}
@Override
protected void done() {
DefaultTreeModel treeModel = (DefaultTreeModel) RefreshableJTree.this.getModel();
treeModel.nodeStructureChanged(treeNode);
RefreshableJTree.this.updateUI();
// 恢复Tree的可用性
RefreshableJTree.this.setEnabled(true);

Loading…
Cancel
Save