首先,一些背景知识。我正在用Java构建我的第一个GUI应用程序,并且我不确定我是否正确地使用它,因为我不熟悉GUI类。最终目标是根据Open Street Map数据构建可调整大小,可缩放,可滚动的地图。
我现在拥有的是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程序员的一些指导,关于我应该如何进行这一整个努力。如果我走在正确的轨道上,请随意向我推进正确的方向,而不是让我走上新的道路,但我怀疑是这样的。
答案 0 :(得分:2)
public void repaint() {
NO,NO,NO Graphics2D g = (Graphics2D) this.getGraphics();
- NO,NO,NO 这不是绘画在Swing中的作用。有关如何在Swing
中完成绘画的详细信息,请参阅Performing Custom Painting和Painting in AWT and 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个实际的重绘事件 - 作为一个例子)......