import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.ImageIcon;
import javax.swing.*;
import java.awt.*;
public class AWG_Widget extends JPanel {
public static final int mapWidth = 300;
public static final int mapHeight = 300;
BorderLayout layout = new BorderLayout();
JPanel northPanel, centerPanel;
JButton bt_GetMap;
//Holds the map
JLabel map;
ImageIcon mapIcon;
// Combo Box for the types of maps: roadmap, satellite, terrain
String[] mapTypesStringArray = {"roadmap","satellite","terrain"};
String selectedMapType = "satellite";
JComboBox mapTypesComboBox = new JComboBox(mapTypesStringArray);
public AWG_Widget(){
// Set layout
setLayout(layout);
// Sets a border around the pane
this.setBorder(BorderFactory.createEtchedBorder());
// inits panels
northPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
// Creates components
try {
createMap();
}
catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
bt_GetMap = new JButton("Get Map!");
// Add components to panels
try{
createMap();
}
catch(IOException e){
System.out.println("Bad output");
}
northPanel.add(mapTypesComboBox);
northPanel.add(bt_GetMap);
// Add panels to layout
add(northPanel, BorderLayout.NORTH);
add(centerPanel, BorderLayout.CENTER);
// Add Listeners
mapTypesComboBox.addItemListener(new ComboBoxItemListener());
bt_GetMap.addActionListener(new ButtonListener());
}
public void createMap() throws IOException{
String imageUrl = "https://maps.googleapis.com/maps/api/staticmap?center=10,-11.998672&zoom=6&size=612x612&scale=5&maptype=" + selectedMapType + "";
String destinationFile = "image.jpg";
String str = destinationFile;
URL url = new URL(imageUrl);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(destinationFile);
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
mapIcon = new ImageIcon((new ImageIcon("image.jpg")).getImage().getScaledInstance(mapWidth, mapHeight,
java.awt.Image.SCALE_SMOOTH));
map = new JLabel(mapIcon);
centerPanel.add(map);
}
// Item Listener Class
class ComboBoxItemListener implements ItemListener{
@Override
public void itemStateChanged(ItemEvent e){
if(e.getStateChange() == ItemEvent.SELECTED){
if(e.getItem().equals("roadmap")){
selectedMapType = "roadmap";
}
if(e.getItem().equals("satellite")){
selectedMapType = "satellite";
}
if(e.getItem().equals("terrain")){
selectedMapType = "terrain";
}
}
}
}
class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
try{
centerPanel.remove(map);
remove(centerPanel);
repaint();
revalidate();
createMap();
add(centerPanel, BorderLayout.CENTER);
revalidate();
repaint();
}
catch(IOException ex){
System.out.println("Bad map");
}
catch(InterruptedException ex){
System.out.println("Bad map");
}
}
}
}
所以我从面板中删除组件,从主面板中删除子面板。我可以让图像消失,但是当我调用创建新图像的方法时,我无法将其显示出来。
我知道它会创建一个新的图像文件,因为我可以在文件夹中手动检查它。
为什么这不起作用?
预期行为:程序有一个下拉框,其中包含Google提供的三种类型的地图。我想选择一张地图,然后点击获取地图按钮。
该按钮调用get map函数,该函数创建一个jlabel,其中包含从Google地图网址创建的图像图标。
我只是希望程序删除旧图像并添加更新后的图像。
观察到的行为:我可以删除旧图像并调用创建贴图功能。该程序感觉它挂起了Split Second,我认为它正在下载新图像,但它实际上并没有更新图像。
我知道它正确下载图像,因为我可以在目录文件夹中手动检查它。
答案 0 :(得分:2)
您需要使用您创建并添加到其中的每个新JLabel在centerPanel上调用revalidate()
和repaint()
。但是,再一次,不要为此烦恼。只需交换图标。
只需改变一下:
mapLabel = new JLabel(mapIcon);
centerPanel.add(mapLabel);
到此:
mapLabel.setIcon(mapIcon);
// mapLabel = new JLabel(mapIcon);
// centerPanel.add(mapLabel);
并删除所有删除先前centerPanel和JLabel的代码。
如,
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.awt.event.ItemEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
@SuppressWarnings("serial")
public class AWG_Widget2 extends JPanel {
public static final int MAP_WIDTH = 300;
public static final int MAP_HEIGHT = 300;
private static final String DEFAULT_GOOGLE_MAP_TEXT = "https://maps.googleapis.com/maps/"
+ "api/staticmap?center=10,-11.998672&zoom=6&size=612x612&scale=5&maptype=";
private Icon defaultIcon = new ImageIcon(
new BufferedImage(MAP_WIDTH, MAP_HEIGHT, BufferedImage.TYPE_INT_ARGB));
private BorderLayout layout = new BorderLayout();
private JPanel northPanel, centerPanel;
private JButton bt_GetMap;
// Holds the map
private JLabel mapLabel = new JLabel(defaultIcon);
// Combo Box for the types of maps: roadmap, satellite, terrain
private String[] mapTypesStringArray = { "roadmap", "satellite", "terrain" };
private String selectedMapType = "satellite";
private JComboBox<MapType> mapTypesComboBox = new JComboBox<>(MapType.values());
private String googleMapText = DEFAULT_GOOGLE_MAP_TEXT;
public AWG_Widget2() {
// Set layout
setLayout(layout);
// Sets a border around the pane
this.setBorder(BorderFactory.createEtchedBorder());
// inits panels
northPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
centerPanel.add(mapLabel);
// Creates components
try {
createMap(MapType.ROADMAP);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
bt_GetMap = new JButton("Get Map!");
northPanel.add(mapTypesComboBox);
northPanel.add(bt_GetMap);
// Add panels to layout
add(northPanel, BorderLayout.NORTH);
add(centerPanel, BorderLayout.CENTER);
// Add Listeners
mapTypesComboBox.addItemListener(new ComboBoxItemListener());
bt_GetMap.addActionListener(new ButtonListener());
}
private void createMyMap() {
mapLabel.setIcon(defaultIcon);
try {
createMap((MapType) mapTypesComboBox.getSelectedItem());
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void createMap(MapType mapType) throws IOException {
new SwingWorker<Icon, Void>() {
@Override
protected Icon doInBackground() throws Exception {
// this code is all done within a background thread
String imageUrl = googleMapText + mapType.getText();
URL url = new URL(imageUrl);
Image img = ImageIO.read(url);
img = img.getScaledInstance(MAP_WIDTH, MAP_HEIGHT, Image.SCALE_SMOOTH);
return new ImageIcon(img);
}
@Override
protected void done() {
try {
// this code is called on the Swing event thread
// get returns the Icon created in the doInBackground method
mapLabel.setIcon(get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
};
}.execute(); // executes our worker
}
// Item Listener Class
class ComboBoxItemListener implements ItemListener {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
createMyMap();
}
}
}
class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
createMyMap();
}
}
private static void createAndShowGui() {
AWG_Widget2 mainPanel = new AWG_Widget2();
JFrame frame = new JFrame("AWG_Widget");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
public enum MapType {
ROADMAP("roadmap"), SATELLITE("satellite"), TERRAIN("terrain");
private String text;
private MapType(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
同样根据Titus的评论说明,任何长时间运行的代码都应该在不同的线程中运行该进程。对于Swing,规范的解决方案是使用SwingWorker。有关这方面的更多信息,请参阅:
另请注意,在我的代码中,JButton及其ActionListener是多余的,因为地图是由添加到JComboBox的ItemListener更新的。