2015-07-19 3 views
1

Я создал графический компонент, который позволяет вам просматривать изображение и позволяет сделать выбор части изображения: выбор части изображения выполняется путем рисования прямоугольника на этом изображении (с помощью кнопок перетаскивания и -drop).Как запустить пользовательское событие при рисовании нового прямоугольника?

С этой целью я использовал this example, который создал подкласс JLabel, чтобы нарисовать изображение и для того, чтобы разобраться с рисунком прямоугольника. Затем я помещаю экземпляр этого подкласса в пределах JPanel, чтобы изображение всегда располагалось в центре панели.

FigurePanel.java

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.GridBagLayout; 
import java.awt.Image; 
import java.awt.Rectangle; 
import java.awt.event.MouseEvent; 
import javax.swing.ImageIcon; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.event.MouseInputAdapter; 


public class FigurePanel extends JPanel 
{ 
    private SelectionLabel imageLabel = null; 


    public FigurePanel() 
    { 
     this.setLayout(new GridBagLayout()); 

     imageLabel = new SelectionLabel(); 
     this.add(imageLabel, null); 
    } 

    public void setImage(Image image) 
    { 
     imageLabel.setImage(image); 
    } 

    private class SelectionLabel extends JLabel 
    { 
     private Rectangle currentRect = null; 
     private Rectangle rectToDraw = null; 
     private final Rectangle previousRectDrawn = new Rectangle(); 


     public SelectionLabel() 
     { 
      super(); 
      setOpaque(true); 

      SelectionListener listener = new SelectionListener(); 
      addMouseListener(listener); 
      addMouseMotionListener(listener); 
     } 


     public void setImage(Image image) 
     { 
      currentRect = null; 
      rectToDraw = null; 
      previousRectDrawn.setBounds(0, 0, 0, 0); 

      setIcon(new ImageIcon(image)); 
     } 

     private class SelectionListener extends MouseInputAdapter 
     { 
      @Override 
      public void mousePressed(MouseEvent e) 
      { 
       int x = e.getX(); 
       int y = e.getY(); 
       currentRect = new Rectangle(x, y, 0, 0); 
       updateDrawableRect(getWidth(), getHeight()); 
       repaint(); 
      } 

      @Override 
      public void mouseDragged(MouseEvent e) 
      { 
       updateSize(e); 
      } 

      @Override 
      public void mouseReleased(MouseEvent e) 
      { 
       updateSize(e); 
      } 

      /* 
      * Update the size of the current rectangle 
      * and call repaint. Because currentRect 
      * always has the same origin, translate it 
      * if the width or height is negative. 
      * 
      * For efficiency (though 
      * that isn't an issue for this program), 
      * specify the painting region using arguments 
      * to the repaint() call. 
      * 
      */ 
      void updateSize(MouseEvent e) 
      { 
       int x = e.getX(); 
       int y = e.getY(); 
       currentRect.setSize(x - currentRect.x, 
            y - currentRect.y); 
       updateDrawableRect(getWidth(), getHeight()); 
       Rectangle totalRepaint = rectToDraw.union(previousRectDrawn); 
       repaint(totalRepaint.x, totalRepaint.y, 
         totalRepaint.width, totalRepaint.height); 
      } 
     } 

     @Override 
     protected void paintComponent(Graphics g) 
     { 
      super.paintComponent(g); //paints the background and image 

      //If currentRect exists, paint a box on top. 
      if (currentRect != null) { 
       //Draw a rectangle on top of the image. 
       g.setXORMode(Color.white); //Color of line varies 
              //depending on image colors 
       g.drawRect(rectToDraw.x, rectToDraw.y, 
          rectToDraw.width - 1, rectToDraw.height - 1); 

       System.out.println("rectToDraw: " + rectToDraw); 
      } 
     } 

     private void updateDrawableRect(int compWidth, int compHeight) 
     { 
      int x = currentRect.x; 
      int y = currentRect.y; 
      int width = currentRect.width; 
      int height = currentRect.height; 

      //Make the width and height positive, if necessary. 
      if (width < 0) { 
       width = 0 - width; 
       x = x - width + 1; 
       if (x < 0) { 
        width += x; 
        x = 0; 
       } 
      } 
      if (height < 0) { 
       height = 0 - height; 
       y = y - height + 1; 
       if (y < 0) { 
        height += y; 
        y = 0; 
       } 
      } 

      //The rectangle shouldn't extend past the drawing area. 
      if ((x + width) > compWidth) { 
       width = compWidth - x; 
      } 
      if ((y + height) > compHeight) { 
       height = compHeight - y; 
      } 

      //Update rectToDraw after saving old value. 
      if (rectToDraw != null) { 
       previousRectDrawn.setBounds(
          rectToDraw.x, rectToDraw.y, 
          rectToDraw.width, rectToDraw.height); 
       rectToDraw.setBounds(x, y, width, height); 
      } else { 
       rectToDraw = new Rectangle(x, y, width, height); 
      } 
     } 
    } 

} 

