簡體   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