简体   繁体   中英

How to refresh/reload an image in Swing GUI as the real image file changes?

I am trying to implement Remote FrameBuffer Protocol using Java socket programming. I have a server side program that takes screenshot of the entire screen using robot and store it in BufferedImage.Then I converted it into a byte array and sending it to the client.

Objective: To display the entire screen of the server side machine in a Swing GUI of the client side.

Problem i am facing: i am able to send the image in bytes from server and receive it from the server by the client (client.java) and convert it into a jpg image (output.jpg) using ImageIO and put that image in a Swing frame.

But i am able to see the first image in the Swing and whenever the image gets updated,the image in the Swing is not updating or refreshing.

What I want: I want the image to refresh and show updated image every time the server sends the image data.

client.java

package remoteclient;

import java.lang.*;
import javax.imageio.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.net.*;
import java.io.*;

public class client  {

   
    public static void main(String args[])throws Exception{  
        Socket s=new Socket("localhost",5900);  
        DataInputStream din=new DataInputStream(s.getInputStream());  
        DataOutputStream dout=new DataOutputStream(s.getOutputStream());  
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));  
      
        int width=0,height=0;
        try {
            width = din.readInt(); //getting width and height from server thru socket.
            height = din.readInt(); 
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        JFrame f = new JFrame("Client");
        JLabel label = new JLabel();
       

        f.setSize(width, height);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         f.setVisible(true);

        boolean continueLoop = true;
        

        while(continueLoop)
        {
            try {
                
                int len = din.readInt();
                byte[] imageInByte = new byte[len];
                            
                System.out.println(len);

                din.readFully(imageInByte);

                System.out.println(imageInByte);
                
                ByteArrayInputStream bis = new ByteArrayInputStream(imageInByte);
                BufferedImage bImage2 = ImageIO.read(bis);
             //   Image im1 = bImage2.getScaledInstance(width,height, Image.SCALE_SMOOTH);

                
                ImageIO.write(bImage2, "jpg", new File("output.jpg") );
                bImage2 = ImageIO.read(new File("output.jpg"));
                label.setIcon(new ImageIcon(im1));
              
                ImageIcon icon = new ImageIcon(bImage2);
                icon.getImage().flush();
                label.setIcon( icon );
                f.getContentPane().add(label, BorderLayout.CENTER);
                
                f.pack();

           
            
           
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

  
    }
    }  


What I want: I want the image to refresh and show updated image every time the server sends the image data.

Updated code with comments about demo code that should be removed from your working code:

Here's an example, using default UIManager icons, and SwingWorker , as noted in the comments to the original posting. You would instead use images from your server connection.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.UIManager;

public class SwingLabelWithUpdatedImage {

    public static void main(String args[]) throws Exception {

        final JLabel label = new JLabel("", SwingConstants.CENTER);

        final JFrame frame = new JFrame("Client");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(label, BorderLayout.CENTER);
        final Dimension preferredSize = new Dimension(200, 100);
        frame.setPreferredSize(preferredSize);
        frame.setVisible(true);
        frame.pack();

        final ImageUpdateWorker task = new ImageUpdateWorker(label);
        task.execute();
    }

    public static class ImageUpdateWorker extends SwingWorker<Void, IconInfo> {
        // iconInfoList is not need in your code. It's here so I can
        // supply a dummy set of icons to demonstrate UI updates.
        final List<IconInfo> iconInfoList;
        private JLabel label;

        ImageUpdateWorker(JLabel label) {
            this.label = label;
            // Delete this in your code
            this.iconInfoList = initIconInfoList();
        }

        @Override
        public Void doInBackground() {
            boolean isTrue = true;
            while (isTrue) {
                // Put your socket code to read the next icon from a server.
                // You don't need to do the ImageIO.write(), ImageIO.read() dance,
                // unless you must save the icon to disk. In that case, you don't need
                // to read it back in.

                // Here, I just rotate the iconInfoList to make it
                // appear as though a new icon was received.
                // Your code will not have any need to do this.
                Collections.rotate(iconInfoList, -1);
                // Just publish the icon you create from the image
                // you receive from your remote server.
                publish(iconInfoList.get(0));
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void process(List<IconInfo> icons) {
            // You might check for an empty list.
            // @kleopatra's suggestion to get the last icon is correct.
            // See https://docs.oracle.com/javase/tutorial/uiswing/concurrency/interim.html
            IconInfo iconInfo = icons.get(icons.size() - 1);
            label.setIcon(iconInfo.icon);
            // Your code will not do this 
            label.setText(iconInfo.name);
            // You can get the icon dimensions just from the icon, 
            // so you don't really need the IconInfo class.
            label.setSize(iconInfo.dimension);
        }

        /** Demo code only. It doesn't belong in your working code.
         */
        protected List<IconInfo> initIconInfoList() {
            // Just a quick way to get some icons; don't need to
            // fetch from a server just to demonstrate how to
            // refresh the UI.
            List<IconInfo> iconInfoList = UIManager.getDefaults().keySet().stream()
                .filter(this::isIconKey)
                .map(IconInfo::new)
                .filter(iconInfo -> iconInfo.icon != null)
                .collect(Collectors.toList());

            return iconInfoList;
        }

        /** Demo code only. It doesn't belong in your working code.
         */
        protected boolean isIconKey(Object key) {
            return String.class.isAssignableFrom(key.getClass())
                && ((String) key).toLowerCase().contains("icon");
        }
    }

    /** This is just a convenience to convey 
     * the icon and its UIManager key (i.e., name). 
     * Your remote server doesn't supply a name, 
     * so you don't really need this class.
     * It's just to make the demo more expressive.
     */
    public static class IconInfo {
        final private String name;
        final private Icon icon;
        final private Dimension dimension;

        IconInfo(Object name) {
            this.name = name.toString();
            icon = UIManager.getIcon(name);
            dimension = icon == null
                ? new Dimension(32, 32)
                : new Dimension(icon.getIconWidth(), icon.getIconHeight());
        }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM