繁体   English   中英

Java/Swing:单击矩形时创建文本字段

[英]Java/Swing: Create text fields upon clicking a rectangle

我正在创建一个应用程序,用户可以在其中上传图像,使用鼠标在图像顶部绘制矩形进行注释,单击每个矩形时,右侧会显示一个空文本字段,如图所示,供用户附加评论到那个特定的区域。 在此处输入图片说明 现在程序将上传图像并让用户在其顶部绘制矩形(实现了上面显示的图像的左侧),但我无法弄清楚如何让程序创建并显示空文本用户第一次单击矩形时的字段(实现所示图像的右侧)。 矩形在选中时也会以红色突出显示,如果评论已经存在,点击后评论应该在文本框中。 我的猜测是我必须在 DrawingArea 类中创建 JTextFields 并以某种方式将它传递给 ImageAnnotator 类? 或者我必须在 DrawingArea 中导入 ImageAnnotator 并直接在那里输入 TextFields? 或者也许有我没有建立的联系。 我也无法在屏幕上显示图像名称,即使我将它传递给 JLabel。 任何帮助表示赞赏。

绘图区.java:

public class DrawingArea extends JPanel
    {
        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);
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            //  Custom code to support painting from the BufferedImage

            if (image != null)
            {
                g.drawImage(image, 0, 0, null);
            }
            
            Color foreground = g.getColor();


            for (Box b : rectangles)
            {
                g.setColor( b.getForeground() );
                Rectangle r = b.getRectangle();
                g.drawRect(r.x, r.y, r.width, r.height);
            }

            //  Paint the Rectangle as the mouse is being dragged

            if (shape != null)
            {
                Graphics2D g2d = (Graphics2D)g;
                g2d.draw( shape );
            }
        }

        public void addRectangle(Rectangle rectangle, Color color)
        {
            //  Draw the Rectangle onto the BufferedImage

            Box b = new Box(color, rectangle);
            rectangles.add( b );
            repaint();
        }

        public void clear()
        {
            rectangles.clear();
            repaint();
        }
        
        public void loadImage() {
            ...
            this.imageName = f.getName(); //this is where I pass the file name
            ...
        }
        
        public static BufferedImage scaleImage(int w, int h, BufferedImage img) throws Exception {...}

        class MyMouseListener extends MouseInputAdapter
        {
            private Point startPoint;

            public void mousePressed(MouseEvent e)
            {
                startPoint = e.getPoint();
                shape = new Rectangle();
            }

            public void mouseDragged(MouseEvent e)
            {
                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.width != 0 || shape.height != 0)
                {
                    addRectangle(shape, e.getComponent().getForeground());
                }

                shape = null;
            }
        }       
    }

ImageAnnotator.java:

public class ImageAnnotator extends JFrame {

    private JPanel contentPane;
    Model model;
    private JLabel ImageName;
    DrawingArea drawingArea;
    ButtonPanel buttonPanel;
    GroupLayout gl_contentPane;
    private JLabel lblNewLabel;
    /**
     * Create the frame.
     */
    public ImageAnnotator(Model m) {
        super();
        this.model = m;
        setTitle("Image Annotator");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 850, 646);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        drawingArea = new DrawingArea();
        
        ImageName = new JLabel(drawingArea.imageName); // here I'm trying to set the filename
        buttonPanel = new ButtonPanel( drawingArea );
        
        lblNewLabel = new JLabel("Comments");
        lblNewLabel.setFont(new Font("Times New Roman", Font.BOLD, 17));
        
        gl_contentPane = new GroupLayout(contentPane);
        gl_contentPane.setHorizontalGroup(
            gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_contentPane.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(drawingArea, GroupLayout.PREFERRED_SIZE, 490, GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(ComponentPlacement.RELATED, 128, Short.MAX_VALUE)
                    .addComponent(lblNewLabel)
                    .addGap(117))
                .addGroup(gl_contentPane.createSequentialGroup()
                    .addGap(121)
                    .addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING)
                        .addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                        .addComponent(ImageName, GroupLayout.PREFERRED_SIZE, 254, GroupLayout.PREFERRED_SIZE))
                    .addContainerGap(451, Short.MAX_VALUE))
        );
        gl_contentPane.setVerticalGroup(
            gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_contentPane.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
                        .addComponent(lblNewLabel)
                        .addGroup(gl_contentPane.createSequentialGroup()
                            .addComponent(drawingArea, GroupLayout.PREFERRED_SIZE, 490, GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(ComponentPlacement.RELATED)
                            .addComponent(ImageName, GroupLayout.PREFERRED_SIZE, 26, GroupLayout.PREFERRED_SIZE)))
                    .addPreferredGap(ComponentPlacement.RELATED)
                    .addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addContainerGap(27, Short.MAX_VALUE))
        );
        contentPane.add(drawingArea);
        contentPane.setLayout(gl_contentPane);
    }

盒子.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 setImageName(String imageName) { bImageName = imageName; }
    public String getImageName() { return bImageName; }
    
    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 Color getForeground()
    {
        return foreground;
    }

    public void setForeground(Color foreground)
    {
        this.foreground = foreground;
    }

    public Rectangle getRectangle()
    {
        return rectangle;
    }
    
}

您可能需要的第一件事是某种侦听器或观察者,可用于在选择Box时通知相关方

public interface BoxSelectionListener extends EventListener {
    public void didSelect(Box box);
}

这将由管理绘图和输入组件的 UI 的父部分实现,当触发时,感兴趣的一方将根据其需要采取适当的行动。

接下来,我们需要为DrawingArea添加一些管理代码来管理监听器支持。 由于 Swing 组件有一些方便的支持,这变得更容易

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

好的,非常简单,您可以添加或删除侦听器并在需要时触发事件。

好的,现在“稍微”更难一点。 当按下和释放鼠标时,您需要决定要做什么,是要选择一个框还是要绘制一个新框。

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

        startPoint = null;
        shape = null;
    }
}

因此,对您的代码进行一些修改。

  1. 在检测到阻力之前,我们不会创建新的shape ,这为我们的决策过程提供了一些回旋余地。
  2. 如果用户“点击”了组件,我们扫描可用的形状并确定用户是否点击了一个,如果一个被点击,我们调用didSelect

我们为什么要做这个? 这样做的主要原因是它允许用于检测某人何时创建重叠矩形(或多或少),但幸运的是他们不会这样做,因为它使选择变得非常困难。

didSelect方法是一个简单的机会,可以处理您想要“选择”特定框时需要做的所有事情。 这将功能解耦,并允许您决定何时调用它

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
    
    fireBoxSelected(box);
}

你可以用,当你点击一个广场去,你既可以,捕获鼠标的位置,并做一些数学和构建jpanel用一种无形的jtextbox ,或做同样的事情,但产卵时,提请箱面板。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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