gpt4 book ai didi

Java - Lists 和 Graphics2D 的分层问题

转载 作者:行者123 更新时间:2023-12-01 15:03:16 26 4
gpt4 key购买 nike

所以我有一个 DisplayPanel 类,它扩展了 JPanel,并且还使用 Graphics2D 为我的程序绘制了大量图像。为了能够轻松地自定义使用它,我对其进行了设置,以便每次重新绘制面板时它都使用一个列表,我可以在程序处理时添加或删除该列表。我的问题是分层。我遇到了一个问题,列表必须达到其大小调整点(或类似的奇怪的东西),因此我想要显示的图像最终位于屏幕上已有的所有其他图像的下方。我来到社区寻求答案,因为我相信您会提供一个好的答案。

问题图片:只有远角的图片被鼠标高亮显示。其余部分的亮点如下......(http://imgur.com/LY41q)

来自 DisplayPanel 的代码:

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.clearRect(0, 0, 800, 640);
for(int i = 0; i < images.size(); i++) g2d.drawImage(
images.get(i).getImage(), images.get(i).getX(),
images.get(i).getY(), null);
}

public void paintImage(ImageMap[] images, ImageMap[] clearImages, boolean clear) {
if(clear) this.images.clear();
else if(clearImages!=null) for(int i = 0; i < clearImages.length; i++) this.images.remove(clearImages[i]);
if(images!=null) for(int i = 0; i<images.length; i++) this.images.add(images[i]);
refresh();
}

游戏代码:

    private void handleMoveClick(int identity) {

int index = -1;
if(identity >=0 && identity < 36) {
System.out.println(identity);
index = identity;
identity = 0;
}

switch(identity) {

case startButtonIdentity:
if(!tempButtonImages.contains(startButtonLight)) {
tempButtonImages.add(startButtonLight);
display.panel.addImage(startButtonLight);
}
break;

case 0:
if(!tempButtonImages.contains(field.getFieldHighlightImageAt(index))) {
tempButtonImages.add(field.getFieldHighlightImageAt(index));
display.panel.addImage(field.getFieldHighlightImageAt(index));
}
break;

default:
ImageMap[] tempImages = tempButtonImages.toArray(new ImageMap[tempButtonImages.size()]);
for(int i = 0; i<tempImages.length; i++) {
display.panel.removeImage(tempImages[i]);
}
tempButtonImages.clear();
break;
}

创建高亮图像的位置

来自字段的代码:

public void makeFieldHighlightImages() {
fieldHighlightImages = new ImageMap[fieldTable.length*fieldTable[0].length];
for(int i = 0; i < fieldTable.length; i++)
for(int j = 0; j < fieldTable[0].length; j++)
fieldHighlightImages[i*fieldTable[0].length+j] =
new ImageMap(Deck.getCardImage(56),
startX+j*horizontalSpacing,
startY+i*verticalSpacing);
}

public ImageMap getFieldHighlightImageAt(int index) {
System.out.println(fieldHighlightImages[index].getImage() + " " + fieldHighlightImages[index].getX() + " " + fieldHighlightImages[index].getY());
return fieldHighlightImages[index];
}

最佳答案

可能更容易的是使用某种后备缓冲区,并且仅在发生变化时才对其进行绘制。

这意味着对paintComponent的调用仅绘制后备缓冲区,使其速度更快,并且如果列表变得很大,则允许在第二个线程中绘制后备缓冲区。

已更新示例

enter image description here

public class BackingBuffer {

public static void main(String[] args) {
new BackingBuffer();
}

public BackingBuffer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}

File[] imageFiles = new File("D:/hold/ScaledImages").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".gif");
}
});

ImagesPane imagesPane = new ImagesPane();
for (File file : imageFiles) {
try {
BufferedImage image = ImageIO.read(file);
imagesPane.addImage(image);
} catch (Exception e) {
e.printStackTrace();
}
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(imagesPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class ImagesPane extends JPanel {

private BufferedImage backingBuffer;
private List<Image> images;
private Timer updateTimer;

public ImagesPane() {
images = new ArrayList<Image>(25);
updateTimer = new Timer(125, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateBuffer();
repaint();
}
});
updateTimer.setRepeats(false);
updateTimer.setCoalesce(true);
}

public void addImage(Image image) {
// You could devise some kind of algorithim to determine if was possible
// to image the image into the existing backing buffer or not.
// It would save having to recreate the backing buffer unless it
// really was required...
images.add(image);
invalidate();
}

public void removeImage(Image image) {
images.remove(image);
invalidate();
}

@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}

protected void updateBuffer() {
if (backingBuffer == null || backingBuffer.getWidth() != getWidth() || backingBuffer.getHeight() != getHeight()) {
if (getWidth() > 0 && getHeight() > 0) {
backingBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
}
if (backingBuffer != null) {
Graphics2D g2d = backingBuffer.createGraphics();
int y = 0;
int x = 0;
int rowHeight = 0;
for (Image image : images) {
rowHeight = Math.max(image.getHeight(this), rowHeight);
if (x + image.getWidth(this) > getWidth() && x != 0) {
x = 0;
y += rowHeight;
}
g2d.drawImage(image, x, y, this);
x += image.getWidth(this);
if (x > getWidth()) {
x = 0;
y += rowHeight;
rowHeight = 0;
}
}
g2d.dispose();
}
}

@Override
public void invalidate() {
// This method can be called repeatly in quick sucession, rather then
// reacting to each call, I want to delay performing the update,
// which might be costly in time and memory until it's all settled down
// a little...
super.invalidate();
updateTimer.restart();
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backingBuffer != null) {
g.drawImage(backingBuffer, 0, 0, this);
}
}
}
}

