Java 创建多个JButton(数百个)会在创建它们时产生巨大的延迟
当我创建jbutton时,会有很大的延迟。以下是我如何创建按钮的一些示例代码:Java 创建多个JButton(数百个)会在创建它们时产生巨大的延迟,java,swing,2d-games,game-development,Java,Swing,2d Games,Game Development,当我创建jbutton时,会有很大的延迟。以下是我如何创建按钮的一些示例代码: import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class Scratch { public static void main(Stri
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Scratch {
public static void main(String[] args) {
Runnable r = () -> {
JOptionPane.showMessageDialog(
null, new Scratch().getUI(new TileSet("Content/Graphics/tileSets/12x12x3 - tileSet.png", 12, 12, 3)));
JOptionPane.showMessageDialog(
null, new Scratch().getUI(new TileSet("Content/Graphics/tileSets/16x16x0 - tileSetItems.png", 12, 12, 3)));
JOptionPane.showMessageDialog(
null, new Scratch().getUI(new TileSet("Content/Graphics/tileSets/29x18x1 - roguelikeDungeon_transparent.png", 12, 12, 3)));
};
SwingUtilities.invokeLater(r);
}
public final JComponent getUI(TileSet tileSet) {
JPanel ui = new JPanel();
JPanel tilePanel = new JPanel();
tilePanel.setLayout(new GridLayout(12, 12, 5, 5));
long t1 = System.currentTimeMillis();
TileButton tileMenuButtons[] = new TileButton[tileSet.tileSet.length];
long tot = 0;
for (int i = 0; i < tileMenuButtons.length; i++) {
long t2 = System.currentTimeMillis();
tileMenuButtons[i] = new TileButton(i,tileSet);
long t3 = System.currentTimeMillis();
tot += (t3-t2);
System.out.println(String.format("It took : "+ tot +"ms for loading "+i+ ". Button "));
tilePanel.add(tileMenuButtons[i]);
}
long t4 = System.currentTimeMillis();
JScrollPane scrollPane = new JScrollPane();
scrollPane.getVerticalScrollBar().setUnitIncrement(16);
scrollPane.setOpaque(true);
scrollPane.setViewportView(tilePanel);
ui.add(scrollPane);
System.out.println(String.format("It took in total : "+ (t4-t1) +"ms for loading "+tileMenuButtons.length+ " TileButtons"));
return ui;
}
测量创建每个按钮的时间后,整个延迟由按钮引起:
It took 30915ms for loading the 521st Button
It took in total : 30979ms for loading the TileSet
我可以过滤出这个问题是由我的Button类引起的,但我不知道在哪里,为什么
class TileButton extends JButton {
private int id;
private TileSet ts = new TileSet("Content/Graphics/tileSets/12x12x3 - tileSet.png", 12, 12, 3);
private int size = 50;
public TileButton(int id, TileSet tileSet) {
super();
this.ts = tileSet;
this.id = id;
loadImage(id);
}
public void loadImage(int imageno) {
this.setBorder(null);
try {
Image img = ts.tileSet[imageno].tileImage;
img = img.getScaledInstance(size, size, Image.SCALE_SMOOTH);
ImageIcon icon = new ImageIcon(img);
this.setIcon(icon);
} catch (Exception e) {
System.out.println("Fehler beim Laden von Bild");
}
}
}
static class TileSet{
private String tileSetImagePath;
private int numberOfTilesX, numberOfTilesY;
private BufferedImage tileSetImage;
public Tile[] tileSet;
private int width = Tile.TILEWIDTH, height = Tile.TILEHEIGHT;
private int border;
public TileSet(String pTileSetImagePath, int pNumberOfTilesX, int pNumberOfTilesY, int pBorder){
tileSetImagePath = pTileSetImagePath;
numberOfTilesX = pNumberOfTilesX;
numberOfTilesY = pNumberOfTilesY;
border = pBorder;
tileSet = new Tile[numberOfTilesX * numberOfTilesY];
createTileSetImages();
}
public void createTileSetImages(){
try {
tileSetImage = ImageIO.read(new File(tileSetImagePath));
width = tileSetImage.getWidth() / numberOfTilesX - border;
height = tileSetImage.getHeight() / numberOfTilesY - border;
} catch (IOException e) {
e.printStackTrace();
}
int i = 0;
for(int y = 0; y < numberOfTilesY; y++) {
for(int x = 0; x < numberOfTilesX; x++) {
BufferedImage bi = tileSetImage.getSubimage(x * (width + border), y * (height + border), width, height);
bi.getScaledInstance(Tile.TILEWIDTH, Tile.TILEHEIGHT, Image.SCALE_SMOOTH);
tileSet[i++] = new Tile(bi);
}
}
}
}
}
class Tile extends JPanel{
public Image tileImage;
public Tile(Image pTileImage) {
super();
setOpaque(true);
tileImage = pTileImage;
}
}
类TileButton扩展了JButton{
私有int-id;
私有TileSet ts=新TileSet(“Content/Graphics/TileSet/12x12x3-TileSet.png”,12,12,3);
私有整数大小=50;
公共TileButton(int-id,TileSet-TileSet){
超级();
this.ts=tileSet;
this.id=id;
loadImage(id);
}
公共无效加载映像(int imageno){
本订单(空);
试一试{
图像img=ts.tileSet[imageno].tileImage;
img=img.getScaledInstance(大小、大小、图像.缩放\u平滑);
ImageIcon图标=新的ImageIcon(img);
这个.setIcon(图标);
}捕获(例外e){
系统输出打印(“Fehler beim Ladden von Bild”);
}
}
}
静态类TileSet{
私有字符串tileSetImagePath;
私有int numberoftilex,numberoftilexy;
私有缓冲区映像tile估计;
公共瓷砖[]瓷砖集;
private int width=Tile.TILEWIDTH,height=Tile.tilewhight;
私人国际边界;
公共TileSet(字符串pTileSetImagePath、int-pNumber-OftilesX、int-pNumber-OftileSy、int-pOrder){
tileSetImagePath=PTILESITIMAGEPATH;
numberoftilex=pnumberoftilex;
numberOfTilesY=pNumberOfTilesY;
border=pBorder;
tileSet=新磁贴[NumberOfTileX*numberOfTilesY];
createTileSeimages();
}
public void createTileSetImages(){
试一试{
tileSetImage=ImageIO.read(新文件(tileSetImagePath));
width=tileSetImage.getWidth()/NumberOfTileX-border;
height=tileSetImage.getHeight()/numberOfTilesY-border;
}捕获(IOE异常){
e、 printStackTrace();
}
int i=0;
for(int y=0;y
正如Andrew所说,可能是缩放状态导致了延迟。有没有其他方法可以在没有这么大延迟的情况下缩放图像?编辑:缩放不会导致延迟:创建一个缩放按钮需要1毫秒。
(很抱歉代码太长,但它是必需的,因为如果我只使用(简化的)图标和按钮,它将不适用于我的问题,因此不会有帮助)
在尝试创建没有缩放的按钮后,延迟仍然存在。这里是一个MCVE/SSCCE,将100个按钮添加到GUI中的6400个按钮,每个按钮都有自己的图标 此处的典型输出:
It took 14 milliseconds for 100 buttons.
It took 110 milliseconds for 1600 buttons.
It took 138 milliseconds for 6400 buttons.
它在一个框架中看起来像什么
import java.awt.*;
import java.awt.image.*;
import java.io.IOException;
import java.net.*;
import javax.swing.*;
import javax.imageio.*;
public class LotsOfButtons {
public final JComponent getUI(int pts) {
JComponent ui = new JPanel(new GridLayout(0, pts));
try {
BufferedImage image = ImageIO.read(new URL(
"https://i.stack.imgur.com/OVOg3.jpg"));
int wT = image.getWidth() / pts;
int hT = image.getHeight() / pts;
Insets insets = new Insets(0, 0, 0, 0);
long t1 = System.currentTimeMillis();
for (int jj = 0; jj < pts; jj++) {
for (int ii = 0; ii < pts; ii++) {
int x = ii * wT;
int y = jj * hT;
JButton b = new JButton(new ImageIcon(
image.getSubimage(x, y, wT, hT)));
b.setMargin(insets);
ui.add(b);
}
}
long t2 = System.currentTimeMillis();
System.out.println(String.format(
"It took %1s milliseconds for %1s buttons.",
(t2 - t1), pts*pts));
} catch (IOException ex) {
ex.printStackTrace();
}
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
JOptionPane.showMessageDialog(
null, new LotsOfButtons().getUI(10));
JOptionPane.showMessageDialog(
null, new LotsOfButtons().getUI(40));
JOptionPane.showMessageDialog(
null, new LotsOfButtons().getUI(80));
};
SwingUtilities.invokeLater(r);
}
}
import java.awt.*;
导入java.awt.image.*;
导入java.io.IOException;
导入java.net。*;
导入javax.swing.*;
导入javax.imageio.*;
公共类按钮{
公开最终JComponent getUI(int pts){
jcomponentui=newjpanel(新网格布局(0,pts));
试一试{
BuffereImage image=ImageIO.read(新URL(
"https://i.stack.imgur.com/OVOg3.jpg"));
int wT=image.getWidth()/pts;
int hT=image.getHeight()/pts;
插图插图=新插图(0,0,0,0);
long t1=System.currentTimeMillis();
对于(intjj=0;jj{
JOptionPane.showMessageDialog(
null,新的LotsOfButtons().getUI(10));
JOptionPane.showMessageDialog(
null,新的LotsOfButtons().getUI(40));
JOptionPane.showMessageDialog(
null,新的LotsOfButtons().getUI(80));
};
SwingUtilities.invokeLater(r);
}
}
因此,给定的
14毫秒
不会接近“(>30秒。)”我猜你会这么做。。不同地除非上述源代码帮助您解决问题,否则我建议您准备并发布一份MCVE/SSCCE,与上述源代码一样,热链接到图像将是解决问题的最佳举措 您的问题可能在TileButton类中:
class TileButton extends JButton {
private int id;
private TileSet ts = new TileSet("Content/Graphics/tileSets/12x12x3 - tileSet.png", 12, 12, 3);
private int size = 50;
public TileButton(int id, TileSet tileSet) {
super();
this.ts = tileSet;
this.id = id;
loadImage(id);
}
为每个TileButton创建新的TileSet。此磁贴集从文件读取-这可能会导致相当大的延迟。然后忽略此平铺集并使用传入构造函数的平铺集
因此,您不应每次都创建新的瓷砖集:
class TileButton extends JButton {
private int id;
private final TileSet ts;
private int size = 50;
public TileButton(int id, TileSet tileSet) {
super();
this.ts = tileSet;
this.id = id;
loadImage(id);
}
1) 为了更快地获得更好的帮助,请添加或。2) 例如,获取图像的一种方法是热链接到中看到的图像。例如,嵌入到中的图像的热链接。3) 请参阅(是)。您可能需要分析您的应用程序。通常创建和添加100个按钮不应该
class TileButton extends JButton {
private int id;
private final TileSet ts;
private int size = 50;
public TileButton(int id, TileSet tileSet) {
super();
this.ts = tileSet;
this.id = id;
loadImage(id);
}