- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用 JComponent
with HTML inside it (特别是 JLabel
)来显示和更改一些可能需要换行的文本。不幸的是,当我更改 HTML 时会出现明显的闪烁,因为它正在执行两个布局 + 绘制循环,而不是一个。有什么办法可以避免用错误的布局绘制 JLabel
吗?我试过在 setText
之后调用 jframe.revalidate();
,但没有用。
通过每秒更改 HTML 来演示闪烁的示例代码。我在 paintComponent
期间添加了人工 Thread.sleep
来模拟大型布局树或昂贵的油漆,以便在这个小窗口中可以看到闪烁。在屏幕截图中,左边是正确布局的标签,而右边是在闪烁中捕获的错误屏幕截图。
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class HtmlJLabelFlicker {
static final String text =
"<html>This label is being set to a new value " +
"that needs to wrap. Unfortunately, this causes " +
"two layout + paint cycles instead of just one, " +
"which can cause flicker if the text doesn\u2019t " +
"change very much between refreshes. ";
public static void createUI() {
final JLabel label = new JLabel(text);
final Timer timer = new Timer(1000, new ActionListener() {
int n;
@Override public void actionPerformed(ActionEvent e) {
label.setText(text + n++);
}
});
timer.start();
JFrame jframe = new JFrame();
jframe.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
jframe.addWindowListener(new WindowAdapter() {
@Override public void windowClosed(WindowEvent e) {
timer.stop();
}
});
jframe.setSize(300, 300);
Container content = jframe.getContentPane();
content.add(label);
jframe.setVisible(true);
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
@Override public void run() {
createUI();
}
});
}
}
最佳答案
在将 JLabel 插入树中后尝试 scrollRectToVisible 时,我遇到了与 OP 相同的问题。问题是在布局的 getPreferredSize() 期间,包含 HTML 的 JLabel 在需要换行之前不知道有多少水平空间可用。假设它根本不需要换行,它只是返回一个宽尺寸。然后,在绘制期间,JLabel 的内部 FlowView 将“修复”布局并设置其实际需要的高度,该高度被缓存并在下一次布局迭代时返回。
我使用的解决方案是调用 JLabel.paint,因为似乎没有其他方法可以告诉它以实际可用宽度完成布局。
顺便说一句,其他 UI 系统,例如 WPF’s MeasureOverride , JavaFX’s prefHeight with contentBias和 Android’s measure给措施通过可用空间,这样他们就不会遇到这个问题。
防止闪烁的相关代码如下:
label.setText(text + n++);
// revalidate, but do so synchronously.
Container validateRoot = label;
while (! validateRoot.isValidateRoot()) {
Container parent = validateRoot.getParent();
if (parent == null)
break;
validateRoot = parent;
}
// This first validate() call may be excluded if the width is already correct
validateRoot.validate();
NoopGraphics g = new NoopGraphics(0, 0, label.getWidth(), label.getHeight(), label.getGraphicsConfiguration(), false, false);
label.paint(g);
validateRoot.validate();
// Now you can use the measured bounds for e.g. scrollRectToVisible
NoopGraphics.java:
import java.awt.AlphaComposite;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Collections;
import java.util.Map;
import javax.swing.SwingUtilities;
/**
* A subclass of Graphics2D that returns the correct FontMetrics but does not
* actually paint anything.
*
* @see <a
* href="http://stackoverflow.com/questions/16227877/how-to-update-a-jcomponent-with-html-without-flickering">How
* to update a JComponent with HTML without flickering?</a>
*/
public class NoopGraphics extends Graphics2D {
private Font font;
private Color color = Color.BLACK;
private final Rectangle clip;
private Stroke stroke;
private Paint paint;
private Color background;
private AffineTransform transform = new AffineTransform();
private final RenderingHints renderingHints = new RenderingHints(Collections.<Key,Object>emptyMap());
private Composite composite = AlphaComposite.SrcOver;
private boolean isAntiAliased;
private boolean usesFractionalMetrics;
private GraphicsConfiguration graphicsConfiguration;
public static GraphicsConfiguration getDefaultScreenGraphicsConfiguration() {
GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
return graphicsConfiguration;
}
public NoopGraphics(int x, int y, int width, int height) {
this(x, y, width, height, getDefaultScreenGraphicsConfiguration(), false, false);
}
public NoopGraphics(int x, int y, int width, int height, GraphicsConfiguration graphicsConfiguration, boolean isAntiAliased, boolean usesFractionalMetrics) {
this.graphicsConfiguration = graphicsConfiguration;
this.isAntiAliased = isAntiAliased;
this.usesFractionalMetrics = usesFractionalMetrics;
this.clip = new Rectangle(x, y, width, height);
}
@Override public void setXORMode(Color c1) {}
@Override public void setPaintMode() {}
@Override public Font getFont() {return font;}
@Override public void setFont(Font font) {this.font=font;}
@Override public Color getColor() {return color;}
@Override public void setColor(Color c) {this.color=c;}
@Override public void setClip(int x, int y, int width, int height) {
}
@Override public void setClip(Shape clip) {this.clip.setRect(clip.getBounds());}
@Override public FontMetrics getFontMetrics(Font f) {
// http://stackoverflow.com/questions/2753514/java-friendlier-way-to-get-an-instance-of-fontmetrics
return new Canvas(graphicsConfiguration).getFontMetrics(f);
}
@Override public Rectangle getClipBounds() {return clip.getBounds();}
@Override public Shape getClip() {return clip;}
@Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {}
@Override public void fillRect(int x, int y, int width, int height) {}
@Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {}
@Override public void fillOval(int x, int y, int width, int height) {}
@Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {}
@Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {}
@Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {}
@Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {}
@Override public void drawOval(int x, int y, int width, int height) {}
@Override public void drawLine(int x1, int y1, int x2, int y2) {}
@Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) {return true;}
@Override public boolean drawImage(Image img, int dx1,
int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, ImageObserver observer) {
return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer);
}
@Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
return false;
}
@Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
return drawImage(img, x, y, width, height, null, observer);
}
@Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
return false;
}
@Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
return drawImage(img, x, y, null, observer);
}
@Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {}
@Override public void dispose() {}
@Override public Graphics create() {return this;}
@Override public void copyArea(int x, int y, int width, int height, int dx, int dy) {}
@Override public void clipRect(int x, int y, int width, int height) {SwingUtilities.computeIntersection(x, y, width, height, this.clip);}
@Override public void clearRect(int x, int y, int width, int height) {}
@Override public void translate(double tx, double ty) {getTransform().translate(tx, ty);}
@Override public void translate(int x, int y) {translate((double)x, (double)y);}
@Override public void transform(AffineTransform Tx) {getTransform().concatenate(Tx);}
@Override public void shear(double shx, double shy) {getTransform().shear(shx, shy);}
@Override public void scale(double sx, double sy) {getTransform().scale(sx, sy);}
@Override public void setTransform(AffineTransform Tx) {this.transform = Tx;}
@Override public void setStroke(Stroke s) {this.stroke = s;}
@Override public void setRenderingHints(Map<?, ?> hints) {this.renderingHints.clear(); this.renderingHints.putAll(hints);}
@Override public void setRenderingHint(Key hintKey, Object hintValue) {this.renderingHints.put(hintKey, hintValue);}
@Override public void setPaint(Paint paint) {this.paint = paint;}
@Override public void setComposite(Composite comp) {this.composite = comp;}
@Override public void setBackground(Color color) {this.background = color;}
@Override public void rotate(double theta, double x, double y) {getTransform().rotate(theta, x, y);}
@Override public void rotate(double theta) {getTransform().rotate(theta);}
@Override public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
return false;
}
@Override public AffineTransform getTransform() {return this.transform;}
@Override public Stroke getStroke() {return this.stroke;}
@Override public RenderingHints getRenderingHints() {return renderingHints;}
@Override public Object getRenderingHint(Key hintKey) {return renderingHints.get(hintKey);}
@Override public Paint getPaint() {return this.paint;}
@Override public FontRenderContext getFontRenderContext() {return new FontRenderContext(transform, isAntiAliased, usesFractionalMetrics);}
@Override public GraphicsConfiguration getDeviceConfiguration() {return graphicsConfiguration;}
@Override public Composite getComposite() {return composite;}
@Override public Color getBackground() {return background;}
@Override public void fill(Shape s) {}
@Override public void drawString(AttributedCharacterIterator iterator, float x, float y) {}
@Override public void drawString(AttributedCharacterIterator iterator, int x, int y) {drawString(iterator, (float)x, (float)y);}
@Override public void drawString(String str, float x, float y) {drawString(new AttributedString(str).getIterator(), x, y);}
@Override public void drawString(String str, int x, int y) {drawString(str, (float)x, (float)y);}
@Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) {}
@Override public void drawRenderableImage(RenderableImage img, AffineTransform xform) {}
@Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {}
@Override public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {return false;}
@Override public void drawGlyphVector(GlyphVector g, float x, float y) {}
@Override public void draw(Shape s) {}
@Override public void clip(Shape s) {}
@Override public void addRenderingHints(Map<?, ?> hints) {renderingHints.putAll(hints);}
}
关于java - 如何在不闪烁的情况下使用 HTML 更新 JComponent?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16227877/
我查看了网站上的一些问题,但还没有完全弄清楚我做错了什么。我有一些这样的代码: var mongoose = require('mongoose'), db = mongoose.connect('m
基本上,根据 this bl.ocks,我试图在开始新序列之前让所有 block 都变为 0。我认为我需要的是以下顺序: 更新为0 退出到0 更新随机数 输入新号码 我尝试通过添加以下代码块来遵循上述
我试图通过使用随机数在循环中设置 JSlider 位置来模拟“赛马”的投注结果。我的问题是,当然,我无法在线程执行时更新 GUI,因此我的 JSlider 似乎没有在竞赛,它们从头到尾都在运行。我尝试
该功能非常简单: 变量:$table是正在更新的表$fields 是表中的字段,$values 从帖子生成并放入 $values 数组中而$where是表的索引字段的id值$indxfldnm 是索引
让我们想象一个环境:有一个数据库客户端和一个数据库服务器。数据库客户端可以是 Java 程序或其他程序等;数据库服务器可以是mysql、oracle等。 需求是在数据库服务器上的一个表中插入大量记录。
在我当前的应用程序中,我正在制作一个菜单结构,它可以递归地创建自己的子菜单。然而,由于这个原因,我发现很难也允许某种重新排序方法。大多数应用程序可能只是通过“排序”列进行排序,但是在这种情况下,尽管这
Provisioning Profile 有 key , key 链依赖于它。我想知道 key 什么时候会改变。 Key will change after renew Provisioning Pr
截至目前,我在\server\publications.js 中有我的 MongoDB“选择”,例如: Meteor.publish("jobLocations", function () { r
我读到 UI 应该始终在主线程上更新。但是,当谈到实现这些更新的首选方法时,我有点困惑。 我有各种函数可以执行一些条件检查,然后使用结果来确定如何更新 UI。我的问题是整个函数应该在主线程上运行吗?应
我在代理后面,我无法构建 Docker 镜像。 我试过 FROM ubuntu , FROM centos和 FROM alpine ,但是 apt-get update/yum update/apk
我构建了一个 Java 应用程序,它向外部授权客户端公开网络服务。 Web 服务使用带有证书身份验证的 WS-security。基本上我们充当自定义证书颁发机构 - 我们在我们的服务器上维护一个 ja
因此,我有时会在上传新版本时使用 app_offline.htm 使应用程序离线。 但是,当我上传较大的 dll 时,我收到黄色错误屏幕,指出无法加载 dll。 这似乎与我对 app_offline.
我刚刚下载了 VS Apache Cordova Tools Update 5,但遇到了 Node 和 NPM 的问题。我使用默认的空白 cordova 项目进行测试。 版本 如果我在 VS 项目中对
所以我有一个使用传单库实例化的 map 对象。 map 实例在单独的模板中创建并以这种方式路由:- var app = angular.module('myApp', ['ui', 'ngResour
我使用较早的 Java 6 u 3 获得的帧速率是新版本的两倍。很奇怪。谁能解释一下? 在 Core 2 Duo 1.83ghz 上,集成视频(仅使用一个内核)- 1500(较旧的 java)与 70
我正在使用 angular 1.2 ng-repeat 创建的 div 也包含 ng-click 点击时 ng-click 更新 $scope $scope 中的变化反射(reflect)在使用 $a
这些方法有什么区别 public final void moveCamera(CameraUpdate更新)和public final void animateCamera (CameraUpdate
我尝试了另一篇文章中某人评论中关于如何将树更改为列表的建议。但是,我在某处(或某物)有未声明的变量,所以我列表中的值是 [_G667, _G673, _G679],而不是 [5, 2, 6],这是正确
实现以下场景的最佳方法是什么? 我需要从java应用程序调用/查询包含数百万条记录的数据库表。然后,对于表中的每条记录,我的应用程序应该调用第三方 API 并获取状态字段作为响应。然后我的应用程序应该
只是在编写一些与 java 图形相关的代码,这是我今天的讲座中的非常简单的示例。不管怎样,互联网似乎说更新不会被系统触发器调用,例如调整框架大小等。在这个例子中,更新是由这样的触发器调用的(因此当我只
我是一名优秀的程序员,十分优秀!