Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

progress bar error #841

Closed
Frank-99 opened this issue May 8, 2024 · 4 comments
Closed

progress bar error #841

Frank-99 opened this issue May 8, 2024 · 4 comments

Comments

@Frank-99
Copy link

Frank-99 commented May 8, 2024

I sometimes get the error call below from the progress bar of the splash screen of my app, but it does it very randomly and out of nowhere, and then it might not do it again for another twenty runs, even if I don't change any of the code...
Any clue if this can be a bug somewhere in the FlatProgressBarUI or something else unrelated?

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at java.desktop/javax.swing.plaf.basic.BasicProgressBarUI.updateSizes(BasicProgressBarUI.java:537)
	at java.desktop/javax.swing.plaf.basic.BasicProgressBarUI.getBox(BasicProgressBarUI.java:494)
	at com.formdev.flatlaf.ui.FlatProgressBarUI.paint(FlatProgressBarUI.java:230)
	at com.formdev.flatlaf.ui.FlatProgressBarUI.update(FlatProgressBarUI.java:201)
	at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
	at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)
	at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedFPScales(RepaintManager.java:1707)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1616)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
	at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
	at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
	at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
	at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
	at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1890)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

@Frank-99 Frank-99 changed the title progressbar error progress bar error May 8, 2024
@Frank-99
Copy link
Author

Frank-99 commented May 8, 2024

Just noticed it's very similar to #830
What I do with My JProgressBar is as follows:

private JProgressBar progress;
progress = new JProgressBar();
progress.setIndeterminate(true);
progress.setPreferredSize(new Dimension(150, 6));
progress.setBackground(Color.decode("#ADB8CE"));
progress.setForeground(Color.decode("#688FDD"));

window.addWindowListener(new WindowListener() {
	@Override
	public void windowOpened(WindowEvent e) {
		runner = Runner.run(() -> {	checkForUpdates(); }).toService();
	}
	@Override public void windowClosing(WindowEvent e) { }
	@Override public void windowClosed(WindowEvent e) { }
	@Override public void windowIconified(WindowEvent e) { }
	@Override public void windowDeiconified(WindowEvent e) { }
	@Override public void windowActivated(WindowEvent e) { }
	@Override public void windowDeactivated(WindowEvent e) { }
});

And the subsequent calls:

private static Runner run(Runnable runnable) {
	Runner handler = new Runner();
	handler.worker = new SwingWorker<Void, Void>() {
		@Override protected Void doInBackground() throws Exception {
			runnable.run();
			return null;
		}
		@Override protected void done() { }
	};
	handler.start();
	return handler;
}

private void checkForUpdates() {
	runner = UpdateManager.startUpdater(new UpdaterListener() {
		@Override public void onLookingForUpdate() {
			progress.setIndeterminate(true);
		}
		@Override public void onIsUpToDate() {
			progress.setIndeterminate(false);
			progress.setValue(100);
			Runner.sleep(100);
			cleanFiles();
		}
		@Override public boolean onUpdateFound() {
			progress.setIndeterminate(false);
			progress.setValue(100);
			return true;
		}
		@Override public void onDownloadingUpdate() {
			progress.setIndeterminate(false);
			progress.setValue(0);
		}
		@Override public void onDownloadUpdate(int progr) {
			progress.setValue(progr);
		}
		@Override public void onPreparingToIstall() {
			progress.setValue(0);
		}
		@Override public void onPreparingUpdate(int progr) {
			progress.setValue(progr);
		}
		@Override public boolean onReadyToIstall() {
			progress.setValue(100);
			Runner.sleep(100);
			progress.setIndeterminate(true);
			Runner.sleep(100);
			return true;
		}
		@Override public void onUpdateCanceled() {
			progress.setIndeterminate(false);
			progress.setValue(0);
			Runner.sleep(100);
			cleanFiles();
		}
		@Override public void onFailed() {
			progress.setIndeterminate(false);
			progress.setValue(0);
			Runner.sleep(100);
			cleanFiles();
		}
	});
	
	
private void cleanFiles() {
	runner = Runner.run(() -> {
		progress.setIndeterminate(false);
		progress.setValue(0);
		//...
		progress.setValue(100);
		checkDataUpdated();
	}).toService();
}

private void checkDataUpdated() {
	runner = Runner.run(() -> {
		progress.setIndeterminate(false);
		progress.setValue(0);
		//...
		progress.setValue(100);
		loadUser();
	}).toService();
}

private void loadUser() {
	runner = Runner.run(() -> {
		progress.setIndeterminate(false);
		progress.setValue(0);
		//...
		progress.setValue(100);
		launchApp();
	}).toService();
}

private void launchApp() {
	runner = Runner.run(() -> {
		progress.setValue(0);
		progress.setIndeterminate(true);
		Runner.run(() -> { window.dispose(); }, 100);
	}).toService();
}

What I don't understand is that it does it apparently randomly, without changing any of the code or circumstances when running it.

perhaps the progressbar can be set to null here? Runner.run(() -> { window.dispose(); }, 100); but I've never seen it happen without the FlatLaf library so far...

@DevCharly
Copy link
Collaborator

Looks like a threading issue.

You need to do all modifications of the progress bar on the AWT thread. Use SwingUtilities.invokeLater().

What I don't understand is that it does it apparently randomly, without changing any of the code or circumstances when running it

Because in "indeterminate" mode the progress bar repaints every 15ms on AWT thread while you modify it on another thread.

perhaps the progressbar can be set to null here? Runner.run(() -> { window.dispose(); }, 100);

You should dispose the window on AWT thread. This avoids the NPE.

but I've never seen it happen without the FlatLaf library so far...

I think this is because FlatLaf repaints progress bar in "indeterminate" mode every 15ms, but other Laf every 50ms.
So the chance that this happens in FlatLaf is much higher than in other Lafs.

DevCharly added a commit that referenced this issue May 9, 2024
…determinate progress bar UI or using `JProgressBar.setIndeterminate(false)` not on AWT thread, because this may throw NPE in `FlatProgressBarUI.paint()` (issues #841 and #830)
@DevCharly
Copy link
Collaborator

I've added some logs (including stack trace) to FlatProgressBarUI that warns when modifying indeterminate progress bar not on AWT thread.

Please try latest 3.5-SNAPSHOT: https://github.com/JFormDesigner/FlatLaf#snapshots

@Frank-99
Copy link
Author

Frank-99 commented May 9, 2024

Thank you, in the midst of it I didn't realise I was updating UI outside of AWT thread... Fixed it and will have to be more careful!

I've added some logs to FlatProgressBarUI that warns when modifying indeterminate progress bar not on AWT thread.

I also appreciate the friendly reminder for when dumb mistakes like mine are made and the promptness of which you've added this... amazing as always!

@Frank-99 Frank-99 closed this as completed May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants