【问题标题】:Java/Swing: How to pass properties from Boundary to Model and vice versaJava/Swing:如何将属性从边界传递到模型,反之亦然
【发布时间】:2020-09-29 07:27:25
【问题描述】:

我正在构建一个应用程序,用户可以在其中上传图像并在其上绘制矩形以进行注释,并将 cmets 附加到该特定区域/矩形,例如在 Word 或 Docs 中。我对如何在类之间建立联系以传递信息有点困惑。一旦用户绘制了一个矩形并单击它,他们将能够在提供的 JTextField 中编写 cmets,并且程序会将那个矩形与该注释相关联。我有三个班级BoxDrawingAreaImageAnnotator。 Box(矩形)的字段/属性之一是bComment,在ImageAnnotator 类中我有一个JButton,单击它时,需要设置从ImageAnnotator 类中的JTextField 检索的字符串到Box.bComment。我知道 onClick 方法应该在ImageAnnotator 类中,因为那是按钮所在的位置,但我对如何将此字符串传递给Box 有点困惑。我应该在ImageAnnotator 中导入Box 并将其设置在onClick 方法中吗?那么现在反过来,在点击矩形时,我如何设置ImageAnnotator中的JTextField和从Box.bComment检索的String,即当用户再次点击同一个矩形时,程序将显示之前添加的在文本字段中发表评论。单击矩形的所有侦听器都在DrawingArea 类内,因此我需要以某种方式从ImageAnnotator 获取文本字段,并用从Box.bComment 检索的字符串填充文本字段。为了更清楚起见,我提供了以下类。

ImageAnnotator.java:

public class ImageAnnotator extends JFrame {

    private JPanel contentPane;
    Model model;
    DrawingArea drawingArea;
    GroupLayout gl_contentPane;
    private JTextField textField;
    private JButton btnNewButton;
    /**
     * Create the frame.
     */
    public ImageAnnotator(Model m) {
        super();
        this.model = m;
        setTitle("Image Annotator");
        ...
        setContentPane(contentPane);
        drawingArea = new DrawingArea();
        
        //ImageName = new JLabel(drawingArea.imageName);
        buttonPanel = new ButtonPanel( drawingArea );
        
        textField = new JTextField(); // this is the text field which will be later set to Box.bComment
        
        btnNewButton = new JButton("Add this comment");//this is the button which needs onClick listener
        
        gl_contentPane = new GroupLayout(contentPane);
        gl_contentPane.setHorizontalGroup(...);
        gl_contentPane.setVerticalGroup(...);
        contentPane.add(drawingArea);
        contentPane.setLayout(gl_contentPane);
    }
    
    // onClick listener should be here for JButton
}

Box.java:

public class Box {
    int bWidth, bHeight, bX, bY;
    String bImageName, bComment;
    
    Color foreground;
    Rectangle rectangle;
    
    public Box(int width, int height) {
        bWidth = width;
        bHeight = height;
    }
    
    public Box(Color foreground, Rectangle rectangle) {
        this.foreground = foreground;
        this.rectangle = rectangle;
    }
    
    public void setComment(String comment) { bComment = comment; }
    public String getComment() { return bComment; }
    
    public void setX(int x) { bX = x; }
    public int getX() { return bX; }
    
    public void setY(int y) { bY = y; }
    public int getY() { return bY; }
   
    public Rectangle getRectangle()
    {
        return rectangle;
    }
}

DrawingArea.java:

