Skip to content

Instantly share code, notes, and snippets.

@dhsrocha
Created January 1, 2024 21:38
Show Gist options
  • Save dhsrocha/4c275de093bcc05f9328814dab94b064 to your computer and use it in GitHub Desktop.
Save dhsrocha/4c275de093bcc05f9328814dab94b064 to your computer and use it in GitHub Desktop.
package com.ludo.adapter.awt;
import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;
final class Client {
private static final System.Logger LOGGER = System.getLogger("");
private static final System.Logger.Level INFO = System.Logger.Level.INFO;
private static final String TITLE = "Swing Worker Example";
private final ExamplePanel panel;
Client(final Runnable callback) {
this.panel = new ExamplePanel();
this.panel.addPropertyChangeListener(new PropListener(this.panel, callback));
}
public static void main(final String[] args) {
EventQueue.invokeLater(
() -> {
LOGGER.log(INFO, "Here I start");
final Runnable cb = () -> LOGGER.log(INFO, "This is being displayed from a Runnable");
new Client(cb).displayGUI();
LOGGER.log(INFO, "This is displayed after the dialog is no longer visible");
});
}
private void displayGUI() {
final var modal = new JDialog(null, TITLE, Dialog.ModalityType.APPLICATION_MODAL);
modal.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
modal.add(panel);
modal.pack();
modal.setLocationByPlatform(true);
modal.setVisible(true);
panel.run();
}
private record PropListener(ExamplePanel panel, Runnable callback)
implements PropertyChangeListener {
@Override
public void propertyChange(final PropertyChangeEvent event) {
if (event.getNewValue() == SwingWorker.StateValue.DONE) {
final var status = panel.getProcessStatus();
LOGGER.log(INFO, "Process State: " + status + "\n");
callback.run(); // simply run it. No need to place into a new thread
}
}
}
}
final class ExamplePanel extends JPanel implements Runnable {
// Components
private final JLabel status = new JLabel("Status: ", SwingConstants.CENTER);
private final JTextArea textArea = new JTextArea(20, 30);
private final JProgressBar bar = new JProgressBar();
// Actions
private final StartAction start = new StartAction("Start", KeyEvent.VK_S);
private final StopAction stop = new StopAction("Stop", KeyEvent.VK_T);
private Worker worker;
private int processStatus;
ExamplePanel() {
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout(5, 5));
final var sp = new JScrollPane();
sp.setBorder(BorderFactory.createTitledBorder("Output: "));
sp.setViewportView(textArea);
add(sp, BorderLayout.CENTER);
final var buttonTray = new JPanel();
buttonTray.add(new JButton(start));
buttonTray.add(new JButton(stop));
buttonTray.add(bar);
add(buttonTray, BorderLayout.PAGE_END);
add(status, BorderLayout.PAGE_START);
textArea.setFocusable(false);
stop.setEnabled(false);
}
int getProcessStatus() {
return processStatus;
}
@Override
public void run() {
if (worker != null && !worker.isDone()) {
return; // background task not yet done
}
textArea.setText("");
start.setEnabled(false);
stop.setEnabled(true);
worker = new Worker();
worker.addPropertyChangeListener(new PropListener(this::printAndDisableComponents));
worker.execute();
bar.setIndeterminate(true);
}
void cancel() {
if (worker != null && !worker.isDone()) {
worker.cancel(true);
}
}
void printAndDisableComponents() {
status.setText(worker.getState() + " " + processStatus);
stop.setEnabled(false);
start.setEnabled(true);
bar.setIndeterminate(false);
}
private final class PropListener implements PropertyChangeListener {
private final Runnable whenDone;
private PropListener(final Runnable whenDone) {
this.whenDone = whenDone;
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
if (event.getNewValue() == SwingWorker.StateValue.DONE) {
whenDone.run();
}
firePropertyChange(event.getPropertyName(), event.getOldValue(), event.getNewValue());
}
}
private final class Worker extends SwingWorker<Integer, String> implements Serializable {
@Override
protected Integer doInBackground() throws Exception {
final var list = new ArrayList<String>();
list.add("ping");
list.add(System.getProperty("os.name").startsWith("Win") ? "-n" : "-c");
list.add("5");
list.add("google.com");
final var pb = new ProcessBuilder(list);
pb.redirectErrorStream(true);
final var p = pb.start();
String s;
final var stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null && !isCancelled()) {
publish(s);
}
if (!isCancelled()) {
processStatus = p.waitFor();
}
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
p.destroy();
return processStatus;
}
@Override
protected void process(final List<String> messages) {
status.setText((this.getState()).toString());
for (final var m : messages) {
textArea.append(m + "\n");
}
}
}
private final class StartAction extends AbstractAction {
StartAction(final String name, final int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(final ActionEvent e) {
run();
}
}
private final class StopAction extends AbstractAction {
public StopAction(final String name, final int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(final ActionEvent e) {
cancel();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment