首页 > 技术文章 > 图书管理系统总结——统计图实现

satire 2017-05-14 11:00 原文

JAVA的JFreeChar提供了绘制各种与统计有关的图形,比如直方图,折线图,饼图等,而且有各种样式。这里只是应用了最简单的绘制,没有什么炫酷的修饰。

一、饼状图:

实现饼状图的类为

public class PieChart {
    ChartPanel frame1;
    
    public PieChart() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * 画出指定大小饼状图
     * @param v 表示图片大小
     * @param TypeBuffer 用来记录图书种类
     * @param number 用来记录每种图书对应的数量
     */
    public PieChart(Dimension v,StringBuffer[] TypeBuffer,int[] number)
    {
          DefaultPieDataset data = getDataSet(TypeBuffer,number);//数据集获得
          JFreeChart chart = ChartFactory.createPieChart3D(
                                       "借阅分类分布",//// 图表标题
                                        data,//数据集 
                                         true,// 是否显示图例 
                                         false,// 是否生成工具 
                                          false// 是否生成URL链接  
                                          );// 创建图表
        //设置百分比
          PiePlot pieplot = (PiePlot) chart.getPlot();
          DecimalFormat df = new DecimalFormat("0.00%");//获得一个DecimalFormat对象,主要是设置小数问题
          NumberFormat nf = NumberFormat.getNumberInstance();//获得一个NumberFormat对象
          StandardPieSectionLabelGenerator sp1 = new StandardPieSectionLabelGenerator("{0}  {2}", nf, df);//获得StandardPieSectionLabelGenerator对象
          pieplot.setLabelGenerator(sp1);//设置饼图显示百分比
      
      //没有数据的时候显示的内容
          pieplot.setNoDataMessage("无数据显示");
          pieplot.setCircular(false);
          pieplot.setLabelGap(0.02D);
      
          pieplot.setIgnoreNullValues(true);//设置不显示空值
          pieplot.setIgnoreZeroValues(true);//设置不显示负值
          frame1=new ChartPanel (chart,true);
          frame1.setPreferredSize(new Dimension(v));//设置大小
          chart.getTitle().setFont(new Font("宋体",Font.BOLD,35));//设置标题字体
          PiePlot piePlot= (PiePlot) chart.getPlot();//获取图表区域对象
          piePlot.setLabelFont(new Font("宋体",Font.BOLD,30));//解决乱码,设置标签的字体
          chart.getLegend().setItemFont(new Font("黑体",Font.BOLD,35));//设置下面图例字体
    }

    /**
     *生成与外界窗口一样大小图
     * @param TypeBuffer
     * @param number
     */
    public PieChart(StringBuffer[] TypeBuffer,int[] number)
    {
          DefaultPieDataset data = getDataSet(TypeBuffer,number);
          JFreeChart chart = ChartFactory.createPieChart3D("借阅分类分布",data,true,false,false);
        //设置百分比
          PiePlot pieplot = (PiePlot) chart.getPlot();
          DecimalFormat df = new DecimalFormat("0.00%");//获得一个DecimalFormat对象,主要是设置小数问题
          NumberFormat nf = NumberFormat.getNumberInstance();//获得一个NumberFormat对象
          StandardPieSectionLabelGenerator sp1 = new StandardPieSectionLabelGenerator("{0}  {2}", nf, df);//获得StandardPieSectionLabelGenerator对象
          pieplot.setLabelGenerator(sp1);//设置饼图显示百分比
      
      //没有数据的时候显示的内容
          pieplot.setNoDataMessage("无数据显示");
          pieplot.setCircular(false);
          pieplot.setLabelGap(0.02D);
      
          pieplot.setIgnoreNullValues(true);//设置不显示空值
          pieplot.setIgnoreZeroValues(true);//设置不显示负值
          frame1=new ChartPanel (chart,true);
          chart.getTitle().setFont(new Font("宋体",Font.BOLD,35));//设置标题字体
          PiePlot piePlot= (PiePlot) chart.getPlot();//获取图表区域对象
          piePlot.setLabelFont(new Font("宋体",Font.BOLD,30));//解决乱码
          chart.getLegend().setItemFont(new Font("黑体",Font.BOLD,35));
    }
    /**
     * 获得数据集
     * @param TypeBuffer
     * @param number
     * @return
     */
    private static DefaultPieDataset getDataSet(StringBuffer[] TypeBuffer,int[] number) 
    {
        DefaultPieDataset dataset = new DefaultPieDataset();
        for(int i=0;i<TypeBuffer.length;++i)
        {
            if(StringUtil.isEmpty(TypeBuffer[i].toString()))//每个下标对应图书类别的主键,如果那个主键下没有记录,跳过
            {
                continue;
            }
            else
            {
                dataset.setValue(TypeBuffer[i].toString(),number[i]);//数据集来自图书种类名称和相应种类的借阅本数
            }
        }
        return dataset;
  }
    public ChartPanel getChartPanel(){
        return frame1;        
    }
}

