jfreechart是一个优秀的开源chart软件。利用jfreechart可以绘制出各种丰富和优美的图形。但是在jfreechart的图上对于鼠标的支持不很充分,对于鼠标的clicked、moved、pressed、released、entered、exited的事件只支持了两个clicked和moved(不知道为什么?),幸运的是jfreechart是一个开源的软件,可以对于它的实现进行升级,在它传统的功能基础上,实现自己的功能需求。
jfreechart中的鼠标事件实现机制为:一是扩展java.util.EventListener接口为ChartMouseListener,在其中定义了chartMouseClicked和chartMouseMoved两个事件响应函数;而是继承java.util.EventObject类生成ChartMouseEvent,在ChartMouseEvent中封装了鼠标事件和Jfreechart的对象,供事件处理函数中应用;三是在jfreechart的ChartPanel中定义了事件监听器队列,当外部程序注册了事件监听器后,在chartpanel中发生定义的事件后,监听器响应响应的事件。
在jfreechart默认的实现中,对于鼠标事件,只有clicked和moved可以供外部监听,其他事件提供了默认的监听实现,这样就阻碍了外部对jfreechart的更深入的鼠标操作。
为了实现其它事件能够被外部监听器监听,首先需要对ChartPanel中的事件监听机制进行调整,这里我利用MyChartPanel继承ChartPanel,重载其中所需要被外部监听器监听的事件的实现函数,把事件发给外部的监听器,类定义如下所示:
import java.awt.Insets; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.EntityCollection; @SuppressWarnings("serial") public class MyChartPanel extends ChartPanel { public MyChartPanel(JFreeChart chart) { super(chart); // TODO Auto-generated constructor stub } /* (non-Javadoc) * @see org.jfree.chart.ChartPanel#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(MouseEvent event) { // TODO Auto-generated method stub Insets insets = getInsets(); int x = (int) ((event.getX() - insets.left) /this.scaleX); int y = (int) ((event.getY() - insets.top) / this.scaleY); this.anchor = new Point2D.Double(x, y); if (this.chart == null) { return; } this.chart.setNotify(true); // force a redraw // new entity code... Object[] listeners = this.chartMouseListeners.getListeners( ChartMouseListener.class); if (listeners.length == 0) { return; } ChartEntity entity = null; if (this.info != null) { EntityCollection entities = this.info.getEntityCollection(); if (entities != null) { entity = entities.getEntity(x, y); } } ChartMouseEvent chartEvent = new ChartMouseEvent(getChart(), event, entity); for (int i = listeners.length - 1; i >= 0; i -= 1) { ((MyChartMouseListener) listeners[i]).chartMousePressed(chartEvent); } } /* (non-Javadoc) * @see org.jfree.chart.ChartPanel#mouseReleased(java.awt.event.MouseEvent) */ @Override public void mouseReleased(MouseEvent event) { // TODO Auto-generated method stub Insets insets = getInsets(); int x = (int) ((event.getX() - insets.left) /this.scaleX); int y = (int) ((event.getY() - insets.top) / this.scaleY); this.anchor = new Point2D.Double(x, y); if (this.chart == null) { return; } this.chart.setNotify(true); // force a redraw // new entity code... Object[] listeners = this.chartMouseListeners.getListeners( ChartMouseListener.class); if (listeners.length == 0) { return; } ChartEntity entity = null; if (this.info != null) { EntityCollection entities = this.info.getEntityCollection(); if (entities != null) { entity = entities.getEntity(x, y); } } ChartMouseEvent chartEvent = new ChartMouseEvent(getChart(), event, entity); for (int i = listeners.length - 1; i >= 0; i -= 1) { ((MyChartMouseListener) listeners[i]).chartMouseReleased(chartEvent); } } }
把mousePressed和mouseReleased事件转发出来。
扩展ChartMouseListener,增加这两个事件的出来接口:
import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; public interface MyChartMouseListener extends ChartMouseListener { public void chartMousePressed(ChartMouseEvent event); public void chartMouseReleased(ChartMouseEvent event); }
实现自定义的MouseListener:
import java.awt.Cursor; import java.awt.Shape; import javax.swing.JPanel; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.JFreeChart; import org.jfree.chart.entity.XYItemEntity; import org.jfree.data.xy.XYIntervalDataItem; import org.jfree.data.xy.XYIntervalSeries; import org.jfree.data.xy.XYIntervalSeriesCollection; public class MyBarChartListener implements MyChartMouseListener { @Override public void chartMouseClicked(ChartMouseEvent event) { // TODO Auto-generated method stub /* JFreeChart chart = event.getChart(); if (chart == null) return; XYItemEntity ce = (XYItemEntity) event.getEntity(); if (ce == null) return; IntervalXYDataset my = (IntervalXYDataset) ce.getDataset(); int sindex = ce.getSeriesIndex(); int iindex = ce.getItem(); System.out.println("x = " + my.getXValue(sindex, iindex)); System.out.println("y = " + my.getYValue(sindex, iindex)); */ } @Override public void chartMouseMoved(ChartMouseEvent event) { // TODO Auto-generated method stub } XYItemEntity ce; XYIntervalSeriesCollection my; @Override public void chartMousePressed(ChartMouseEvent event) { // TODO Auto-generated method stub System.out.println("mouse chartMousePressed"); JPanel src = (JPanel) event.getTrigger().getSource(); src.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); JFreeChart chart = event.getChart(); if (chart == null) return; ce = (XYItemEntity) event.getEntity(); if (ce == null) return; my = (XYIntervalSeriesCollection) ce.getDataset(); int sindex = ce.getSeriesIndex(); int iindex = ce.getItem(); Shape shape = ce.getArea(); System.out.println("sindex = " + sindex); System.out.println("iindex = " + iindex); System.out.println("x = " + my.getXValue(sindex, iindex)); System.out.println("y = " + my.getYValue(sindex, iindex)); XYIntervalSeries series = (XYIntervalSeries) my.getSeries(ce.getSeriesIndex()); System.out.println("y1 = " + shape.getBounds2D().getCenterY()); /* series.remove(my.getXValue(sindex, iindex)); Day day1 = new Day(13, 6, 2007); Day day2 = new Day(14, 6, 2007); XYBarChartDemo7.addItem(series,day1,day2,sindex); */ } @Override public void chartMouseReleased(ChartMouseEvent event) { // TODO Auto-generated method stub System.out.println("mouse chartMouseReleased"); MyChartPanel src = (MyChartPanel) event.getTrigger().getSource(); src.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); double cursorY = event.getTrigger().getY(); System.out.println("y = "+ cursorY); int seriesIndex = my.getSeriesCount(); double maxY = src.getScreenDataArea().getMaxY(); double minY = src.getScreenDataArea().getMinY(); double heightY = (maxY-minY)/seriesIndex; for(int i=0;i<seriesIndex;i++) { if(cursorY >= minY && cursorY<=(i+1)*heightY) { XYIntervalSeries srcSeries =((XYIntervalSeriesCollection) (this.ce.getDataset())).getSeries(seriesIndex-i-1); XYIntervalSeriesCollection destSeriesCollection = (XYIntervalSeriesCollection) (this.ce.getDataset()); XYIntervalSeries destSeries =destSeriesCollection.getSeries(this.ce.getSeriesIndex()); XYIntervalDataItem item = (XYIntervalDataItem) destSeries.getDataItem(this.ce.getItem()); srcSeries.add(item.getX(), item.getXLowValue(), item.getXHighValue(), seriesIndex-i-1, seriesIndex-i-1-0.1, seriesIndex-i-1+0.3); destSeries.remove(destSeriesCollection.getXValue(this.ce.getSeriesIndex(), this.ce.getItem())); /* Day day1 = new Day(13, 6, 2007); Day day2 = new Day(14, 6, 2007); XYBarChartDemo7.addItem(series,day1,day2,seriesIndex-i-1); */ break; } } }
就可以实现在jfreechart中的图形的拖拽了。