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中的图形的拖拽了。