为什么我的JPanel上的图像更新?

时间:2017-10-29 17:24:14

标签: java google-maps jpanel jlabel

https://pastebin.com/Mfj4pX2c

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,我认为它正在下载新图像,但它实际上并没有更新图像。

我知道它正确下载图像,因为我可以在目录文件夹中手动检查它。

1 个答案:

答案 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。有关这方面的更多信息,请参阅:

Lesson: Concurrency in Swing

另请注意,在我的代码中,JButton及其ActionListener是多余的,因为地图是由添加到JComboBox的ItemListener更新的。