简体   繁体   中英

Java/Swing: How to pass properties from Boundary to Model and vice versa

I'm building an app where user can upload an image and draw rectangles on top of it for annotation and also attach comments to that certain region/rectangle, like in Word or Docs. I'm a bit confused on how to make the connection between the classes to pass information around. Once user draws a rectangle and clicks on it, they will be able to write comments in the JTextField provided, and the program will associate that rectangle with that comment. I have three classes Box , DrawingArea , and ImageAnnotator . One of the fields/properties of Box (which is the rectangle) is bComment , and inside the ImageAnnotator class I have a JButton which upon click, will need to set the String retrieved from the JTextField in the ImageAnnotator class to Box.bComment . I know the onClick method should be inside the ImageAnnotator class since that's where the button is but I'm a bit confused to how to pass this String over to Box . Should I import Box inside the ImageAnnotator and set it within an onClick method? So now the reverse way, upon clicking the rectangle, how do I set the JTextField in ImageAnnotator with the String retrieved from Box.bComment , that is, when the user clicks on the same rectangle again, the program will display the previously added comment in the text field. All the listeners for clicking on rectangle is inside the DrawingArea class so I would need to somehow get the Text field from ImageAnnotator and fill the text field with String retrieved from Box.bComment . For more clarity, I have provided the classes below.

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;
            }
        }
        
    }

I was able to get those working by making some fields static (the TextField) so that I can reference it from another class, and my mistake was that I was creating instances of the ImageAnnotator class in my DrawingArea class so when I try to reference the TextField from ImageAnnotator inside DrawingArea, it was null. So my solution was instead I called ImageAnnotator directly without creating an instance and I set the TextField to static.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM