gpt4 book ai didi

java - 当我在 JPanel 上绘制背景图像时,它在 Windows 下的行为与在 Linux 下的行为不同

转载 作者:行者123 更新时间:2023-11-30 03:42:02 25 4
gpt4 key购买 nike

我正在开发一个工作程序(注意:我无法共享完整的代码,因为它在很大程度上是 protected 工作产品,但我会分享我能分享的一切)。在应用程序中,我有 JPanel,它们应用了背景图像。其中一些面板还附加了鼠标监听器,我的管理层希望有一个视觉线索,表明可以单击面板来启动操作。为此,我在带有背景图像的 JPanel 顶部覆盖了一个透明 JPanel,并为其附加了一个 MouseListener,从而关闭 mouseEntered/Exited 事件。当鼠标进入图像面板时,覆盖的面板将从透明切换为半透明,当鼠标退出时又返回。

在 Linux 下,这工作得很好。在Windows下……幸好我是秃头,所以我不能把头发扯下来。似乎正在发生的事情是,当我移动鼠标时,正在发生某种图像缓存,并且 mouseEnter 事件导致鼠标一秒前的任何内容都被绘制到框架中;即,如果我将鼠标放在 GUI 上附近的按钮上,然后将鼠标放在面板上,我将看到该按钮与周围的 GUI 一起出现在面板中。

图像面板包含在不透明的 JInternalFrame 中。

另一件事需要注意,如果我在应用程序中执行某些操作会导致图像发生更改(例如,从 JComboBox 中进行新选择),图像将按预期重新绘制。无论问题是什么,它似乎与突出显示以及如何重新绘制/重绘图像有关。

我没有为 Windows 做哪些我应该做的事情?

提前致谢。

Here is a link to some images 。 Start.png 是面板打开时在两个操作系统中的样子。 GoodMouseEnter.png 是 Linux 下 mouseEnter 事件的样子。 BadMouseEnter.png 和 badMouseExit.png 是 Windows 下的样子。

这是我用来创建图像面板的类(编辑:此示例是独立的):

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ImageTest {
JFrame frm = null;
ImagePanel imgP = null;

public static void main(String[] args) throws MalformedURLException
{
ImageTest it = new ImageTest();
it.initialize();
}

public void initialize() throws MalformedURLException
{
String path = "file:/C:/CylinderTank.png";
URL imagePath = new URL(path);
System.out.println(imagePath.toString());
frm = new JFrame();
imgP = new ImagePanel(true);
int fW = 500;
int fH = 700;
int pW = 450;
int pH = 650;

frm.setLayout(null);
frm.setPreferredSize(new Dimension(fW,fH));
frm.setSize(fW,fH);

imgP.getFilterPanel().addMouseListener(new PanelListener());
imgP.useCustomSizing(pW, pH);
imgP.setImageURL(imagePath);
imgP.setBounds(0, 0, pW, pH);

frm.add(imgP);

frm.pack();
frm.setVisible(true);
}

private class PanelListener implements MouseListener {

public PanelListener() { }
@Override
public void mouseClicked(MouseEvent e) { }
@Override
public void mousePressed(MouseEvent e) { }
@Override
public void mouseReleased(MouseEvent e) { }
@Override
public void mouseEntered(MouseEvent e)
{
imgP.highlightImage(true);
imgP.repaint();
}
@Override
public void mouseExited(MouseEvent e)
{
imgP.highlightImage(false);
imgP.repaint();
}
}
}



