2017-03-08 3 views
2

저는 Java에서 GUI를 작성하여 지역 이상의 여러 사람들의 심장 박동수를 모니터합니다 (기밀성 이유로 수정 됨).XChart에서 JPanel로 다중 실시간 그래프 추가하기

총 8 개의 지역이 있고 각 지역에는 8 명이 있습니다. 이것들은 JTabbedPane에 의해 나타내지는 각 탭의 1 탭입니다. XChart 라이브러리를 사용하여 8 개의 실시간 그래프를 그리고 그려 봅니다. 데이터는 텍스트 파일에서 읽고 두 개의 이중 배열로 전달됩니다. 하나의 배열은 밀리 초 (x 축)이고 두 번째 배열은 1 인 (y 축)의 심박수 데이터입니다. 각 사용자는 해당 지역 탭에서 고유 한 그래프를 갖습니다.

이것은 병원에서 바이탈을 모니터링하기 위해 여러 개의 그래프를 보는 것과 유사합니다.이 그래프는이 응용 프로그램이 시뮬레이션 할 것으로 예상되는 것에 대한 개요를 얻습니다.

현재 모델 - 뷰 - 컨트롤러 아키텍처를 사용하고 있습니다.

TLDR; JTabbedPane 내의 JPanel 내의 탭 내에 복수의 실시간 XYChart를 추가하려고 시도하고 있습니다. 그러나 당분간 ONE 실시간 차트를 추가하는 것이 좋습니다.

View.java

private void initComponents() { 
    jTabbedPane1 = new javax.swing.JTabbedPane(); 
    tabRegion1 = new javax.swing.JPanel(); 
    jTabbedPane1.setTabPlacement(javax.swing.JTabbedPane.BOTTOM); 
    tabRegion1.setLayout(new java.awt.GridLayout(4, 2)); 

    // Populate the JPanel with empty static graphs 
    for(int i = 0; i < Global.MAX_GRAPHS; i++) 
     tabRegion1.add(Graph.getRandomStaticGraph()); 

    jTabbedPane1.addTab("Region 1", tabRegion1); 
} 

Graph.java 내가
http://knowm.org/how-to-make-real-time-charts-in-java/
를 검토 한 결과 (모델)

// Testing purposes 
public static JPanel getRandomStaticGraph() { 
    XYChart chart = getEmptyXYChart(); 

    XYSeries series = chart.addSeries("HeartRate", null, getRandomWalk(200)); 
    series.setMarker(SeriesMarkers.NONE); 
    return new XChartPanel(chart); 
} 

// Testing purposes 
public static JPanel getRandomRealTimeGraph() throws InterruptedException { 
    XYChart chart = getEmptyXYChart(); 

    // Show it 
    final SwingWrapper<XYChart> sw = new SwingWrapper<XYChart>(chart); 
    sw.displayChart(); 

    double phase = 0; 
    double[][] initdata = getSineData(phase); 
    XYSeries series = chart.addSeries("HeartRate", null, getRandomWalk(200)); 
    while(true) { 
     phase += 2 * Math.PI * 2/20.0; 

     Thread.sleep(100); 
     final double[][] data = getSineData(phase); 

     chart.updateXYSeries("sine", data[0], data[1], null); 
     sw.repaintChart(); 

    } 

} 
// To be used to generate random static graphs (testing purposes) 
private static double[] getRandomWalk(int numPoints) { 
    double[] y = new double[numPoints]; 
    y[0] = 0; 
    for(int i = 1; i < y.length; i++) 
     y[i] = y[i-1] + Math.random() - .5; 
    return y; 
} 

// To be used to generate real time graphs (testing purposes) 
private static double[][] getSineData(double phase) { 
    double[] xData = new double[100]; 
    double[] yData = new double[100]; 
    for(int i = 0; i < xData.length; i++) { 
     double radians = phase + (2 * Math.PI/xData.length * i); 
     xData[i] = radians; 
     yData[i] = Math.sin(radians); 
    } 
    return new double[][] {xData, yData}; 
} 

