2015-04-05 53 views
0

所以我正在研究观察员模式分配。我有2个窗口,每个窗口有4个字段。在一个窗口中,您可以将双值输入到4个不同的文本框中,并且它们会反映在条形图中的4个对应条之一中。观察者模式更新文本字段和条形图

我也可以通过按下鼠标按钮来更改条形图中的条形图,并将其移动到指针所在的位置。现在,我想要更新文本字段,但我不知道如何执行此操作。它似乎得到一个通知,说有变化,但我不知道如何在现场设置适当的文本。酒吧框架重新绘制。我是否也为文本框架执行此操作?

这里是我的3分相关的类代码至今:

BarFrame

import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.geom.*; 

import javax.swing.*; 
import javax.swing.event.*; 

import java.util.*; 

/** 
    A class that implements an Observer object that displays a barchart view of 
    a data model. 
*/ 
public class BarFrame extends JFrame implements ChangeListener, MouseListener 
{ 

     private ArrayList<Double> a; 
     private DataModel dataModel; 

     private static final int ICON_WIDTH = 200; 
     private static final int ICON_HEIGHT = 200; 
    /** 
     Constructs a BarFrame object 
     @param dataModel the data that is displayed in the barchart 
    */ 
    public BarFrame(DataModel dataModel) 
    { 
     this.dataModel = dataModel; 
     a = dataModel.getData(); 

     setLocation(0,200); 
     setLayout(new BorderLayout()); 

     addMouseListener(this); // adds the mouse listener in to the bar frame 

     Icon barIcon = new Icon() 

     { 
     public int getIconWidth() { return ICON_WIDTH; } 
     public int getIconHeight() { return ICON_HEIGHT; } 

     public void paintIcon(Component c, Graphics g, int x, int y) 
     { 
      Graphics2D g2 = (Graphics2D) g; 

      g2.setColor(Color.red); 

      double max = (a.get(0)).doubleValue(); 

      for (Double v : a) 
      { 
       double val = v.doubleValue(); 
       if (val > max) 
        max = val; 
      } 
      double barHeight = getIconHeight()/a.size(); 

      int i = 0; 
      for (Double v : a) 
      { 
       double value = v.doubleValue(); 

       double barLength = getIconWidth() * value/max; 
       Rectangle2D.Double rectangle = new Rectangle2D.Double 
        (0, barHeight * i, barLength, barHeight); 
       i++; 
       g2.fill(rectangle); 
      } 
     } 
     }; 

     add(new JLabel(barIcon)); 

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     setVisible(true); 
    } 

    /** 
     Called when the data in the model is changed. 
     @param e the event representing the change 
    */ 
    public void stateChanged(ChangeEvent e) 
    { 
     a = dataModel.getData(); 
//  for(Double d: a){ 
//  System.out.println(d); 
//  } 
     repaint(); 
    } 


@Override 
public void mouseClicked(MouseEvent e) { 
    // TODO Auto-generated method stub 

} 

@Override 
public void mousePressed(MouseEvent e) { 
    // TODO Auto-generated method stub 

    double max = Collections.max(dataModel.getData()); 
    double value = (double)e.getX()/(double)getWidth()* max; 

    if(30 <= e.getY() && e.getY() < 80){ 
     //first bar 
     dataModel.update(0, value); 
    } 

    if(80 <= e.getY() && e.getY() < 130){ 
     //second bar 
     dataModel.update(1, value); 
    } 

    if(130 <= e.getY() && e.getY() < 180){ 
     //third bar 
     dataModel.update(2, value); 
    } 

    if(180 <= e.getY() && e.getY() < 230){ 
     //fourth bar 
     dataModel.update(3, value); 
    } 
} 

@Override 
public void mouseReleased(MouseEvent e) { 
    // TODO Auto-generated method stub 

} 

@Override 
public void mouseEntered(MouseEvent e) { 
    // TODO Auto-generated method stub 

} 

@Override 
public void mouseExited(MouseEvent e) { 
    // TODO Auto-generated method stub 

} 

} 

的DataModel

import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.util.ArrayList; 