其中TypeBuffer和number获得方式就是扫描借阅记录的表格,将每条记录图书类别的主键作为这两个数组的下标,++即可:

/**
 * 借阅分布统计
 */
private void HisBorrowPieChart(StringBuffer[] TypeBuffer,int[] number)
{
    Connection con=null;
    try {
        con=dbUtil.getCon();
        Arrays.fill(number,0);//初始将所有类别本数置0
        for(int i=0;i<TypeBuffer.length;++i)
        {
             TypeBuffer[i]=new StringBuffer();//切记StringBuffer需要分配空间!这是与String最大不同
        }
        if(StringUtil.isEmpty(PresentUser))
        {
            Dialogutil attention=new Dialogutil(null,"Attention!","用户信息获取失败!");
            return;
        }
        else            
        {
            //找到当前书和用户
            User user=new User(PresentUser);
            ResultSet Hisbo=borrowDao.HisBorrowDistri(con,user);//获取所有记录,由用户ID查找
            while( Hisbo.next()){
                int index=Hisbo.getInt("bt.id");//主键作为数组下标
                if(StringUtil.isEmpty(TypeBuffer[index].toString()))
                {                    TypeBuffer[index].append(Hisbo.getString("bt.bookTypeName"));
                }
                number[index]++;                
            }
        }        
    } catch (Exception e) {
        Dialogutil attention=new Dialogutil(null,"Attention!","用户信息获取失败!");
        e.printStackTrace();
    }    
}

调用方式为:

HisBorrowPieChart(TypeBuffer,TypeNum);//更新数据集
PieChartJP.add(new PieChart(PieDi,TypeBuffer,TypeNum).getChartPanel());//添加饼状图 ,画在一个Jpanel容器中

二、折线图

public class TimeSeriesChart 
{
    ChartPanel frame1;
/**
     * 折线图构造函数
     * @param v 折线图大小
     * @param BookMonthly 记录每个月本数,下标与月对应
     * @param CurrentYear  记录当前年份
     */
    public TimeSeriesChart(Dimension v,int []BookMonthly,int CurrentYear)
{
        XYDataset xydataset = createDataset(BookMonthly,CurrentYear);
        JFreeChart jfreechart = ChartFactory.createTimeSeriesChart("借阅趋势",//标题
                                                 "月份", //横坐标
                                                 "数量",//纵坐标
                                                  xydataset,//数据集
                                                   true,//有图例
                                                  true,//有工具集
                                                    true//统一资源定位图
                                                     );
        XYPlot xyplot = (XYPlot) jfreechart.getPlot();  // 获取绘图区对象
        DateAxis dateaxis = (DateAxis) xyplot.getDomainAxis();
        DecimalFormat df = new DecimalFormat("#0");//整数
        //y轴用整数表示
        ((NumberAxis) ((XYPlot)jfreechart.getPlot()).getRangeAxis()).setNumberFormatOverride(df);
        
        dateaxis.setDateFormatOverride(new SimpleDateFormat("MMM"));//横轴格式-yyyy
        
        frame1=new ChartPanel(jfreechart,true);
        frame1.setPreferredSize(new Dimension(v));//设置大小
        
        dateaxis.setLabelFont(new Font("黑体",Font.BOLD,30));         //水平底部标题
        dateaxis.setTickLabelFont(new Font("宋体",Font.BOLD,30));  //垂直标题
       // axis0.setLabelFont(new Font("黑体", Font.PLAIN, 12));// y轴字体
        ValueAxis rangeAxis=xyplot.getRangeAxis();//获取柱状
        rangeAxis.setLabelFont(new Font("黑体",Font.BOLD,35));
        jfreechart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 30));
        //设定y在轴显示范围
       // NumberAxis domainAxis = (NumberAxis)xyplot.getDomainAxis();
        //纵轴从0开始
        //((NumberAxis)rangeAxis).setAutoRangeIncludesZero(true); 
        rangeAxis.setLowerBound(0);
        //找最大值
         int max = BookMonthly[0];//定义变量
            for (int x=1; x<BookMonthly.length; x++ )
            {
                if (BookMonthly[x]>max)
                {
                    max = BookMonthly[x];
                }
            }       
        rangeAxis.setUpperBound(max+1);//显示最大设为记录中最大值+1
     // 设置y轴不是使用自动刻度
        ((NumberAxis)rangeAxis).setAutoTickUnitSelection(false);
        // 设置刻度
        NumberTickUnit numberTickUnit = new NumberTickUnit(1);
        ((NumberAxis)rangeAxis).setTickUnit(numberTickUnit);
        jfreechart.getTitle().setFont(new Font("宋体",Font.BOLD,35));//设置标题字体

    } 
     private static XYDataset createDataset(int []BookMonthly,int CurrentYear) 
     {  //这个数据集有点多,但都不难理解
            TimeSeries timeseries = new TimeSeries(Integer.toString(CurrentYear)+"各月借阅数量",
                    org.jfree.data.time.Month.class);//时间轴精确到月
            timeseries.add(new Month(1,CurrentYear), BookMonthly[1]);//设置每个月数量
            timeseries.add(new Month(2,CurrentYear), BookMonthly[2]);
            timeseries.add(new Month(3,CurrentYear), BookMonthly[3]);
            timeseries.add(new Month(4,CurrentYear), BookMonthly[4]);
            timeseries.add(new Month(5,CurrentYear), BookMonthly[5]);
            timeseries.add(new Month(6,CurrentYear), BookMonthly[6]);
            timeseries.add(new Month(7,CurrentYear), BookMonthly[7]);
            timeseries.add(new Month(8,CurrentYear), BookMonthly[8]);
            timeseries.add(new Month(9,CurrentYear), BookMonthly[9]);
            timeseries.add(new Month(10,CurrentYear), BookMonthly[10]);
            timeseries.add(new Month(11,CurrentYear), BookMonthly[11]);
            timeseries.add(new Month(12,CurrentYear), BookMonthly[12]);            
            TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
            timeseriescollection.addSeries(timeseries);
            return timeseriescollection;
        }
      public ChartPanel getChartPanel()
      {
            return frame1;            
        }
}

