loottracker: Optimize panel rebuild
Removing components in swing can be incredibly slow under serveral circumstances. This adds a special removeAll that can take less time in some cases
This commit is contained in:
@@ -54,6 +54,7 @@ import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
import net.runelite.client.util.ColorUtil;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.QuantityFormatter;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
import net.runelite.http.api.loottracker.LootTrackerClient;
|
||||
|
||||
class LootTrackerPanel extends PluginPanel
|
||||
@@ -488,7 +489,7 @@ class LootTrackerPanel extends PluginPanel
|
||||
*/
|
||||
private void rebuild()
|
||||
{
|
||||
logsContainer.removeAll();
|
||||
SwingUtil.fastRemoveAll(logsContainer);
|
||||
boxes.clear();
|
||||
|
||||
if (groupLoot)
|
||||
|
||||
@@ -612,7 +612,7 @@ public class LootTrackerPlugin extends Plugin
|
||||
}
|
||||
|
||||
config.setIgnoredItems(Text.toCSV(ignoredItemSet));
|
||||
panel.updateIgnoredRecords();
|
||||
// the config changed will update the panel
|
||||
}
|
||||
|
||||
boolean isIgnored(String name)
|
||||
|
||||
@@ -26,11 +26,16 @@ package net.runelite.client.util;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.SecondaryLoop;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -50,6 +55,7 @@ import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
@@ -293,4 +299,54 @@ public class SwingUtil
|
||||
{
|
||||
button.addItemListener(l -> button.setToolTipText(button.isSelected() ? on : off));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of a component's children faster than calling removeAll() on it in many cases
|
||||
*/
|
||||
public static void fastRemoveAll(Container c)
|
||||
{
|
||||
// If we are not on the EDT this will deadlock, in addition to being totally unsafe
|
||||
assert SwingUtilities.isEventDispatchThread();
|
||||
|
||||
// when a component is removed it has to be resized for some reason, but only if it's valid
|
||||
// so we make sure to invalidate everything before removing it
|
||||
c.invalidate();
|
||||
for (int i = 0; i < c.getComponentCount(); i++)
|
||||
{
|
||||
Component ic = c.getComponent(i);
|
||||
|
||||
// removeAll and removeNotify are both recursive, so we have to recurse before them
|
||||
if (ic instanceof Container)
|
||||
{
|
||||
fastRemoveAll((Container) ic);
|
||||
}
|
||||
|
||||
// each removeNotify needs to remove anything from the event queue that is for that widget
|
||||
// this however requires taking a lock, and is moderately slow, so we just execute all of
|
||||
// those events with a secondary event loop
|
||||
pumpPendingEvents();
|
||||
|
||||
// call removeNotify early; this is most of the work in removeAll, and generates events that
|
||||
// the next secondaryLoop will pickup
|
||||
ic.removeNotify();
|
||||
}
|
||||
|
||||
// Actually remove anything
|
||||
c.removeAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any events currently in the event queue
|
||||
*/
|
||||
public static void pumpPendingEvents()
|
||||
{
|
||||
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
|
||||
if (eq.peekEvent() != null)
|
||||
{
|
||||
SecondaryLoop l = eq.createSecondaryLoop();
|
||||
SwingUtilities.invokeLater(l::exit);
|
||||
l.enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user