2013-08-02 2 views
2

В главе 15 из программирования Ляна (7-е изд.) он представляет программу для создания (2-D) шара на JPanel и увеличьте его, нажав кнопки увеличения/уменьшения. Я изменил программу так, чтобы она также 1) увеличивала/уменьшала мяч, если пользователь нажимает/выбирает + клики, 2) позволяет выбрать цвет мяча, нажав кнопку, и 3) позволяет перемещать кругом, перетащив его мышью.Есть ли лучший способ установить начальную позицию для JPanel?)

Последняя модификация - это то, что вызывало у меня проблемы какое-то время, потому что я хотел центрировать мяч в начале, но затем разрешить пользователю перемещать мяч с помощью мыши. Решение, с которым я столкнулся, заключалось в том, чтобы метод paintComponent устанавливал только x- и y-координаты шара относительно getWidth() и getHeight() при его первом рисовании. Для этого я добавил переменную paintCount в класс BallCanvas и сделал оператор if, чтобы он выполнял только первый раз. Когда я пытался выяснить, как это сделать вначале, я увидел другие решения, такие как приведенные здесь: Why can't I access my panel's getWidth() and getHeight() functions?, но я считаю, что решение намного проще.

Итак, вопрос в том, что я считал плохой стиль кодирования? Будет ли профессиональный программист издеваться над этим решением? Или все в порядке?

Что еще более важно, есть ли лучший (но также и относительно простой) способ сделать это, не связанный с настройкой счетчика?

Вот соответствующие биты кода:

начала BallCanvas:

public static class BallCanvas extends JPanel { 

    private int radius = 20; 
    private Color color = Color.BLACK; 
    private int ballX; 
    private int ballY; 
    private int paintCount = 0; 

    ... 

Метод шаг (который реагирует на событие MouseDragged):

public void move(MouseEvent e){ 

     ballX = e.getX() - radius; 
     ballY = e.getY() - radius; 
     repaint(); 

} 

paintComponent метод:

protected void paintComponent(Graphics g){ 

     super.paintComponent(g); 
     g.setColor(color); 
     if(paintCount < 1){ 
      ballX = getWidth()/2 - radius; 
      ballY = getHeight()/2 - radius; 
     } 
     g.fillOval(ballX, ballY, 2*radius, 2*radius); 
     paintCount++; 

} 

Полная программа:

// Reference: Liang's Intro to Java Programming 

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 

public class ControlBall extends JFrame{ 

    private JButton jbtRed = new JButton("Red"); 
    private JButton jbtGreen = new JButton("Green"); 
    private JButton jbtBlue = new JButton("Blue"); 
    private JButton jbtBlack = new JButton("Black"); 
    private BallCanvas canvas = new BallCanvas(); 
    private JMenuBar menuBar = new JMenuBar(); 
    private JMenu menu = new JMenu("Edit"); 
    private JMenuItem miEnlarge = new JMenuItem("Enlarge"); 
    private JMenuItem miShrink = new JMenuItem("Shrink"); 

    public ControlBall(){ 

     menuBar.add(menu); 
     menu.add(miEnlarge); 
     menu.add(miShrink); 

     JPanel panel = new JPanel(); 
     panel.add(jbtRed); 
     panel.add(jbtGreen); 
     panel.add(jbtBlue); 
     panel.add(jbtBlack); 

     this.add(canvas, BorderLayout.CENTER); 
     this.add(panel, BorderLayout.SOUTH); 
     this.add(menuBar, BorderLayout.NORTH); 

     jbtRed.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e){ 
       canvas.setColor(Color.RED); 
      } 
     }); 

     jbtGreen.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e){ 
       canvas.setColor(Color.GREEN); 
      } 
     }); 

     jbtBlue.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e){ 
       canvas.setColor(Color.BLUE); 
      } 
     }); 

     jbtBlack.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e){ 
       canvas.setColor(Color.BLACK); 
      } 
     }); 

     miEnlarge.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e){ 
       canvas.enlarge(); 
      } 
     }); 

     miShrink.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e){ 
       canvas.shrink(); 
      } 
     }); 

     canvas.addMouseListener(new MouseListener() { 
      public void mouseClicked(MouseEvent e){ 
       canvas.changeSize(e); 
      } 
      public void mousePressed(MouseEvent e){} 
      public void mouseReleased(MouseEvent e){} 
      public void mouseEntered(MouseEvent e){} 
      public void mouseExited(MouseEvent e){} 
     }); 

     canvas.addMouseMotionListener(new MouseMotionAdapter() { 

      public void mouseDragged(MouseEvent e) { 

       canvas.move(e); 

      } 
     }); 

    } 

    public static void main(String[] args){ 

     JFrame frame = new ControlBall(); 
     frame.setTitle("ControlBall"); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(400, 200); 
     frame.setVisible(true); 

    } 

    public static class BallCanvas extends JPanel { 

     private int radius = 20; 
     private Color color = Color.BLACK; 
     private int ballX; 
     private int ballY; 
     private int paintCount = 0; 

     public BallCanvas(){ 

      System.out.println(getWidth() + " " + getHeight()); 

     } 

     public BallCanvas(int initialRadius){ 

      radius = initialRadius; 

     } 

     public void setColor(Color color){ 

      this.color = color; 
      repaint(); 

     } 

     public void changeSize(MouseEvent e){ 

      int numClicks = e.getClickCount(); 

      if(e.isAltDown()){ 
       if(radius >= 6){ 
        this.radius -= 5*numClicks; 
       } else{ 
        // do nothing 
       } 
      } else{ 

       this.radius += 5*numClicks; 
      } 

      repaint(); 

     } 

     public void enlarge(){ 

      this.radius += 5; 
      repaint(); 

     } 

     public void shrink(){ 

      if(radius >= 10){ 
       this.radius -= 5; 
      } 
      repaint(); 
     } 

     public void move(MouseEvent e){ 

      ballX = e.getX() - radius; 
      ballY = e.getY() - radius; 
      repaint(); 

     } 

     protected void paintComponent(Graphics g){ 

      super.paintComponent(g); 
      g.setColor(color); 
      if(paintCount < 1){ 
       ballX = getWidth()/2 - radius; 
       ballY = getHeight()/2 - radius; 
      } 
      g.fillOval(ballX, ballY, 2*radius, 2*radius); 
      paintCount++; 

     } 

    } 

} 
+2