数组BookMonthly对应值获得同样先连接数据库,扫描借阅表,取出其中的借阅日期,以月作为数组下标++即可:

//找到当前书和用户
            User user=new User(PresentUser);
            //获取当前时间
            java.sql.Date currentDate = new java.sql.Date(System.currentTimeMillis());
            DateInt curdate=new DateInt();
            DateUtil.getdate(currentDate, curdate);
            this.CurrentYear=curdate.getYear();
            ResultSet Hisbo=borrowDao.HisBorrowTrend(con,user);//获取所有记录,由用户ID查找
            while( Hisbo.next())
            {
                DateInt date=new DateInt();                
                DateUtil.getdate(Hisbo.getDate("borTime"), date);                
                if(curdate.getYear()==date.getYear())
                {
                    BookMonthly[date.getMonth()]++;//只统计当前年份
                }
                else
                {
                    continue;
                }
            }

使用折线图方式:

HisBorrowBrokenLine(BookMonthly);//更新数据集
BrokenLineJP.add(new TimeSeriesChart(Linetrend,BookMonthly,CurrentYear).getChartPanel()); //添加折线图  

三、柱状图:

柱状图构造类实现方式:

public class BarChart {
      ChartPanel frame1; 
      
      public BarChart() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * 柱状图构造函数
     * @param TypeBuffer 图书种类名称
     * @param number   图书种类对应数目
     */
    public  BarChart(StringBuffer[] TypeBuffer,int[] number)
      {  
      CategoryDataset dataset = getDataSet(TypeBuffer,number);  
      JFreeChart chart = ChartFactory.createBarChart3D( "各类图书借阅统计", // 图表标题  
                                "图书种类", // 目录轴的显示标签  
                                "数量", // 数值轴的显示标签  
                                dataset, // 数据集  
                                PlotOrientation.VERTICAL, // 图表方向:水平、垂直  
                                true,           // 是否显示图例(对于简单的柱状图必须是false)  
                                false,          // 是否生成工具  
                                false           // 是否生成URL链接  
                                );  
              
         CategoryPlot plot=chart.getCategoryPlot();//获取图表区域对象  
         CategoryAxis domainAxis=plot.getDomainAxis();         //水平底部列表  
         domainAxis.setLabelFont(new Font("黑体",Font.BOLD,30));         //水平底部标题  
         domainAxis.setTickLabelFont(new Font("宋体",Font.BOLD,30));  //垂直标题  
         
         ValueAxis rangeAxis=plot.getRangeAxis();//获取柱状  
         //设置刻度
         NumberTickUnit numberTickUnit = new NumberTickUnit(1);
         ((NumberAxis)rangeAxis).setTickUnit(numberTickUnit);
         //设置柱状图顶部数字
         BarRenderer3D renderer = (BarRenderer3D) plot.getRenderer(); //获得当前数据
         renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator()); //显示每个柱的数值  
         
