异步加载JButton图标

时间:2018-08-07 11:37:55

标签: java api asynchronous jbutton okhttp3

我有一个应用程序,该应用程序在启动时会从API中提取数据,并将其显示在JButtons的网格中。我已经根据API响应成功显示并生成了JButton,但是我的问题是每个Button都需要有一个图标,该图标也要从API直接拉到JButton图标中。

实现这一点很好,但我的问题是,由于该应用程序已同步逐个拉动每个图像图标,因此启动该应用程序大约需要10分钟。 附言我使用OkHttp作为我的http客户端。

有人可以帮我找到一种方法,也许可以加载按钮,然后在完全从API中拉出图像时逐渐加载图像。

我该怎么做? 如何异步执行此操作?

我尝试到处寻找,但无法将找到的答案成功应用于我的问题。

这是此问题的代码段。

提前谢谢!

static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

// api post method
String post(String url, String json) throws IOException {
    RequestBody body = RequestBody.create(JSON, json);
    Request request = new Request.Builder()
        .url(url)
        .post(body)
        .build();
    try (Response response = client.newCall(request).execute()) {
        return response.body().string();
    }
}

// api call
try {
        String json = "";
        String response = post("http://myapi.com", json);

        JSONObject JsonResponse = new JSONObject(response);
        JSONArray devices = JsonResponse.getJSONArray("response");

        int rows = (devices.length() / 4) + 3;
        resultsPanel.setLayout(new GridLayout(rows, 0, 20, 20));

        for(int d = 0; d < devices.length(); d++){

            // store device details
            JSONObject selectedDevice = devices.getJSONObject(d);

            // create button
            JButton device = new JButton();

            // style button
            Border lineBorder = new LineBorder(new java.awt.Color(238, 238, 238));
            Border padding = new EmptyBorder(0, 10, 0, 0);

            device.setIcon(new javax.swing.ImageIcon(getClass().getResource("/assets/shield_32.png")));

            device.setIconTextGap(20);
            device.setText(devices.getJSONObject(d).get("name").toString());
            device.setPreferredSize(new Dimension(100, 100));
            device.setBackground(new java.awt.Color(255, 255, 255));
            device.setFont(new java.awt.Font("Arial", 0, 12));
            device.setVerticalTextPosition(SwingConstants.BOTTOM);
            device.setHorizontalTextPosition(SwingConstants.CENTER);
            device.setBorder(new CompoundBorder(lineBorder, padding));
            device.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
            device.setFocusable(false);

            // event handling
            device.addActionListener((java.awt.event.ActionEvent evt) -> {
                System.out.println("Selected: " + ((JButton) evt.getSource()).getText());
                deviceNameLbl.setText(((JButton) evt.getSource()).getText());

                deviceImgLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/assets/shield_350.png")));
                getDevicePattern(selectedDevice.get("deviceModelID").toString());

                CardLayout card = (CardLayout)mainPanel.getLayout();
                card.show(mainPanel, "material_design");
            });

            // add button to panel
            resultsPanel.add(device);
        }

    } catch (IOException ex) {
        Logger.getLogger(ISoD.class.getName()).log(Level.SEVERE, null, ex);
    }

1 个答案:

答案 0 :(得分:0)

我终于设法解决了这个问题。

当从API中提取图像图标时,我使用了SwingWorker类来异步设置图像图标。这是我一直在寻找的完美效果!

这是完整的解决方案:

主类(JFrame)

static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
    RequestBody body = RequestBody.create(JSON, json);
    Request request = new Request.Builder()
        .url(url)
        .post(body)
        .build();
    try (Response response = client.newCall(request).execute()) {
        return response.body().string();
    }
}

try {
        String json = "";
        String response = post("http://my-api.com/images", json);

        JSONObject JsonResponse = new JSONObject(response);
        JSONArray devices = JsonResponse.getJSONArray("response");

        int rows = (devices.length() / 4) + 3;
        resultsPanel.setLayout(new GridLayout(rows, 0, 20, 20));

        for(int d = 0; d < devices.length(); d++){

            // store device details
            JSONObject selectedDevice = devices.getJSONObject(d);

            // create button
            JButton device = new JButton();

            // extracting icon url from api response
            URL imageURL = new URL(devices.getJSONObject(d).get("brandImage").toString());

            // style button
            Border lineBorder = new LineBorder(new java.awt.Color(238, 238, 238));
            Border padding = new EmptyBorder(0, 10, 0, 0);

            device.setIcon(new javax.swing.ImageIcon(getClass().getResource("/assets/stock_image.png")));
            device.setIconTextGap(20);
            device.setText(devices.getJSONObject(d).get("name").toString());
            device.setPreferredSize(new Dimension(100, 100));
            device.setBackground(new java.awt.Color(255, 255, 255));
            device.setFont(new java.awt.Font("Arial", 0, 12));
            device.setVerticalTextPosition(SwingConstants.BOTTOM);
            device.setHorizontalTextPosition(SwingConstants.CENTER);
            device.setBorder(new CompoundBorder(lineBorder, padding));
            device.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
            device.setFocusable(false);

            // add button to panel
            resultsPanel.add(device);

            // asynchronously load images from api response
            new ImageWorker(imageURL, device).execute();
        }

    } catch (IOException ex) {
        Logger.getLogger(ISoD.class.getName()).log(Level.SEVERE, null, ex);
    }


SwingWorker类

public class ImageWorker extends SwingWorker<ImageIcon, Void>{

URL imageURL;
ImageIcon brandImage;
JButton device;

public ImageWorker(URL imageURL, JButton device){
    this.imageURL = imageURL;
    this.device = device;
}

@Override
protected ImageIcon doInBackground() throws Exception {
    brandImage = new ImageIcon(imageURL);
    Image rawBrandImage = brandImage.getImage();
    Image newimg = rawBrandImage.getScaledInstance(32, 32,  java.awt.Image.SCALE_SMOOTH);
    brandImage = new ImageIcon(newimg);
    return brandImage;
}

@Override
protected void done() {
    // leave as default zagg shield icon if no brand icon is returned by api
    if (brandImage.getIconWidth() == 32 && brandImage.getIconHeight() == 32) {
        device.setIcon(brandImage);
    }
  }
}