[英]Why isn't my image updating on my JPanel?
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 maps URL創建的圖像圖標。
我只希望程序刪除舊圖像並添加更新的圖像。
觀察到的行為:我可以刪除舊圖像並調用create map函數。 該程序感覺像是掛了一秒鍾,我想是下載新圖像,但實際上並沒有更新圖像。
我知道它正在正確下載圖像,因為我可以在目錄文件夾中手動檢查它。
您將需要使用創建並添加到其中的每個新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進行更新的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.