Я не считаю это плохой стиль программирования. Но опять же, я не профессионал. Этот вопрос, скорее всего, будет основан на мнениях, а не на фактах, поэтому я голосую, чтобы закрыть. – Jeffrey

+0

Возможно, если я сфокусирую внимание на «есть ли лучший способ, которым вы это сделаете?» Будет ли это более подходящим вопросом? –

+0

+1 для [sscce] (http://sscce.org/) – trashgod

ответ

4

Некоторые вещи заслуживают внимания:

  • Override getPreferredSize() установить первоначальную геометрию панели.

  • Используйте эту геометрию, чтобы установить начальное положение мяча.

  • Invoke pack() и затем установить местоположение & видимость.

  • Использовать Action для инкапсуляции кода, совместно используемого в меню и элементах управления.

  • Использовать адаптеры последовательно.

  • Использовать initial threads правильно.

  • См. Это Q&A, в котором рассматривается связанный пример с нескольких точек зрения.

image

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 

public class ControlBall extends JFrame { 

    private JButton jbtRed = new JButton("Red"); 
    private JButton jbtGreen = new JButton("Green"); 
    private JButton jbtBlue = new JButton("Blue"); 
    private JButton jbtBlack = new JButton("Black"); 
    private BallCanvas canvas = new BallCanvas(); 
    private JMenuBar menuBar = new JMenuBar(); 
    private JMenu menu = new JMenu("Edit"); 
    private JMenuItem miEnlarge = new JMenuItem("Enlarge"); 
    private JMenuItem miShrink = new JMenuItem("Shrink"); 

    public ControlBall() { 

     menuBar.add(menu); 
     menu.add(miEnlarge); 
     menu.add(miShrink); 

     JPanel panel = new JPanel(); 
     panel.add(jbtRed); 
     panel.add(jbtGreen); 
     panel.add(jbtBlue); 
     panel.add(jbtBlack); 

     this.add(canvas, BorderLayout.CENTER); 
     this.add(panel, BorderLayout.SOUTH); 
     this.add(menuBar, BorderLayout.NORTH); 

     jbtRed.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       canvas.setColor(Color.RED); 
      } 
     }); 

     jbtGreen.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       canvas.setColor(Color.GREEN); 
      } 
     }); 

     jbtBlue.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       canvas.setColor(Color.BLUE); 
      } 
     }); 

     jbtBlack.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       canvas.setColor(Color.BLACK); 
      } 
     }); 

     miEnlarge.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       canvas.enlarge(); 
      } 
     }); 

     miShrink.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       canvas.shrink(); 
      } 
     }); 

     canvas.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       canvas.changeSize(e); 
      } 

      @Override 
      public void mouseDragged(MouseEvent e) { 
       canvas.move(e); 
      } 
     }); 
    } 

    public static void main(String[] args) { 

     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       JFrame frame = new ControlBall(); 
       frame.setTitle("ControlBall"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 

    } 

    public static class BallCanvas extends JPanel { 

     private static final int SIZE = 400; 
     private int radius = 20; 
     private Color color = Color.BLACK; 
     private int ballX = SIZE/2 - radius; 
     private int ballY = SIZE/2 - radius; 

     public BallCanvas() { 
      System.out.println(getWidth() + " " + getHeight()); 
     } 

     public BallCanvas(int initialRadius) { 
      radius = initialRadius; 
     } 

     public void setColor(Color color) { 
      this.color = color; 
      repaint(); 
     } 

     public void changeSize(MouseEvent e) { 

      int numClicks = e.getClickCount(); 

      if (e.isAltDown()) { 
       if (radius >= 6) { 
        this.radius -= 5 * numClicks; 
       } else { 
        // do nothing 
       } 
      } else { 

       this.radius += 5 * numClicks; 
      } 

      repaint(); 

     } 

     public void enlarge() { 

      this.radius += 5; 
      repaint(); 

     } 

     public void shrink() { 

      if (radius >= 10) { 
       this.radius -= 5; 
      } 
      repaint(); 
     } 

     public void move(MouseEvent e) { 

      ballX = e.getX() - radius; 
      ballY = e.getY() - radius; 
      repaint(); 

     } 

     @Override 
     protected void paintComponent(Graphics g) { 

      super.paintComponent(g); 
      g.setColor(color); 
      g.fillOval(ballX, ballY, 2 * radius, 2 * radius); 

     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(SIZE, SIZE); 
     } 
    } 
} 
+2

См. Также этот [ответ] (http://stackoverflow.com/a/5312702/230513) при перетаскивании объекты; обратите внимание на то, как автор примера не использовал адаптеры последовательно. :-) – trashgod

+0

Ничего себе !! Большое вам спасибо за очень подробный ответ. Мне понадобится немного времени, чтобы все обработать. Я мог бы задать вам вопрос или два, если он не щелкнет. –

+1

@ChrisMiddleton: Рад, что это помогло. – trashgod

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