2015-03-19 46 views
1

首先,一些背景。我正在使用Java构建我的第一个GUI应用程序,但我不确定如果我以正确的方式进行操作,因为我不熟悉GUI类。最终目标是根据开放街道地图数据构建可调整大小的可缩放滚动地图。JPanel重新调整大小重绘几次,有时根本没有

我现在所拥有的是JPanel的一个子类,我在JFrame中调用LinePanel,并使用Graphics对象绘制表示道路的线条。这对于检查我是否正确地解析和解释数据的目的是正确的,但它似乎不够和天真。我已经遇到了一个问题,JPanel在重新调整大小后重新绘制了几次,导致地图出错,直到我的应用程序需要癫痫警告。

这是我现在的代码:

package map; 

import java.awt.BasicStroke; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics2D; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class MapDisplay { 
    private JFrame frame; 
    private LinePanel jpanel; 

    public MapDisplay(Map map) { 
     this.frame = new JFrame(); 
     frame.setLayout(new BorderLayout()); 
     frame.addComponentListener(new ComponentAdapter() { 
      public void componentResized(ComponentEvent e) { 
       jpanel.repaint(); 
      } 
     }); 
     jpanel = new LinePanel(map); 
     frame.add(jpanel, BorderLayout.CENTER); 
    } 

    public void display() { 
     frame.setSize(710, 935); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     jpanel.repaint(); 
    } 

    class LinePanel extends JPanel { 
     private static final long serialVersionUID = 1965018056953712219L; 
     private Map map; 
     private int width; 
     private int height; 

     private int latAsY(double lat) { 
      return height 
        - (int) (height * (lat - map.getMinLat())/(map 
          .getMaxLat() - map.getMinLat())); 
     } 

     private int lonAsX(double lon) { 
      return (int) (width * (lon - map.getMinLong())/(map.getMaxLong() - map 
        .getMinLong())); 
     } 

     private void recalculateDimensions() { 
      double mapRatio = (map.getMaxLat() - map.getMinLat()) 
        /(map.getMaxLong() - map.getMinLong()); 
      double panelRatio = this.getHeight()/(double) this.getWidth(); 
      if (mapRatio > panelRatio) { 
       width = (int) (this.getHeight()/mapRatio); 
       height = this.getHeight(); 
      } else { 
       width = this.getWidth(); 
       height = (int) (mapRatio * this.getWidth()); 
      } 
     } 

     public LinePanel(Map map) { 
      super(); 
      this.map = map; 
     } 

     public void repaint() { 
      if (map != null) { 
       recalculateDimensions(); 
       Graphics2D g = (Graphics2D) this.getGraphics(); 
       if (g != null) { 
        g.setStroke(new BasicStroke(2)); 
        g.clearRect(0, 0, jpanel.getWidth(), jpanel.getHeight()); 
        g.setColor(Color.WHITE); 
        g.fillRect(0, 0, width, height); 
        g.setColor(Color.BLACK); 
        for (String wayId : map.getWays()) { 
         Way way = map.getWay(wayId); 
         Node prev = null; 
         for (String nodeId : way.getNodes()) { 
          Node cur = map.getNode(nodeId); 
          if (prev != null) { 
           int y1 = latAsY(prev.getLatitude()); 
           int x1 = lonAsX(prev.getLongitude()); 
           int y2 = latAsY(cur.getLatitude()); 
           int x2 = lonAsX(cur.getLongitude()); 
           g.drawLine(x1, y1, x2, y2); 
          } 
          prev = cur; 
         } 
        } 
       } 
      } 
     } 
    } 
} 

我打电话重新绘制调整大小,因为它不会自动做到这一点,我做错了又一个迹象。我也用g.fillRect手动清除了JPanel,因为在重绘图之前调用super.repaint()会导致没有任何东西出现...

本质上,我只想从更高级的Java程序员那里得到一些指导,应该全力以赴。如果我走在正确的道路上,随意推动我朝着正确的方向前进,而不是让我走上新的道路,但我怀疑是这样。

