java - 异步加载 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);
}
解决方案
我终于设法自己解决了这个问题。
我使用 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);
}
}
}
推荐阅读
- javascript - 使用依赖异步函数的 ngif 的正确方法
- javascript - 在 expressionProperties 中组合模型和布尔变量 - Formly
- javascript - AngularJs复选框的ngDupes错误
- c# - .Net Core 2.1 Web 和控制台 DbContexts
- javascript - 强制光标自动放置在注册表单中用户名字段的左端
- arduino - 使用 Arduino Uno 或 Feather M0 查找电池温度
- python - 如何使用 Pysolr 进行构面搜索
- java - 如何检查两个序列是否以某种顺序具有相同的值,(忽略重复)java
- git - 如何知道其他人正在 Visual Studio Team Services 中 Git 下的 Visual Studio 项目中的文件中工作?
- excel - Excel VBA 代码:系统错误(服务器抛出异常)