When using Lanterna I noticed a quite high CPU usage whenever I had some Components invisible. After some debugging I could find the problem in the Panel isInvalid() method.
This checks if one of its children components is invalid. If this is the case, all components are redrawn, skipping the invisible ones. This way the invisible components will not be drawn and will not be set to valid again. In the next isInvalid check, the invisible components cause the Panel to be redrawn again.
Implemented soultion
Ignore invisible components during Panel.isInvalid() check.
@Override
public boolean isInvalid() {
synchronized(components) {
for(Component component: components) {
// a Panel (Container) isInvalid when any child component isInvalid AND also isVisible
if(component.isInvalid() && component.isVisible()) {
return true;
}
}
}
return super.isInvalid() || layoutManager.hasChanged();
}
Demonstration before
Demonstration after
Used code in shown demonstration
import com.googlecode.lanterna.TextColor.ANSI;
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.screen.TerminalScreen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import com.googlecode.lanterna.terminal.Terminal;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
public class DemonstrationPanel extends Panel {
AtomicInteger drawCounter = new AtomicInteger();
Label drawCounterLabel = new Label("0").setLabelWidth(6);
Label spinnerLabel = new Label("");
AnimatedLabel spinner = AnimatedLabel.createClassicSpinningLine(500);
Button toggleVisibleBtn = new Button("toggle spinner visibility", this::toggleSpinningLineVisibility);
public DemonstrationPanel() {
setLayoutManager(new GridLayout(2));
addComponent(new Label("Draw calls: "));
addComponent(drawCounterLabel);
addComponent(spinnerLabel);
addComponent(spinner);
addComponent(toggleVisibleBtn, GridLayout.createHorizontallyFilledLayoutData(2));
}
private void toggleSpinningLineVisibility() {
spinner.setVisible(!spinner.isVisible());
}
@Override
protected void onBeforeDrawing() {
int drawCounter = this.drawCounter.incrementAndGet();
drawCounterLabel.setText(String.valueOf(drawCounter));
spinnerLabel.setText("Visibility [" + spinner.isVisible() + "]");
}
public static void main(String[] args) throws IOException {
try (Terminal terminal = new DefaultTerminalFactory().createTerminal()) {
TerminalScreen screen = new TerminalScreen(terminal);
screen.startScreen();
BasicWindow window = new BasicWindow();
window.setComponent(new DemonstrationPanel());
MultiWindowTextGUI gui = new MultiWindowTextGUI(screen);
gui.addWindowAndWait(window);
}
}
}
Issue this pull requests tries to fix
When using Lanterna I noticed a quite high CPU usage whenever I had some Components invisible. After some debugging I could find the problem in the Panel isInvalid() method. This checks if one of its children components is invalid. If this is the case, all components are redrawn, skipping the invisible ones. This way the invisible components will not be drawn and will not be set to valid again. In the next isInvalid check, the invisible components cause the Panel to be redrawn again.
Implemented soultion
Ignore invisible components during
Panel.isInvalid()
check.Demonstration before
Demonstration after
Used code in shown demonstration