         renderer.setBaseItemLabelsVisible(true);  
         renderer.setBaseItemLabelPaint(Color.BLACK);  
         renderer.setBaseItemLabelFont(new Font("宋书",Font.PLAIN,30));  
       //注意:此句很关键,若无此句,那数字的显示会被覆盖,给人数字没有显示出来的问题 
         renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition
                 (ItemLabelAnchor.OUTSIDE12,TextAnchor.BASELINE_CENTER ));//表示显示在上方,中间
         //ItemLabelAnchor.OUTSIDE3(显示在垂直方向中间), TextAnchor.BASELINE_RIGHT(显示在柱子右边)
         renderer.setItemLabelAnchorOffset(10D);// 设置柱形图上的文字偏离值 
         rangeAxis.setLabelFont(new Font("黑体",Font.BOLD,15));  
         chart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 30));  
         chart.getTitle().setFont(new Font("宋体",Font.BOLD,30));//设置标题字体                  
         //到这里结束,虽然代码有点多,但只为一个目的,解决汉字乱码问题              
          frame1=new ChartPanel(chart,true);        //这里也可以用chartFrame,可以直接生成一个独立的Frame             
        } 
        
        /**
         * 获取数据
         * @return
         */
       private static CategoryDataset getDataSet(StringBuffer[] TypeBuffer,int[] number) 
       {  
           DefaultCategoryDataset dataset = new DefaultCategoryDataset();  
           for(int i=0;i<TypeBuffer.length;++i)
            {
               if(StringUtil.isEmpty(TypeBuffer[i].toString()))
                {
                    continue;
                }
               else
               {
                   dataset.addValue(number[i],TypeBuffer[i].toString(),TypeBuffer[i].toString());
               }
            }

           return dataset;  
}  
    public ChartPanel getChartPanel()
    {  
        return frame1;  
        
    }  
}

数据集和饼状图一样。但这里显示时候是管理员图书统计按钮下单独开的一个JFrame窗口,与饼状图一起上下排列显示:

public class Statistic extends JFrame {

    private JPanel contentPane;
     //设置跟随分辨率变化窗口
    Toolkit kit = Toolkit.getDefaultToolkit();
    Dimension screenSize = kit.getScreenSize();
    private int screenHeight = (int) screenSize.getHeight();
    private int screenWidth = (int) screenSize.getWidth();
    private double enlargement_x=screenWidth/1920;
    private double enlargement_y=screenHeight/1080;
    private int windowWidth ; //获得窗口宽
    private int windowHeight; //获得窗口高
    /*******************统计变量***************************************/
    final private int typenum=50;//用于存放有多少图书种类
       int []TypeNum=new int[typenum];
    StringBuffer[] TypeBuffer=new StringBuffer[typenum];//记录各类书数量
    int []BookMonthly=new int[13];//统计各月借阅数量,下标与月份对齐
    int CurrentYear;//当前年份,用于折线图数据
    /**************************数据库操作****************************************/
    DbUtil dbUtil=new DbUtil();//数据库连接类
    BorrowDao borrowDao=new BorrowDao();//借阅表类
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    Statistic frame = new Statistic();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public Statistic() 
    {
        setResizable(false);
        setTitle("\u6570\u636E\u7EDF\u8BA1\u56FE");
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setBounds(screenWidth * 2/7, screenHeight / 3, (int)(1400*enlargement_x),(int)(1600*enlargement_y));
        windowWidth = this.getWidth(); //获得窗口宽
        windowHeight = this.getHeight(); //获得窗口高
        this.setLocation(screenWidth / 2 - windowWidth / 2, screenHeight / 2 - windowHeight / 2);//设置窗口居中显示
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new GridLayout(2,1,10,10));
         //Dimension PieDi=new Dimension(50,80);
        HisBorrowPieChart(TypeBuffer,TypeNum);//获得数据
        contentPane.add(new PieChart(TypeBuffer,TypeNum).getChartPanel());           //添加饼状图  
        contentPane.add(new BarChart(TypeBuffer,TypeNum).getChartPanel());//添加柱形图  
        //设置JFrame最大化
        //this.setExtendedState(JFrame.MAXIMIZED_BOTH); 
    }

}

 

推荐阅读