回答

2
  • public void repaint() { NO,NO,NO
  • Graphics2D g = (Graphics2D) this.getGraphics(); - NO,NO,NO

这不是在Swing如何画作品。见Performing Custom PaintingPainting in AWT and Swing有关如何画应该在Swing做更多的细节

你应该摆脱你的repaint方法的开头和paintComponent方法取代它......

public class MapDisplay { 

    private JFrame frame; 
    private LinePanel jpanel; 

    public MapDisplay(Map map) { 
     this.frame = new JFrame(); 
     frame.setLayout(new BorderLayout()); 
     frame.addComponentListener(new ComponentAdapter() { 
      public void componentResized(ComponentEvent e) { 
       jpanel.repaint(); 
      } 
     }); 
     jpanel = new LinePanel(map); 
     frame.add(jpanel, BorderLayout.CENTER); 
    } 

    public void display() { 
     frame.setSize(710, 935); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     jpanel.repaint(); 
    } 

    class LinePanel extends JPanel { 

     private static final long serialVersionUID = 1965018056953712219L; 
     private Map map; 
     private int width; 
     private int height; 

     private int latAsY(double lat) { 
      return height 
          - (int) (height * (lat - map.getMinLat())/(map 
          .getMaxLat() - map.getMinLat())); 
     } 

     private int lonAsX(double lon) { 
      return (int) (width * (lon - map.getMinLong())/(map.getMaxLong() - map 
          .getMinLong())); 
     } 

     private void recalculateDimensions() { 
      double mapRatio = (map.getMaxLat() - map.getMinLat()) 
          /(map.getMaxLong() - map.getMinLong()); 
      double panelRatio = this.getHeight()/(double) this.getWidth(); 
      if (mapRatio > panelRatio) { 
       width = (int) (this.getHeight()/mapRatio); 
       height = this.getHeight(); 
      } else { 
       width = this.getWidth(); 
       height = (int) (mapRatio * this.getWidth()); 
      } 
     } 

     public LinePanel(Map map) { 
      super(); 
      this.map = map; 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (map != null) { 
       recalculateDimensions(); 
       Graphics2D g2d = (Graphics2D) g.create(); 
       g2d.setStroke(new BasicStroke(2)); 
       g2d.clearRect(0, 0, jpanel.getWidth(), jpanel.getHeight()); 
       g2d.setColor(Color.WHITE); 
       g2d.fillRect(0, 0, width, height); 
       g2d.setColor(Color.BLACK); 
       for (String wayId : map.getWays()) { 
        Way way = map.getWay(wayId); 
        Node prev = null; 
        for (String nodeId : way.getNodes()) { 
         Node cur = map.getNode(nodeId); 
         if (prev != null) { 
          int y1 = latAsY(prev.getLatitude()); 
          int x1 = lonAsX(prev.getLongitude()); 
          int y2 = latAsY(cur.getLatitude()); 
          int x2 = lonAsX(cur.getLongitude()); 
          g2d.drawLine(x1, y1, x2, y2); 
         } 
         prev = cur; 
        } 
       } 
       g2d.dispose(); 
      } 
     } 
    } 
} 

是,重绘事件可能会在组件重新调整大小时产生多次,但重新绘制事件也可以自动减少RepaintManager(即RepaintManager可能被调用100次来重新绘制组件,可能仅产生10次实际重绘事件 - 与一个例子)...

+0

谢谢,我知道我必须做一些完全错误的事情。我刚刚发现了其他一些问题,其他问题的做法与思维练习类似,没有人正在纠正它们。 – 2015-03-19 02:50:55

+1

为了能够进一步解决它,我们需要看到一个[runnable示例](https://stackoverflow.com/help/mcve),它演示了您的问题。这不是代码转储,而是您正在做的事情的一个例子,它突出了您遇到的问题。这会导致更少的混淆和更好的响应 – MadProgrammer 2015-03-19 02:54:28

+0

只是好奇,为什么paintComponent更适合重绘? – 2015-03-19 02:55:35