import javax.swing.event.*; 

/** 
    A Subject class for the observer pattern. 
*/ 
public class DataModel 
{ 
     ArrayList<Double> data; 
     ArrayList<ChangeListener> listeners; 

    /** 
     Constructs a DataModel object 
     @param d the data to model 
    */ 
    public DataModel(ArrayList<Double> d) 
    { 
     data = d; 
     listeners = new ArrayList<ChangeListener>(); 

    } 

    /** 
     Constructs a DataModel object 
     @return the data in an ArrayList 
    */ 
    @SuppressWarnings("unchecked") 
public ArrayList<Double> getData() 
    { 
     return (ArrayList<Double>) (data.clone()); 
    } 

    /** 
     Attach a listener to the Model 
     @param c the listener 
    */ 
    public void attach(ChangeListener c) 
    { 
     listeners.add(c); 
    } 

    /** 
     Change the data in the model at a particular location 
     @param location the index of the field to change 
     @param value the new value 
    */ 
    public void update(int location, double value) 
    { 
     data.set(location, new Double(value)); 
    // frame.fieldList[location].setText(Double.toString(value)); 
     for (ChangeListener l : listeners) 
     { 
//  System.out.println("l = " + l); 
     l.stateChanged(new ChangeEvent(this)); 
     } 

    } 

} 

TextFrame

import java.awt.*; 
import java.awt.event.*; 

import javax.swing.*; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

import java.util.ArrayList; 

/** 
    A class for displaying the model as a column of textfields in a frame. 
*/ 
public class TextFrame extends JFrame implements ChangeListener 
{ 

     DataModel dataModel; 
     JTextField[] fieldList; 
     private ArrayList<Double> a; 
    /** 
     Constructs a JFrame that contains the textfields containing the data 
     in the model. 
     @param d the model to display 
    */ 
    public TextFrame(DataModel d) 
    { 
     dataModel = d; 

     final Container contentPane = this.getContentPane(); 
     setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 

     ArrayList<Double> a = dataModel.getData(); 
     fieldList = new JTextField[a.size()]; 

     // A listener for action events in the text fields 
     ActionListener l = new ActionListener() 
     { 
     public void actionPerformed(ActionEvent e) 
     { 
      // Figure out which field generated the event 
      JTextField c = (JTextField) e.getSource(); 
      int i = 0; 
      int count = fieldList.length; 
      while (i < count && fieldList[i] != c) 
       i++; 

      String text = c.getText().trim(); 

      try 
      { 
       double value = Double.parseDouble(text); 
       dataModel.update(i, value); 
      } 
      catch (Exception exc) 
      { 
       c.setText("Error. No update"); 
      } 
     } 
     }; 

     final int FIELD_WIDTH = 11; 
     for (int i = 0; i < a.size(); i++) 
     { 
     JTextField textField = new JTextField(a.get(i).toString(),FIELD_WIDTH); 
     textField.addActionListener(l); 
     add(textField); 
     fieldList[i] = textField; 
     } 

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     setVisible(true); 
    } 


    /** 
    Called when the data in the model is changed. 
    @param e the event representing the change 
*/ 
public void stateChanged(ChangeEvent e) 
{ 
    a = dataModel.getData(); 
// for(Double d: a){ 
// System.out.println(d); 
// } 

} 


} 

一对夫妇的注意事项: 我知道,如果用最大值更改了栏的值(其他栏移动),那么它就很有问题了。随着我应该延续的代码出现了。我猜是这样,以便它可以用作参考点。 我知道我可以通过使用适配器摆脱不必要的鼠标侦听器,但是我的指令声明将它们实现为空。

奖金的问题,如果有人觉得回答:有没有办法让我的鼠标按下实际双精度?它总是返回一个整数。

无论如何,对不起,很长的职位。提前谢谢你的帮助!

回答

1

想通了! 我在TextFrame的stateChanged方法中添加了以下内容:

for(int i = 0; i < a.size(); i++){ 
     fieldList[i].setText(Double.toString(Math.round(a.get(i) * 10)/10.0)); // to get 1 decimal place accuracy 
    }