public class DrawingArea extends JPanel implements BoxSelectionListener
    {
        private final static int AREA_SIZE = 490;
        private BufferedImage image =
            new BufferedImage(AREA_SIZE, AREA_SIZE, BufferedImage.TYPE_INT_ARGB);
        private Rectangle shape;
        private ArrayList<Box> rectangles = new ArrayList<Box>();
        //public String imageName = ""; // this will store the image/file name

        public DrawingArea()
        {
            setBackground(Color.WHITE);
            MyMouseListener ml = new MyMouseListener();
            addMouseListener(ml);
            addMouseMotionListener(ml);
        }
        
        public void addBoxSelectionListener(BoxSelectionListener listener) {
            listenerList.add(BoxSelectionListener.class, listener);
        }

        public void removeBoxSelectionListener(BoxSelectionListener listener) {
            listenerList.remove(BoxSelectionListener.class, listener);
        }
            
        protected void fireBoxSelected(Box box) {
            BoxSelectionListener[] listeners = listenerList.getListeners(BoxSelectionListener.class);
            // Normally, I'd create a event object, which would wrap the source (this) and
            // the Box together, but if there are no listeners, it's a bit of
            // a waste to do so, so I return early in those cases
            if (listeners.length == 0) {
                return;
            }
            for (BoxSelectionListener listener : listeners) {
                listener.didSelect(box);
            }
        }

        public void didSelect(Box box) {
            // Probably assign this to a "assigned" or "selected" property
            // so it can painted differently
            // And now we want to notify some kind of listener so that
            // it can update the UI as required
            box.setForeground(Color.red);
            box.getComment();
            repaint();
            fireBoxSelected(box);
        }
        
        class MyMouseListener extends MouseInputAdapter
        {
            private Point startPoint;

            public void mousePressed(MouseEvent e) {
                // Mark the clip point
                startPoint = e.getPoint();
            }

            public void mouseDragged(MouseEvent e) {
                // Only create the shape when dragging starts
                if (shape == null) {
                    shape = new Rectangle();
                }
                int x = Math.min(startPoint.x, e.getX());
                int y = Math.min(startPoint.y, e.getY());
                int width = Math.abs(startPoint.x - e.getX());
                int height = Math.abs(startPoint.y - e.getY());

                shape.setBounds(x, y, width, height);
                repaint();
            }

            public void mouseReleased(MouseEvent e) {
                if (shape != null) {
                    if (shape.width != 0 || shape.height != 0) {
                        addRectangle(shape, e.getComponent().getForeground());
                    }
                } else {
                    for (Box b : rectangles) {
                        if (b.getRectangle().contains(e.getPoint())) {
                            didSelect(b);
                            break;
                        }
                        else 
                            b.setForeground(Color.black);
                    }
                }

                startPoint = null;
                shape = null;
            }
        }
        
    }

【问题讨论】:

  • 您真的,真的,需要一些时间来了解MVC 是什么,因为这是您的问题/问题的基础。我还建议熟悉 observer pattern,在 Swing 中,它表示为“听众”
  • 1) 正如我在最后几个问题中建议的那样,所有属性都属于一个类。您创建了一个新的“球”对象,因此您需要矩形、颜色和注释作为该类的属性。然后,“球”类将成为您自定义绘画的基础。您已经拥有动态创建 Ball 实例的逻辑。 2)要向 Ball 类添加评论,我会使用双击。我不喜欢单击具有多种功能的想法。所以双击我会显示一个 JOptionPane 来提示输入“评论”。
  • 因此,当您双击矩形时,您会找到相关的“球”对象。然后在 JOptionPane 中显示“注释”。这将允许您添加/更改评论。所以基本上所有的逻辑都是“DrawingArea”中的容器。

标签: java swing


【解决方案1】:

我可以通过将一些字段设为静态(TextField)来使它们工作,以便我可以从另一个类中引用它,我的错误是我在我的 DrawingArea 类中创建 ImageAnnotator 类的实例,所以当我尝试要从 DrawingArea 内的 ImageAnnotator 引用 TextField,它为空。所以我的解决方案是直接调用 ImageAnnotator 而不创建实例,并将 TextField 设置为静态。

【讨论】:

  • 您不应该使用静态字段。这不是 static 关键字的用途。您是否需要在另一个类中引用一个类,然后您需要向该类传递一个参数并添加getter/setter方法。
猜你喜欢
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 2011-03-22
  • 2010-09-29
  • 2018-06-20
  • 2010-12-27
  • 1970-01-01
相关资源
最近更新 更多