자원과 :이 사이트는 나를 만들 수있었습니다 실시간 그래프의 기본 클래스이지만 JP 내부에서이를 통합하는 방법은 없습니다. anel 또는 그것을 repaint() 또는 update()를 통해 "실시간"으로 만드는 방법. repaint() 또는 update()를 사용하는 것이 필요하지 않습니다. 나는 거의 모든 제안에 열려 있습니다.

현재 환경
- 넷빈즈 IDE 8.2 (의 GUI 발생기)
- 자바 1.8.0_111
- XChart의 JAR (http://knowm.org/open-source/xchart/)

추가 정보
난 그냥 아니에요 getRandomRealTimeGraph()를 호출하여 JPanel 또는 XChartPanel을 반환 할 수 있으므로 JTabbedPane에 추가 할 수 있습니다. 나는 도움이 될만한 제안을 원한다.

이 정보가 도움이되면 데이터가 이미 존재하며 2 개의 2 중 배열로 구문 분석됩니다. 그러나 지금은 x- 데이터와 y- 데이터로 받아 들여지고있는 것이 무엇인지는별로 신경 쓰지 않습니다. 내가 나중에 그것을 대체 할 수있는 한, 나는 무엇이든 행복하다.

정말 고마워요!

+0

'while-true' 루프가 이벤트 발송 스레드를 차단하여 UI가 업데이트되지 않을 위험이 있습니다. 업데이트를 수행하기 위해 SwingWorker 또는 Swing Timer를 사용하기를 원할 것입니다. MVC에 대한 생각은 조금 있습니다. – MadProgrammer

+0

더 이상의 컨텍스트가 없으면 도움이 될만한 곳을 알기가 어려워요. 'Graph' 클래스가 잘못되어 많은 일을하는 것 말고는 하나의 그래프만을 다루고 있습니다. 당신이 원하는 것은 프레젠테이션과 데이터 관리를 분리시키는 것입니다. 모델에 대한 업데이트가 발생하면 UI에 대한 요청을 트리거하여 새 데이터를 업데이트하려고합니다. 예를 들어 둘 이상의 모델이 필요할 수도 있습니다. 예를 들어 "원시"모델을 가지고있는 경우 차트 모델을 피드/업데이트하여 UI에 대한 업데이트를 트리거합니다. – MadProgrammer

답변

2

좋아, 큰 걸음을 내딛고 달성하고자하는 점에 대해 생각해 봐야합니다. 그러면 차트 하나에서 작동하게 만들 수있는 방법을 알아야합니다. , 당신은 그것을 확장 할 수 있어야합니다.

간단한 개념의 모델로 시작하십시오.모델은 파일, 웹 서비스, 데이터베이스, 직렬 포트 또는 기타 다른 수단에서 오는 것인지 여부에 상관없이 데이터를 추상화해야하며 솔루션의 다른 부분은 신경 쓰지 않아야합니다. 데이터에 대한 관심은 공통된 방식으로 제시되었습니다.

뭔가 같은 ...

public interface HeartMonitorModel { 
    public List<Double>[] getSineData(); 
    public List<Double> getWalkData(); 
} 

그리고 그래, 당신이 각 차트에 대해 별도의 모델이 필요합니다, 그렇지 않으면 당신은 각각 동일한 데이터를 제시됩니다.

이제 인수하기 위해 코드를 작성하고 간단한 기본 구현을 생성했습니다.

public class DefaultHeartMonitorModel implements HeartMonitorModel { 

    private double phase = 0; 
    private int numPoints = 200; 

    @Override 
    public List[] getSineData() { 
     phase += 2 * Math.PI * 2/20.0; 
     List<Double> xData = new ArrayList<>(100); 
     List<Double> yData = new ArrayList<>(100); 
     for (int i = 0; i < 100; i++) { 
      double radians = phase + (2 * Math.PI/100 * i); 
      xData.add(radians); 
      yData.add(Math.sin(radians)); 
     } 
     return new List[]{xData, yData}; 
    } 

    @Override 
    public List getWalkData() { 
     List<Double> data = new ArrayList<>(numPoints); 
     data.add(0.0); 
     for (int i = 1; i < numPoints; i++) { 
      double last = data.get(i - 1); 
      data.add(last + + Math.random() - .5); 
     } 
     return data; 
    } 

} 

이론적으로,이 중 많은 인스턴스를 만들 수 있어야하고 우리가 필요로하는 두 가지 더가 지금 약간 임의의 데이터

을 제시한다, 우리는 도표로 표시 할 수있는 방법이 필요합니다 데이터 및 그것을 업데이트하는 방법.

우리의 모델을 업데이트하려면, 우리는 스레드이로

이벤트 디스패치를 ​​차단하지 않는 방법으로 UI에 다시 공급하기 위해 새로운 데이터와 어떤 방법을 얻을 어떻게든지 필요, 나는 간단한 시작 다리 역할을 인터페이스

public interface ChartMonitor { 
    public HeartMonitorModel getModel(); 
    public void updateData(List<Double>[] data); 
} 

이는 백그라운드에서 새 데이터를 요청하고 안전하게 화면에 업데이트 할 수 있도록 EDT 다시 그 정보를 피드에 SwingWorker에 의해 사용되는

public class UpdateWorker extends SwingWorker<Void, List<Double>[]> { 

    private ChartMonitor monitor; 
    private XYChart chart; 

    public UpdateWorker(ChartMonitor monitor) { 
     this.monitor = monitor; 
    } 

    @Override 
    protected Void doInBackground() throws Exception { 
     while (true) { 
      Thread.sleep(100); 
      publish(monitor.getModel().getSineData()); 
     } 
    } 

    @Override 
    protected void process(List<List<Double>[]> chunks) { 
     for (List<Double>[] data : chunks) { 
      monitor.updateData(data); 
     } 
    } 

} 
,

마지막으로, 우리는 ...

public class SeriesChartPane extends JPanel implements ChartMonitor { 

    private HeartMonitorModel model; 
    private XYChart chart; 

    public SeriesChartPane(HeartMonitorModel model) { 
     this.model = model; 
     chart = new XYChartBuilder().width(400).height(200).title("Are you dead yet?").build(); 

     List<Double> walkData = model.getWalkData(); 
     chart.addSeries("Heart Rate", null, walkData); 

     List<Double>[] sineData = model.getSineData(); 
     chart.addSeries("sine", sineData[0], sineData[1]); 
     setLayout(new BorderLayout()); 

     XChartPanel<XYChart> chartPane = new XChartPanel<>(chart); 
     add(chartPane); 

     UpdateWorker worker = new UpdateWorker(this); 
     worker.execute(); 
    } 

    @Override 
    public HeartMonitorModel getModel() { 
     return model; 
    } 

    @Override 
    public void updateData(List<Double>[] data) { 
     chart.updateXYSeries("sine", data[0], data[1], null); 
     repaint(); 
    } 

} 

를 모두 표시 할 멀리해야합니다 그리고 우리는 우리의 자신의 창에 표시

public class HeartMonitor { 

    public static void main(String[] args) { 
     new HeartMonitor(); 
    } 

    public HeartMonitor() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       HeartMonitorModel model = new DefaultHeartMonitorModel(); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new SeriesChartPane(model)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 

에 대한 Concurrency in SwingWorker Threads and SwingWorker 좀 걸릴 수 있습니다 스윙 및 스레딩

를 작동하는 방법에 대한 자세한 내용은 또한 Model-View-Controller 패러다임에 원기를 회복시키는 작업을 수행 할 수 있습니다

+0

안녕하세요! 모든 것을 설명하고 내 GUI를위한 더 나은 조직 전략을 제안 할뿐만 아니라 그 놀라운 믿을만한 세부적인 도움을 MadProgrammer에게 너무 감사드립니다. 도와 주셔서 감사합니다. – Yuki