Java,paintComponent 中的 setForeground 融化 CPU
Java, setForeground in paintComponent melts CPU
我在查找/创建支持所有旧 JLabel 功能(Html 标记)的带有阴影的 JLabel 时遇到了问题。所以我尝试了这个,它看起来不错,而且 JLabel 像以前一样工作。
public class SLabel extends JLabel {
public SLabel() {
super();
}
@Override
public void paintComponent(Graphics g) {
// Use Foregroundcolor for the text
// Use Backgroundcolor for the shadow
Color c = getForeground();
setForeground(getBackground());
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create(-2, -2, getWidth() - 1, getHeight() - 1);
setForeground(c); //<-Remove this line and CPU acts normal
super.paintComponent(g2.create());
g2.dispose();
}
}
但我最近买了一台 windows 10 的新电脑,我在显示此 JLabel 时观察到 cpu 使用率非常高(随后是很大的风扇噪音)。
似乎 setForeground(c)
是增加 CPU 使用率的代码行。
知道为什么吗,带有 HTML 标记的阴影 JLabel 的任何替代代码示例或我的代码的改进?
是的,这就是它的作用。绘画应该只是简单地绘制当前状态,它永远不应该尝试改变组件的状态,因为这会产生新的绘画请求
你真正需要做的是首先生成一个 "snapshot" 标签,它成为你想要生成的 "effect" 的一部分,然后将其绘制到提供的 Graphics
调用 paintComponent
时的上下文,例如...
DropShadowLabel
import java.awt.*;
import java.awt.image.BufferedImage;
public class DropShadowLabel extends AbstractEffectLabel {
private int shadowSize;
private Color shadowColor;
private float shadowAlpha;
public DropShadowLabel() {
setShadowSize(2);
setShadowColor(Color.BLACK);
setShadowAlpha(0.5f);
}
@Override
protected BufferedImage applyEffectTo(BufferedImage img) {
return ImageEffectUtilities.applyDropShadow(img, getShadowSize(), getShadowColor(), getShadowAlpha());
}
@Override
public Insets getEffectInsets() {
return new Insets(0, 0, (getShadowSize() * 2), (getShadowSize() * 2));
}
public void setShadowAlpha(float value) {
if (shadowAlpha != value) {
float old = shadowAlpha;
shadowAlpha = value;
firePropertyChange("shadowAlpha", old, value);
invalidate();
repaint();
}
}
public void setShadowColor(Color value) {
if (shadowColor != value) {
Color old = shadowColor;
shadowColor = value;
firePropertyChange("shadowColor", old, value);
invalidate();
repaint();
}
}
public void setShadowSize(int value) {
if (shadowSize != value) {
int old = shadowSize;
shadowSize = value;
updateRendererSize();
firePropertyChange("shadowSize", old, value);
invalidate();
repaint();
}
}
public float getShadowAlpha() {
return shadowAlpha;
}
public Color getShadowColor() {
return shadowColor;
}
public int getShadowSize() {
return shadowSize;
}
}
抽象效果标签
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JLabel;
public abstract class AbstractEffectLabel extends JComponent {
private JLabel renderer;
private BufferedImage imgCache;
public AbstractEffectLabel() {
}
protected JLabel getRenderer() {
if (renderer == null) {
renderer = new JLabel();
renderer.setHorizontalTextPosition(JLabel.LEFT);
renderer.setVerticalTextPosition(JLabel.TOP);
}
return renderer;
}
@Override
public void setForeground(Color fg) {
super.setForeground(fg);
getRenderer().setForeground(fg);
}
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
getRenderer().setBackground(bg);
}
@Override
public Font getFont() {
return getRenderer().getFont();
}
public void setHorizontalAlignment(int alignment) {
getRenderer().setHorizontalAlignment(alignment);
}
public void setVerticalAlignment(int alignment) {
getRenderer().setVerticalAlignment(alignment);
}
public void setHorizontalTextPosition(int alignment) {
getRenderer().setHorizontalTextPosition(alignment);
}
public void setVerticalTextPosition(int alignment) {
getRenderer().setVerticalTextPosition(alignment);
}
public int getHorizontalAlignment() {
return getRenderer().getHorizontalAlignment();
}
public int getVerticalAlignment() {
return getRenderer().getVerticalAlignment();
}
public int getHorizontalTextPosition() {
return getRenderer().getHorizontalTextPosition();
}
public int getVerticalTextPosition() {
return getRenderer().getVerticalTextPosition();
}
@Override
public void setFont(Font font) {
super.setFont(font);
getRenderer().setFont(font);
updateRendererSize();
}
@Override
public void invalidate() {
imgCache = null;
super.invalidate();
}
public void setText(String text) {
getRenderer().setText(text);
updateRendererSize();
invalidate();
repaint();
}
public String getText() {
return getRenderer().getText();
}
protected abstract BufferedImage applyEffectTo(BufferedImage img);
protected BufferedImage getImageCache() {
if (imgCache == null) {
JLabel renderer = getRenderer();
imgCache = ImageEffectUtilities.createCompatibleImage(Math.max(1, renderer.getWidth()), Math.max(renderer.getHeight(), 1));
Graphics2D g2d = imgCache.createGraphics();
renderer.setForeground(getForeground());
renderer.paint(g2d);
g2d.dispose();
// imgCache = GlowEffectFactory.applyDropShadow(imgCache, getShadowSize(), getShadowColor(), getShadowAlpha());
imgCache = applyEffectTo(imgCache);
}
return imgCache;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Rectangle bounds = UIUtilities.getSafeBounds(this);
g2d.drawImage(getImageCache(), bounds.x, bounds.y, this);
}
public abstract Insets getEffectInsets();
protected void updateRendererSize() {
Dimension prefSize = getRenderer().getPreferredSize();
Insets insets = getEffectInsets();
prefSize.width += (insets.left + insets.right);
prefSize.height += (insets.top + insets.bottom);
getRenderer().setSize(prefSize);
setPreferredSize(prefSize);
setMinimumSize(prefSize);
}
}
ImageEffectUtilities
import com.jhlabs.image.GaussianFilter;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.ImageIcon;
public class ImageEffectUtilities {
public static BufferedImage applyDropShadow(BufferedImage imgMaster, int size, Color color, float opactity) {
return applyEffect(imgMaster, 0, 0, size, color, opactity);
}
protected static BufferedImage applyEffect(BufferedImage imgMaster, int xOffset, int yOffset, int size, Color color, float opactity) {
BufferedImage imgShadow = generateShadow(imgMaster, size, color, opactity);
BufferedImage imgCombined = createCompatibleImage(imgShadow);
Graphics2D g2d = imgCombined.createGraphics();
GraphicsUtilities.applyQualityRenderingHints(g2d);
g2d.drawImage(imgShadow, -(size / 2), -(size / 2), null);
g2d.drawImage(imgMaster, xOffset, yOffset, null);
g2d.dispose();
return imgCombined;
}
public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {
int imgWidth = imgSource.getWidth() + (size * 2);
int imgHeight = imgSource.getHeight() + (size * 2);
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgMask.createGraphics();
int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
g2.drawImage(imgSource, x, y, null);
g2.dispose();
// ---- Blur here ---
BufferedImage imgGlow = generateBlur(imgMask, (size * 2), color, alpha);
// ---- Blur here ----
return imgGlow;
}
public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgBlur.createGraphics();
g2.drawImage(imgSource, 0, 0, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2.setColor(color);
g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public static BufferedImage createCompatibleImage(int width, int height) {
return createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static Rectangle getSafeBounds(JComponent comp) {
Insets insets = comp.getInsets();
return getSafeBounds(insets, comp.getBounds());
}
public static Rectangle getSafeBounds(Insets insets, Rectangle bounds) {
int x = insets.left;
int y = insets.top;
int width = bounds.width - (insets.left + insets.right);
int height = bounds.height - (insets.top + insets.bottom);
return new Rectangle(x, y, width, height);
}
}
您还需要 JHLabs Filters
扩展示例
JLabel
是一个复杂的组件,有图标支持,文本和图标定位。我按原样编写上面代码的主要原因是因为我真的不想重新实现很多工作,还因为标签可以呈现 html 以及标签的渲染方式呈现方式与 Graphics#drawString
不同(不知道为什么,就是这样)。
下面是一个扩展示例,其中我为 AbstractEffectLabel
添加了 icon
支持,为了比较,底部的只是一个普通的旧 JLabel
当使用不同的颜色调用 setForeground
时,会触发重绘,因此您会不断触发重绘。参见 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/javax/swing/JComponent.java#JComponent.setForeground%28java.awt.Color%29
我在查找/创建支持所有旧 JLabel 功能(Html 标记)的带有阴影的 JLabel 时遇到了问题。所以我尝试了这个,它看起来不错,而且 JLabel 像以前一样工作。
public class SLabel extends JLabel {
public SLabel() {
super();
}
@Override
public void paintComponent(Graphics g) {
// Use Foregroundcolor for the text
// Use Backgroundcolor for the shadow
Color c = getForeground();
setForeground(getBackground());
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create(-2, -2, getWidth() - 1, getHeight() - 1);
setForeground(c); //<-Remove this line and CPU acts normal
super.paintComponent(g2.create());
g2.dispose();
}
}
但我最近买了一台 windows 10 的新电脑,我在显示此 JLabel 时观察到 cpu 使用率非常高(随后是很大的风扇噪音)。
似乎 setForeground(c)
是增加 CPU 使用率的代码行。
知道为什么吗,带有 HTML 标记的阴影 JLabel 的任何替代代码示例或我的代码的改进?
是的,这就是它的作用。绘画应该只是简单地绘制当前状态,它永远不应该尝试改变组件的状态,因为这会产生新的绘画请求
你真正需要做的是首先生成一个 "snapshot" 标签,它成为你想要生成的 "effect" 的一部分,然后将其绘制到提供的 Graphics
调用 paintComponent
时的上下文,例如...
DropShadowLabel
import java.awt.*;
import java.awt.image.BufferedImage;
public class DropShadowLabel extends AbstractEffectLabel {
private int shadowSize;
private Color shadowColor;
private float shadowAlpha;
public DropShadowLabel() {
setShadowSize(2);
setShadowColor(Color.BLACK);
setShadowAlpha(0.5f);
}
@Override
protected BufferedImage applyEffectTo(BufferedImage img) {
return ImageEffectUtilities.applyDropShadow(img, getShadowSize(), getShadowColor(), getShadowAlpha());
}
@Override
public Insets getEffectInsets() {
return new Insets(0, 0, (getShadowSize() * 2), (getShadowSize() * 2));
}
public void setShadowAlpha(float value) {
if (shadowAlpha != value) {
float old = shadowAlpha;
shadowAlpha = value;
firePropertyChange("shadowAlpha", old, value);
invalidate();
repaint();
}
}
public void setShadowColor(Color value) {
if (shadowColor != value) {
Color old = shadowColor;
shadowColor = value;
firePropertyChange("shadowColor", old, value);
invalidate();
repaint();
}
}
public void setShadowSize(int value) {
if (shadowSize != value) {
int old = shadowSize;
shadowSize = value;
updateRendererSize();
firePropertyChange("shadowSize", old, value);
invalidate();
repaint();
}
}
public float getShadowAlpha() {
return shadowAlpha;
}
public Color getShadowColor() {
return shadowColor;
}
public int getShadowSize() {
return shadowSize;
}
}
抽象效果标签
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JLabel;
public abstract class AbstractEffectLabel extends JComponent {
private JLabel renderer;
private BufferedImage imgCache;
public AbstractEffectLabel() {
}
protected JLabel getRenderer() {
if (renderer == null) {
renderer = new JLabel();
renderer.setHorizontalTextPosition(JLabel.LEFT);
renderer.setVerticalTextPosition(JLabel.TOP);
}
return renderer;
}
@Override
public void setForeground(Color fg) {
super.setForeground(fg);
getRenderer().setForeground(fg);
}
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
getRenderer().setBackground(bg);
}
@Override
public Font getFont() {
return getRenderer().getFont();
}
public void setHorizontalAlignment(int alignment) {
getRenderer().setHorizontalAlignment(alignment);
}
public void setVerticalAlignment(int alignment) {
getRenderer().setVerticalAlignment(alignment);
}
public void setHorizontalTextPosition(int alignment) {
getRenderer().setHorizontalTextPosition(alignment);
}
public void setVerticalTextPosition(int alignment) {
getRenderer().setVerticalTextPosition(alignment);
}
public int getHorizontalAlignment() {
return getRenderer().getHorizontalAlignment();
}
public int getVerticalAlignment() {
return getRenderer().getVerticalAlignment();
}
public int getHorizontalTextPosition() {
return getRenderer().getHorizontalTextPosition();
}
public int getVerticalTextPosition() {
return getRenderer().getVerticalTextPosition();
}
@Override
public void setFont(Font font) {
super.setFont(font);
getRenderer().setFont(font);
updateRendererSize();
}
@Override
public void invalidate() {
imgCache = null;
super.invalidate();
}
public void setText(String text) {
getRenderer().setText(text);
updateRendererSize();
invalidate();
repaint();
}
public String getText() {
return getRenderer().getText();
}
protected abstract BufferedImage applyEffectTo(BufferedImage img);
protected BufferedImage getImageCache() {
if (imgCache == null) {
JLabel renderer = getRenderer();
imgCache = ImageEffectUtilities.createCompatibleImage(Math.max(1, renderer.getWidth()), Math.max(renderer.getHeight(), 1));
Graphics2D g2d = imgCache.createGraphics();
renderer.setForeground(getForeground());
renderer.paint(g2d);
g2d.dispose();
// imgCache = GlowEffectFactory.applyDropShadow(imgCache, getShadowSize(), getShadowColor(), getShadowAlpha());
imgCache = applyEffectTo(imgCache);
}
return imgCache;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Rectangle bounds = UIUtilities.getSafeBounds(this);
g2d.drawImage(getImageCache(), bounds.x, bounds.y, this);
}
public abstract Insets getEffectInsets();
protected void updateRendererSize() {
Dimension prefSize = getRenderer().getPreferredSize();
Insets insets = getEffectInsets();
prefSize.width += (insets.left + insets.right);
prefSize.height += (insets.top + insets.bottom);
getRenderer().setSize(prefSize);
setPreferredSize(prefSize);
setMinimumSize(prefSize);
}
}
ImageEffectUtilities
import com.jhlabs.image.GaussianFilter;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.ImageIcon;
public class ImageEffectUtilities {
public static BufferedImage applyDropShadow(BufferedImage imgMaster, int size, Color color, float opactity) {
return applyEffect(imgMaster, 0, 0, size, color, opactity);
}
protected static BufferedImage applyEffect(BufferedImage imgMaster, int xOffset, int yOffset, int size, Color color, float opactity) {
BufferedImage imgShadow = generateShadow(imgMaster, size, color, opactity);
BufferedImage imgCombined = createCompatibleImage(imgShadow);
Graphics2D g2d = imgCombined.createGraphics();
GraphicsUtilities.applyQualityRenderingHints(g2d);
g2d.drawImage(imgShadow, -(size / 2), -(size / 2), null);
g2d.drawImage(imgMaster, xOffset, yOffset, null);
g2d.dispose();
return imgCombined;
}
public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {
int imgWidth = imgSource.getWidth() + (size * 2);
int imgHeight = imgSource.getHeight() + (size * 2);
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgMask.createGraphics();
int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
g2.drawImage(imgSource, x, y, null);
g2.dispose();
// ---- Blur here ---
BufferedImage imgGlow = generateBlur(imgMask, (size * 2), color, alpha);
// ---- Blur here ----
return imgGlow;
}
public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgBlur.createGraphics();
g2.drawImage(imgSource, 0, 0, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2.setColor(color);
g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public static BufferedImage createCompatibleImage(int width, int height) {
return createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static Rectangle getSafeBounds(JComponent comp) {
Insets insets = comp.getInsets();
return getSafeBounds(insets, comp.getBounds());
}
public static Rectangle getSafeBounds(Insets insets, Rectangle bounds) {
int x = insets.left;
int y = insets.top;
int width = bounds.width - (insets.left + insets.right);
int height = bounds.height - (insets.top + insets.bottom);
return new Rectangle(x, y, width, height);
}
}
您还需要 JHLabs Filters
扩展示例
JLabel
是一个复杂的组件,有图标支持,文本和图标定位。我按原样编写上面代码的主要原因是因为我真的不想重新实现很多工作,还因为标签可以呈现 html 以及标签的渲染方式呈现方式与 Graphics#drawString
不同(不知道为什么,就是这样)。
下面是一个扩展示例,其中我为 AbstractEffectLabel
添加了 icon
支持,为了比较,底部的只是一个普通的旧 JLabel
当使用不同的颜色调用 setForeground
时,会触发重绘,因此您会不断触发重绘。参见 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/javax/swing/JComponent.java#JComponent.setForeground%28java.awt.Color%29