好久没更新过技术相关的东西了,今天要开始写管理控制台,里面需要用到实时曲线图,决定使用JFreeChart做,这东西还真的挺好用,简单的几句代码就能搭建一个看起来不错的程序:-)
预览图:
/* * RealTimeGraphPanel.java * * Created on 2008年10月1日, 下午2:04 */ package cn.bearice.ipcontroller.manager.graph; import cn.bearice.java.util.StopableThread; import java.awt.BorderLayout; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Random; import javax.swing.JFrame; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.data.time.Second; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; /** * * @author Bearice */ public class RealTimeGraphPanel extends javax.swing.JPanel { private static final long serialVersionUID = 8250077948583513551L; TimeSeriesCollection tcl; ChartPanel cp; JFreeChart jfc; ArrayList tss = new ArrayList(); TimeSeries tts = new TimeSeries("Avg.", Second.class); /** Creates new form RealTimeGraphPanel */ public RealTimeGraphPanel() { tcl = new TimeSeriesCollection(); tcl.addSeries(tts); addTimeSeries(); jfc = ChartFactory.createTimeSeriesChart("Random Numbers", "Time", "Value", tcl, true, true, false); XYPlot xyplot = jfc.getXYPlot(); ValueAxis valueaxis = xyplot.getDomainAxis(); valueaxis.setAutoRange(true); // valueaxis.setInverted(true); valueaxis = xyplot.getRangeAxis(); valueaxis.setAutoRange(true); cp = new ChartPanel(jfc); initComponents(); } public void addTimeSeries() { TimeSeries timeSeries = new TimeSeries("Random" + tss.size(), Second.class); tcl.addSeries(timeSeries); tss.add(timeSeries); } public static void main(String[] args) { JFrame frame = new JFrame("Test Chart"); final RealTimeGraphPanel rtgp = new RealTimeGraphPanel(); frame.getContentPane().add(rtgp, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent windowevent) { System.exit(0); } }); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // private void initComponents() { jbtnStartStop = new javax.swing.JButton(); jPanel1 = (cp); jbtnFixed = new javax.swing.JButton(); jbtnScaled = new javax.swing.JButton(); jbtnClear = new javax.swing.JButton(); jbtnAdd = new javax.swing.JButton(); setName("Form"); // NOI18N jbtnStartStop.setText("Start"); jbtnStartStop.setName("jbtnStartStop"); // NOI18N jbtnStartStop.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jbtnStartStopActionPerformed(evt); } }); jPanel1.setName("jPanel1"); // NOI18N javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 400, Short.MAX_VALUE) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 261, Short.MAX_VALUE) ); jbtnFixed.setText("Fixed"); jbtnFixed.setName("jbtnFixed"); // NOI18N jbtnFixed.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jbtnFixedActionPerformed(evt); } }); jbtnScaled.setText("Scaled"); jbtnScaled.setName("jbtnScaled"); // NOI18N jbtnScaled.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jbtnScaledActionPerformed(evt); } }); jbtnClear.setText("Clear"); jbtnClear.setName("jbtnClear"); // NOI18N jbtnClear.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jbtnClearActionPerformed(evt); } }); jbtnAdd.setText("Add"); jbtnAdd.setName("jbtnAdd"); // NOI18N jbtnAdd.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jbtnAddActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jbtnStartStop) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(jbtnFixed) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jbtnScaled) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jbtnClear) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jbtnAdd) .addContainerGap(53, Short.MAX_VALUE)) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jbtnStartStop) .addComponent(jbtnFixed) .addComponent(jbtnScaled) .addComponent(jbtnClear) .addComponent(jbtnAdd)) .addContainerGap()) ); }// class T1 extends StopableThread { @Override protected void loop() throws InterruptedException { for (TimeSeries timeSeries : tss) { double d = randomNum(); num = (num + d) / 2; timeSeries.add(new Second(), d); } tts.add(new Second(), num); Thread.sleep(1000); } double num; Random rand = new Random(); private double randomNum() { return rand.nextGaussian(); } } T1 t1; private void jbtnStartStopActionPerformed(java.awt.event.ActionEvent evt) { if (t1 == null) { t1 = new T1(); t1.start(); jbtnStartStop.setText("stop"); } else { t1.exit(); t1 = null; jbtnStartStop.setText("start"); } } private void jbtnFixedActionPerformed(java.awt.event.ActionEvent evt) { // cp.setAutoscrolls(true); XYPlot xyplot = jfc.getXYPlot(); ValueAxis valueaxis = xyplot.getDomainAxis(); valueaxis.setFixedAutoRange(50000); } private void jbtnScaledActionPerformed(java.awt.event.ActionEvent evt) { XYPlot xyplot = jfc.getXYPlot(); ValueAxis valueaxis = xyplot.getDomainAxis(); valueaxis.setFixedAutoRange(0); } private void jbtnClearActionPerformed(java.awt.event.ActionEvent evt) { for (TimeSeries timeSeries : tss) { timeSeries.clear(); } } private void jbtnAddActionPerformed(java.awt.event.ActionEvent evt) { addTimeSeries(); } // Variables declaration - do not modify private javax.swing.JPanel jPanel1; private javax.swing.JButton jbtnAdd; private javax.swing.JButton jbtnClear; private javax.swing.JButton jbtnFixed; private javax.swing.JButton jbtnScaled; private javax.swing.JButton jbtnStartStop; // End of variables declaration }
PS:里面用到了一个自己实现的StopableThread,代码如下:
/* * Copyrights (C) 2008 Bearice ([email protected]) * Release under GNU/GPL Version 2. */ package cn.bearice.java.util; /** * 可以停止的线程。 * @author Bearice */ public abstract class StopableThread extends Thread { protected boolean exit = false; /** * 线程开始后,进入循环前调用。 */ protected void before() { //System.out.println("Starting thread: "+this); } /** * 线程退出前,循环退出后调用。 */ protected void after() { // System.out.println("Ending thread: "+this); } /** * 循环体代码。 * @throws java.lang.InterruptedException */ protected abstract void loop() throws InterruptedException; /** * 指示线程退出循环。 */ public synchronized void exit() { exit = true; interrupt(); } @Override public final void run() { before(); while (!exit) { try { loop(); } catch (InterruptedException ex) { } } after(); } }
JFC……感觉比MFC只管多了,直逼WinForm……
ps:考拉把这个评论放在页面内,顺便把验证码去掉~
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0)
Sign: kxdrb Hello!!! zsmbs and 2985wbvdddzsws and 671 My Comments: Nice blog!