Java 将多个实时图形从XChart添加到JPanel
我负责用Java创建一个GUI来监控多个地区多人的心率(出于保密原因进行了修改) 总共有8个地区,每个地区有8个人。这些由JTabbedPane表示,每个区域有一个选项卡。我正在尝试使用XChart库绘制和创建8个实时图形。数据将从文本文件中读取,并作为两个双数组传递。其中一个数组是以毫秒为单位的时间(x轴),第二个数组是一个人的心率数据(y轴)。每个人在其相应的区域选项卡中都有自己的图表 这类似于观看几张图表来监测医院的生命体征,以了解该应用程序应该模拟什么 我目前正在使用模型-视图-控制器体系结构 TLDR要分解它,我只尝试在JTabbedPane内的JPanel内的选项卡中添加多个实时XYChart。但就目前而言,只需添加一张实时图表就好了 View.javaJava 将多个实时图形从XChart添加到JPanel,java,swing,user-interface,graph,jtabbedpane,Java,Swing,User Interface,Graph,Jtabbedpane,我负责用Java创建一个GUI来监控多个地区多人的心率(出于保密原因进行了修改) 总共有8个地区,每个地区有8个人。这些由JTabbedPane表示,每个区域有一个选项卡。我正在尝试使用XChart库绘制和创建8个实时图形。数据将从文本文件中读取,并作为两个双数组传递。其中一个数组是以毫秒为单位的时间(x轴),第二个数组是一个人的心率数据(y轴)。每个人在其相应的区域选项卡中都有自己的图表 这类似于观看几张图表来监测医院的生命体征,以了解该应用程序应该模拟什么 我目前正在使用模型-视图-控制器体
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);
}
private void initComponents(){
jTabbedPane1=newjavax.swing.JTabbedPane();
tabRegion1=newjavax.swing.JPanel();
setTabPlacement(javax.swing.jTabbedPane1.BOTTOM);
tabRegion1.setLayout(新java.awt.GridLayout(4,2));
//用空静态图填充JPanel
对于(int i=0;i
Graph.java(模型)
//测试目的
公共静态JPanel getRandomStaticGraph(){
XYChart chart=getEmptyXYChart();
XYSeries=chart.addSeries(“心率”,null,getRandomWalk(200));
系列。设置标记(系列标记。无);
返回新面板(图表);
}
//测试目的
公共静态JPanel getRandomRealTimeGraph()抛出InterruptedException{
XYChart chart=getEmptyXYChart();
//表现出来
最终摇摆振打器sw=新摇摆振打器(图表);
sw.displayChart();
双相=0;
double[]initdata=getSineData(阶段);
XYSeries=chart.addSeries(“心率”,null,getRandomWalk(200));
while(true){
相位+=2*Math.PI*2/20.0;
睡眠(100);
最终双[][]数据=getSineData(阶段);
图表.UpdateXeseries(“正弦”,数据[0],数据[1],空);
sw.repaitchart();
}
}
//用于生成随机静态图(测试目的)
私有静态双[]getRandomWalk(int numPoints){
double[]y=新的双精度[numPoints];
y[0]=0;
对于(int i=1;i
资源和我查看过的地方:此网站帮助我创建了一个实时图形基类,但无法帮助将其集成到JPanel中,也无法帮助我通过repaint()或update()使其成为“实时”图形。并不是说必须使用repaint()或update()。我愿意接受几乎所有的建议 当前环境
-NetBeans IDE 8.2(用于GUI生成器)
-Java 1.8.0_111
-XChart JAR() 附加注释
我无法调用getRandomRealTimeGraph()来返回JPanel甚至XChartPanel,因此我可以将其添加到JTabbedPane。我会喜欢任何有帮助的建议
如果这有帮助的话,数据已经存在并且正在被解析为两个双精度数组。但就目前而言,我并不真正关心x数据和y数据。只要我以后能把它换掉,我对任何事情都满意
非常感谢你 好吧,你需要后退一大步,想想你想要实现什么,然后你需要弄清楚如何让它适用于一张图表,如果你能让它适用于一张图表,你应该能够调整它 从一个简单的模型概念开始。模型应该将数据抽象出来,这样不管数据来自文件、web服务、数据库、串行端口还是其他方式,解决方案的其他部分不应该关心,它们应该只关心以常见方式呈现的数据 类似于
public interface HeartMonitorModel {
public List<Double>[] getSineData();
public List<Double> getWalkData();
}
最后,我们需要把它全部展示出来
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();
}
}
查看和了解有关Swing和线程工作原理的更多详细信息
当true循环有阻塞事件调度线程的危险时,您可能还需要对范式进行刷新,以防止UI更新。你可能想用一个SwingWorker或者一个Swing
定时器来执行更新-而且,你对MVC的想法有点离谱,没有更多的上下文,很难知道在哪里提供帮助,我的直觉是你的Graph
类是错误的,除了做很多工作之外,它只处理一个图形。您要做的是将数据的管理与演示分离。当模型发生更新时,您希望触发对UI的请求以更新新数据。这可能需要您有多个模型,例如,您可能有“原始”模型,然后将其输入/更新图表模型,然后触发对UIHi的某种更新!非常感谢程序员提供的难以置信的详细帮助,以及对一切的解释和建议
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;
}
}
public interface ChartMonitor {
public HeartMonitorModel getModel();
public void updateData(List<Double>[] data);
}
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);
}
});
}
}