FigurePanelTest.java

import java.awt.BorderLayout; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.Image; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.JButton; 
import javax.swing.JFileChooser; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 


public class FigurePanelTest extends JFrame 
{ 
    public FigurePanelTest() 
    { 
     FigurePanel imagePanel = new FigurePanel(); 

     JScrollPane imageScrollPane = new JScrollPane(); 
     imageScrollPane.setPreferredSize(new Dimension(420, 250)); 
     imageScrollPane.setViewportView(imagePanel); 

     JButton imageButton = new JButton("Load Image"); 
     imageButton.addActionListener(
       new ActionListener() 
       { 
        @Override 
        public void actionPerformed(ActionEvent evt) 
        { 
         JFileChooser fc = new JFileChooser(); 
         int returnValue = fc.showOpenDialog(null); 
         if (returnValue == JFileChooser.APPROVE_OPTION) { 
          File selectedFile = fc.getSelectedFile(); 
          System.out.println(selectedFile.getName()); 

          try 
          { 
           Image image = ImageIO.read(selectedFile.getAbsoluteFile()); 
           imagePanel.setImage(image); 

           imageScrollPane.getViewport().setViewPosition(new Point(0, 0)); 
          } 
          catch(IOException e) 
          { 
           e.printStackTrace(); 
          } 
         } 
        } 
       } 
     ); 

     Container container = getContentPane(); 
     container.setLayout(new BorderLayout()); 
     container.add(imageScrollPane, BorderLayout.CENTER); 
     container.add(imageButton, BorderLayout.NORTH); 

     setSize(600, 400); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 


    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String args[]) { 
     /* Create and display the form */ 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new FigurePanelTest().setVisible(true); 
      } 
     }); 
    } 

} 

Частный класс SelectionLabel класс SelectionArea от this example.

Когда нарисован новый прямоугольник, на консоли отображается сообщение. Теперь я бы заменил печать сообщения на увольнение пользовательского события, чтобы позиция и размер прямоугольника были доступны для бизнес-логики приложения.

Я прочитал как create a custom event in Java. Кроме того, this article идентифицирует два супер-типа для создания событий: EventObject и AWTEvent. В данной статье говорится:

Обычно вы расширяете AWTEvent для событий, генерируемых графическим компонента и EventObject любого другого времени.

Поскольку событие в отношении выбора части изображения генерируется графическим компонентом (то есть FigurePanel панель), я мог бы реализовать ImageSelectionEvent класс путем расширения AWTEvent, как следующий фрагмент кода.

public class ImageSelectionEvent extends AWTEvent 
{ 

    public ImageSelectionEvent(Object source, int id) { 
     super(source, id); 
    } 

} 

В документации указывается id as the event type. Итак, какое значение должно быть присвоено этому параметру?

Кроме того, почему конструктор класса EventObject лишен параметра id?

При создании класса событий вы должны гарантировать неизменность события . Генератор событий будет совместно использовать один и тот же случай событий среди слушателей; поэтому убедитесь, что какой-либо один слушатель не может изменить состояние события .

Как насчет этого?

+1

Существует общая разница между AWTEvent и EventObject, AWTEvent обычно описывает системные или основные события, которые предопределены в API, и вместо использования чего-то типа «instanceof» идентифицируются идентификатором ID. EventObject, с другой стороны, используется для создания более общих или настраиваемых событий. Обычно я начинаю. Затем я определяю интерфейс прослушивателя, чтобы использовать его, который реализует EventListener – MadProgrammer

ответ

2

Я не знаю, что необходимо для создания пользовательского события.

Однако, поскольку вы распространяете JLabel, возможно, вы можете просто создать PropertyChangeEvent.

Чтобы сгенерировано событие вы бы просто использовать что-то вроде:

firePropertyChange("selectionRectangle", oldRectangle, newRectangle); 

Затем вы можете использовать PropertyChangeListener для прослушивания изменений «selectionRectangle».

1

The Javadoc for AWTEvent говорит:

Подклассов этого корневого класса AWTEvent, определенный вне пакета java.awt.event следует определить идентификатор события значения больше, чем значение, определенное RESERVED_ID_MAX.

This value is 1999. Вы можете настроить его на все, что хотите, и выше. Это значение определяется всеми различными типами событий Swing, а Swing использует значения, которые меньше этого. Например, типы событий MouseEvent используют значения от 500-507.

Главное - использовать согласованное значение для ваших событий.

Наконец, я хотел бы рассмотреть подклассы ComponentEvent над AWTEvent как источником Вашего мероприятия является Component, не Object.

 Смежные вопросы

  • Нет связанных вопросов^_^