3

I'm using the xchart library for Java and I'm creating a chart as follows:

        XYChart chartHR = QuickChart.getChart("Title", "Time", "y", "randomWalk", new double[] { 0 }, new double[] { 0 });
        chartHR.getStyler().setLegendVisible(false);
        chartHR.getStyler().setXAxisTicksVisible(false);
        SwingWrapper<XYChart> swHR = new SwingWrapper<XYChart>(chartHR);
        swHR.displayChart().setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

I'm creating this chart in a thread launched from my main class. Everytime I close the chart my whole application is closed. How can I prevent that?

Here is the minimal working example:

package test;

import java.util.Scanner;

public class Test {

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        testThread.start();

        String input = "";
        Scanner scanner = new Scanner(System.in);
        while (!input.equals("q")) {
            System.out.print("Enter 'q' for termination.");
            input = scanner.nextLine();
        }
        scanner.close();
    }

}

package test;

import javax.swing.JFrame;

import org.knowm.xchart.QuickChart;
import org.knowm.xchart.SwingWrapper;
import org.knowm.xchart.XYChart;

public class TestThread extends Thread {

    private SwingWrapper<XYChart> swHR;
    private XYChart chartHR;

    public void run() {
        chartHR = QuickChart.getChart("Test", "Time", "y", "randomWalk", new double[] { 0 }, new double[] { 0 });
        chartHR.getStyler().setLegendVisible(false);
        chartHR.getStyler().setXAxisTicksVisible(false);
        swHR = new SwingWrapper<XYChart>(chartHR);
        swHR.displayChart().setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        while(true) {}
    }
}
machinery
  • 5,972
  • 12
  • 67
  • 118
  • 1
    Make sure all your threads aren't just finishing, perhaps? You should post a [MCVE] – pvg Jun 27 '17 at 13:45
  • 1
    @pvg I have added an example – machinery Jun 27 '17 at 14:01
  • You should read this https://docs.oracle.com/javase/tutorial/uiswing/concurrency/ You don't need the extra thread to begin with (and generally shouldn't subclass Thread) and you should do your gui setup from the event dispatch thread. This is what the chart library does but you don't. You end up in a race condition where your change happens before the change `displayChart` makes. – pvg Jun 27 '17 at 14:27
  • 2
    Arguably, this is a bug in xchart's convenience class since it hands you back a frame which it then proceeds to fiddle with. It's not behaviour one can reasonably expect nor is it documented. Seems like someone went ahead and filed it already at https://github.com/timmolter/XChart/issues/197 – pvg Jun 27 '17 at 14:37

1 Answers1

4

If you check the source code, the SwingWrapper sets the default close operation for the JFrame on the EDT. You are not, so you set the value, then it is overwritten. To fix this, post your change to the EDT and it should work.

JFrame frame = swHR.displayChart();
javax.swing.SwingUtilities.invokeLater(
    ()->frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
);

That should go in the queue and happen after the changes the SwingWrapper makes.

matt
  • 10,892
  • 3
  • 22
  • 34