2015-03-19 24 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

相關問題