现在,如果您想使用某种后台线程,我可能会使用 SwingWorker 。您真正需要的唯一额外的东西是您可以引发的某种标志,以便您知道工作人员正在更新缓冲区(因为工作人员是不可重入的(同一实例不能运行两次))

工作人员将创建一个新的临时缓冲区,它可以工作,因为您不想干扰当前正在用于在屏幕上绘画的缓冲区(否则您最终会得到脏油漆)并且一旦完成,您可以在 done 方法中切换缓冲区,并在组件上调用 repaint 以使其在屏幕上更新...

更新了选择突出显示

enter image description here

您可以直接在后备缓冲区中突出显示每个图像,但我个人认为这是一项昂贵的练习,因为您需要在每次点击时更新后备缓冲区。

更好的方法是维护一个键回各个图像的图像边界的Map。当您更新缓冲区时,您将重新创建此 map 。

使用此 map ,您可以确定是否单击了任何“图像”。然后,我会将图像的引用放入列表中,然后在绘制组件时使用该列表......

public class BackingBuffer {

public static void main(String[] args) {
new BackingBuffer();
}

public BackingBuffer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}

File[] imageFiles = new File("C:/hold/ScaledImages").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".gif");
}
});

ImagesPane imagesPane = new ImagesPane();
for (File file : imageFiles) {
try {
BufferedImage image = ImageIO.read(file);
imagesPane.addImage(image);
} catch (Exception e) {
e.printStackTrace();
}
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(imagesPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class ImagesPane extends JPanel {

private Map<Image, Rectangle> mapBounds;
private BufferedImage backingBuffer;
private List<Image> images;
private Timer updateTimer;
private List<Image> selected;

public ImagesPane() {
images = new ArrayList<Image>(25);
selected = new ArrayList<Image>(25);
updateTimer = new Timer(125, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateBuffer();
repaint();
}
});
updateTimer.setRepeats(false);
updateTimer.setCoalesce(true);

addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (mapBounds != null) {
boolean shouldPaint = false;
for (Image image : mapBounds.keySet()) {
Rectangle bounds = mapBounds.get(image);
if (bounds.contains(e.getPoint())) {
if (selected.contains(image)) {
shouldPaint = true;
selected.remove(image);
} else {
shouldPaint = true;
selected.add(image);
}
// In it's current form, there is not overlapping, if you
// have overlapping images, you may want to reconsider this
break;
}
}
if (shouldPaint) {
repaint();
}
}
}
});
}

public void addImage(Image image) {
// You could devise some kind of algorithim to determine if was possible
// to image the image into the existing backing buffer or not.
// It would save having to recreate the backing buffer unless it
// really was required...
images.add(image);
invalidate();
}

public void removeImage(Image image) {
images.remove(image);
if (mapBounds != null) {
mapBounds.remove(image);
}
if (selected.contains(image)) {
selected.remove(image);
}
invalidate();
}

@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}

protected void updateBuffer() {
if (backingBuffer == null || backingBuffer.getWidth() != getWidth() || backingBuffer.getHeight() != getHeight()) {
if (getWidth() > 0 && getHeight() > 0) {
backingBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
}
if (backingBuffer != null) {
mapBounds = new WeakHashMap<Image, Rectangle>(images.size());
Graphics2D g2d = backingBuffer.createGraphics();
int y = 0;
int x = 0;
int rowHeight = 0;
for (Image image : images) {
rowHeight = Math.max(image.getHeight(this), rowHeight);
if (x + image.getWidth(this) > getWidth() && x != 0) {
x = 0;
y += rowHeight;
}
mapBounds.put(image, new Rectangle(x, y, image.getWidth(this), image.getHeight(this)));
g2d.drawImage(image, x, y, this);
x += image.getWidth(this);
if (x > getWidth()) {
x = 0;
y += rowHeight;
rowHeight = 0;
}
}
g2d.dispose();
}
}

@Override
public void invalidate() {
// This method can be called repeatly in quick sucession, rather then
// reacting to each call, I want to delay performing the update,
// which might be costly in time and memory until it's all settled down
// a little...
super.invalidate();
updateTimer.restart();
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backingBuffer != null) {
g.drawImage(backingBuffer, 0, 0, this);
if (selected != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(UIManager.getColor("List.selectionBackground"));
for (Image image : selected) {
Rectangle bounds = mapBounds.get(image);
if (bounds != null) {
Composite composite = g2d.getComposite();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.fill(bounds);
g2d.setComposite(composite);
g2d.draw(bounds);
}
}
}
}
}
}
}

关于Java - Lists 和 Graphics2D 的分层问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13328707/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com