@SuppressWarnings("serial")
class ImagePanel extends JPanel implements ImageObserver {
private final JPanel filterPanel;
private BufferedImage image;
private Dimension panelSize;
private final Toolkit kit;
private boolean highlight = false;
private URL imagePath;
private int imgW, imgH;
private final Color blueFilter = new Color(0, 0, 255, 38);
private final Color redFilter = new Color(255, 0, 0, 38);
private final Color greenFilter = new Color(0, 255, 0, 38);
private final Color clear = new Color(0, 0, 0, 0);
private final Color bgColor = new Color(116, 169, 255, 255);
private boolean customSize = false;

public ImagePanel(boolean opaque)
{
super();
this.kit = Toolkit.getDefaultToolkit();
setLayout(null);
setOpaque(opaque);
setBackground(bgColor);
filterPanel = new JPanel();
filterPanel.setBackground(clear);
}

public ImagePanel(URL imagePath, boolean opaque)
{
super();
this.imagePath = imagePath;
this.kit = Toolkit.getDefaultToolkit();
setLayout(null);
setOpaque(opaque);
setBackground(bgColor);
filterPanel = new JPanel();
filterPanel.setBackground(clear);

readImage();

}

@Override
protected void paintComponent(Graphics g)
{
Graphics2D g2D = (Graphics2D) g;

if (highlight)
filterPanel.setBackground(blueFilter);
else
filterPanel.setBackground(clear);

int X = 0, Y = 0;
if (image != null)
{
image.flush();
kit.prepareImage(image, -1, -1, this);

if (customSize)
{
X = (panelSize.width - imgW) / 2;
Y = (panelSize.height - imgH) / 2;
}

if (isOpaque())
g2D.drawImage(image, X, Y, bgColor, this);
else
g2D.drawImage(image, X, Y, this);
}
else
super.paintComponent(g2D);
}

public void highlightImage(boolean highlight)
{
this.highlight = highlight;

}

private void readImage()
{
try
{
image = ImageIO.read(imagePath);
imgW = image.getWidth();
imgH = image.getHeight();

if (customSize)
panelSize = getPreferredSize();
else
panelSize = new Dimension(imgW, imgH);

setPreferredSize(panelSize);
setMinimumSize(panelSize);
setMaximumSize(panelSize);

int X = (panelSize.width - imgW) / 2;
int Y = (panelSize.height - imgH) / 2;
filterPanel.setBounds(X, Y, imgW, imgH);

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


public void setImageURL(URL img)
{
this.imagePath = img;
readImage();
}

public Dimension getDisplayedImageSize()
{
if (image == null)
return null;

return new Dimension(imgW, imgH);
}

public JPanel getFilterPanel()
{
return filterPanel;
}

public void useCustomSizing(int W, int H)
{
if (W < 0)
W = getPreferredSize().width;
if (H < 0)
H = getPreferredSize().height;

if ((W>0) || (H>0))
customSize = true;

Dimension cDim = new Dimension(W,H);
setPreferredSize(cDim);
setMinimumSize(cDim);
setMaximumSize(cDim);

repaint();
}
}//end class ImagePanel

最佳答案

一连串的问题出现了......

  1. 过度使用 null 布局,我会回过头来讨论...
  2. 使用“覆盖”面板
  3. 在 Paint 方法的上下文中修改组件
  4. 依赖“神奇”数字而不是已知值
  5. 打破油漆链...

所有这些事情都在密谋反对你......

您需要知道的第一件事是 Swing 只知道如何绘制不透明或透明组件,并且仅当这些组件被标记为不透明时才知道。如果您使用带有 alpha 值的颜色,Swing 不知道它也需要在组件下绘制。

您需要知道的第二件事是 Graphics 上下文是共享资源。也就是说,在绘制周期期间更新的每个组件都会获得相同的图形上下文。

主要问题是,您的 filterPanel 使用 alpha 颜色,但 Swing 不知道它应该在其下方绘制,因此它只是“填充”具有您选择的颜色的可用区域,但因为它是 alpha 颜色,所以它不会完全清理 Graphics 上下文,因此您最终会留下绘画伪影...

事实是,您不需要 filterPane,或者更重要的是,不需要按您现在的方式使用它。您永远不应该从绘制方法中更新任何组件的状态,这将导致组件每次都请求重新绘制,这将快速消耗您的 CPU 周期,直到您的系统无法运行...

您可以使用类似的方法获得类似的结果...

@Override
protected void paintComponent(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);

int X = 0, Y = 0;
if (image != null) {

if (customSize) {
X = (panelSize.width - imgW) / 2;
Y = (panelSize.height - imgH) / 2;
}

g2D.drawImage(image, X, Y, this);
}


if (highlight) {
g2D.setColor(blueFilter);
g2D.fillRect(X, Y, image.getWidth(), image.getHeight());
}

}

看看Painting in AWT and Swing , Performing Custom Painting2D Graphics了解更多详情。

对预先计算值的依赖也可能会给您带来问题。组件的大小应通过使用其 getWidthgetHeight 属性来确定,因为这些值可能在绘制周期之间发生变化...

我还鼓励您使用 ImageIO 而不是 Toolkit,它会...

  1. 返回完整实现的图像,而不是将加载卸载到后台线程
  2. 如果由于某种原因无法读取文件,则引发异常,而不是默默地失败......

参见Reading/Loading an Image了解更多详情

这是我如何解决该问题的基本示例......

Mouse in the house

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MouseOverTest {

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

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

try {
BufferedImage background = ImageIO.read(new File("C:\\hold\\thumbnails\\_MTCGAC__Pulling_Cords_by_Dispozition.png"));

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane(background));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}

public static class TestPane extends JPanel {

protected static final Color BLUE_FILTER = new Color(0, 0, 255, 38);

private BufferedImage background;
private Rectangle imageBounds;
private boolean mouseInTheHouse;

public TestPane(BufferedImage background) {
this.background = background;
MouseAdapter ma = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
mouseInTheHouse = getImageBounds().contains(e.getPoint());
repaint();
}

@Override
public void mouseExited(MouseEvent e) {
mouseInTheHouse = false;
repaint();
}

};
addMouseMotionListener(ma);
addMouseListener(ma);
}

@Override
public Dimension getPreferredSize() {
return background == null ? new Dimension(200, 200) : new Dimension(background.getWidth(), background.getHeight());
}

@Override
public void invalidate() {
imageBounds = null;
super.invalidate();
}

protected Rectangle getImageBounds() {

if (imageBounds == null) {

if (background != null) {

int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
imageBounds = new Rectangle(x, y, background.getWidth(), background.getHeight());

} else {

imageBounds = new Rectangle(0, 0, 0, 0);

}

}

return imageBounds;

}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Rectangle bounds = getImageBounds();
if (background != null) {
g2d.drawImage(background, bounds.x, bounds.y, this);
}
if (mouseInTheHouse) {
g2d.setColor(BLUE_FILTER);
g2d.fill(bounds);
}
g2d.dispose();
}

}

}

关于java - 当我在 JPanel 上绘制背景图像时,它在 Windows 下的行为与在 Linux 下的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26618566/

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