我有一个swing应用程序,它在JScrollPane中包含一个SVG画布。应用程序修改显示的SVG文档,这也会导致文档大小的更改。此大小更改需要反映在应用程序中。调整SVG画布的大小,滚动JScrollPane的视口,以便它显示画布的正确部分。
然而,这导致了类似“视觉跳跃”的东西,因为用户首先看到画布大小的变化,然后看到滚动操作。
有没有一种方法可以告诉java停止处理给定组件(及其子组件)上的渲染事件,并且仅在完成修改后恢复,以便只显示所有修改的结果?
以下是我在伪代码方面的想法:
myScrollPane.suspendRendering();
svgDocument.changeSize();
svgCanvas.changeSize();
myScrollPane.getViewport().scrollToCorrectPosition;
myScrollPane.resumeRendering();
我试过使用myScrollPane。setIgnoreRepaint(true),但在这里似乎没有任何效果(即使我再也没有将ignoreRepaint
设置为false
)。
这里是一个SSCCE,它试图模拟这种效果:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Jumping extends JFrame {
private JButton innerPanel= new JButton("Some silly, useless text, just for fun. And it goes on even longer. But that's not a problem.");
private JScrollPane scrollPane= new JScrollPane(innerPanel);
private JButton btnJump= new JButton("Jump");
private int lastWidth= 1024;
public Jumping(){
this.setLayout(new BorderLayout());
this.add(btnJump, BorderLayout.NORTH);
this.add(scrollPane, BorderLayout.CENTER);
this.scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
this.scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.innerPanel.setPreferredSize(new Dimension(1024, 768));
this.innerPanel.setSize(1024, 768);
this.innerPanel.setMinimumSize(new Dimension(1024, 768));
this.innerPanel.setMaximumSize(new Dimension(1024, 768));
this.setSize(640, 480);
this.btnJump.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try{
System.err.println("> actionPerfomed");
//resize the canvas
new Thread(){
public void run() {
System.err.println("> SwingWorker.doInBackground "+SwingUtilities.isEventDispatchThread());
SwingUtilities.invokeLater(new Runnable(){
public void run(){
System.err.println("> resize canvas "+SwingUtilities.isEventDispatchThread());
final int newWidth= (int) (lastWidth * 1.5);
innerPanel.setSize(newWidth, 768);
innerPanel.setPreferredSize(new Dimension(newWidth, 768));
innerPanel.setMinimumSize(new Dimension(newWidth, 768));
innerPanel.setMaximumSize(new Dimension(newWidth, 768));
lastWidth= newWidth;
System.err.println("< resize canvas "+SwingUtilities.isEventDispatchThread());
}
});
//scroll to correct position
SwingUtilities.invokeLater(new Runnable(){
public void run(){
System.err.println("> scroll to pos "+SwingUtilities.isEventDispatchThread());
try {
System.err.println("< sleep "+SwingUtilities.isEventDispatchThread());
Thread.sleep(500);
System.err.println("> sleep "+SwingUtilities.isEventDispatchThread());
} catch (InterruptedException ex) {
ex.printStackTrace();
}
final Point viewPos= scrollPane.getViewport().getViewPosition();
scrollPane.getViewport().setViewPosition(new Point(viewPos.x + 50, viewPos.y));
System.err.println("< scroll to pos "+SwingUtilities.isEventDispatchThread());
}
});
System.err.println("< SwingWorker.doInBackground "+SwingUtilities.isEventDispatchThread());
}
}.start();
System.err.println("< actionPerfomed "+SwingUtilities.isEventDispatchThread());
}catch(Exception ex){
ex.printStackTrace();
}
}
});
}
public static void main(String[] args){
final Jumping frame= new Jumping();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
通常,一种可能性是使用自定义重新绘制管理器。下面是一个过于简单且非常未优化的示例:
public class FreezableRepaintManager extends RepaintManager {
final Set<Component> frozen = new HashSet<Component>();
public void freeze(Container c) {
frozen.add(c);
for (Component child : c.getComponents()) {
if (child instanceof Container) {
freeze((Container) child);
} else {
frozen.add(child);
}
}
}
public void thaw(final Container c) {
frozen.remove(c);
for (Component child : c.getComponents()) {
if (child instanceof Container) {
thaw((Container) child);
} else {
frozen.remove(child);
}
}
c.repaint();
}
@Override
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
if (!frozen.contains(c)) {
super.addDirtyRegion(c, x, y, w, h);
}
}
}
使用repaitmanager在代码早期的某个地方设置重绘管理器。setCurrentManager()
然后在开始一系列操作之前使用冻结(componentTree)
,然后在完成后使用解冻(componentTree)
。
这适用于大多数组件,但不幸的是,JScrollPane还不够,因为它的绘图比大多数组件都复杂。因此,您可能需要一个JScrollPane,它的createViewport()返回一个可以抑制blit的视图端口,例如:
class FreezableViewport extends JViewport {
private boolean frozen;
public void freeze() {
frozen = true;
}
public void thaw() {
frozen = false;
}
@Override
protected boolean computeBlit(int dx, int dy, Point blitFrom,
Point blitTo, Dimension blitSize, Rectangle blitPaint) {
if (frozen) {
return false;
}
return super.computeBlit(dx, dy, blitFrom, blitTo, blitSize, blitPaint);
}
}
这也需要在一系列修改之前冻结,并且使用上述重新绘制管理器,在重新绘制管理器的解冻方法被调用之前解冻。
问题内容: 我有一个swing应用程序,该应用程序将命令发送到服务器并接收XML格式的结果。我需要通过XSLT将其转换为HTML,然后在面板上显示结果HTML。问题在于,唯一能够显示HTML的Swing组件- JEditorPane- 将URL或javax.swing.text.StyledDocument用作源。带有URL的选项对我不起作用,因为我必须先将html作为文件保存在文件系统中,并且我
问题内容: 我想使用Express 3 呈现原始页面,如下所示: 这是我配置服务器以呈现原始HTML页面的方式(此过时的问题启发了这一点): 不幸的是,使用此配置,页面将挂起并且永远无法正确呈现。我做错了什么?如何在没有精美的渲染引擎(如Jade和EJS)的情况下使用Express3渲染原始HTLM? 问题答案: 如果您实际上不需要将数据注入模板,则express中最简单的解决方案是使用静态文件服
渲染节点 精灵 文字 骨骼动画 蒙版节点 裁剪节点 帧动画 图集 纹理
我在Java中的JLabel存在一个渲染问题:我使用oberver observable模式,当我的模型通知我的视图JLabel已经更改了JLabel的内容,或者特别是在我的JLabel区域中显示的内容是随机的时。有时它渲染另一个面板中按钮的一部分,有时它渲染我在视图的其他组件中设置的颜色!但是,如果我最小化然后最大化我的帧,所有的渲染都是正确的。 对不起,我的英语不好。 EDIT这是我的JPan
原子操作 是个不可分割的操作。 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的; 它要么就是做了,要么就是没做,只有这两种可能。 如果从对象读取值的加载操作是 原子 的,而且对这个对象的所有修改操作也是 原子 的, 那么加载操作得到的值要么是对象的初始值,要么是某次修改操作存入的值。 另一方面,非原子操作可能会被另一个线程观察到只完成一半。 如果这个操作是一个存储操作,那么其他线
我在Kubuntu18.04中用Java8 Update181开发了一个应用程序。在我的开发PC中,我有英特尔i3-6100和英特尔®高清图形530。所有的图形都是使用swing完成的,有了这个硬件配置,一切都按它应该的方式工作。 在生产PC上,我有英特尔(R)赛扬(R)CPU J1900与英特尔®高清图形英特尔原子®处理器Z3700系列。使用相同的OS和java版本运行相同的代码,我注意到在Sw