首页 > 解决方案 > 异步加载 JButton 图标

问题描述

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

实现这一点很好,但我的问题是应用程序启动需要大约 10 分钟,因为它同步地一个一个地拉取每个图像图标。PS 我使用 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);
    }

标签: javaapiasynchronousjbuttonokhttp3

解决方案


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

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

这是完整的解决方案:

主类(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);
    }


摇摆工人班

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);
    }
  }
}

推荐阅读