也许我遇到了错误或更可能做错了什么;)
我尝试使用 JScrollPanel
翻译用户绘制的 JPanel
的内容。在面板内部,我想通过 Graphics 类的 getClipBounds 方法访问可见区域,以提高渲染性能。
搜索 SO 会带来很多涉及 JScrollPane
的结果,但没有提到剪辑边界的问题。谷歌也一样。
用户绘制的面板
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Content extends JPanel {
@Override
protected void paintChildren(Graphics g) {
super.paintChildren(g);
// intense clip bounds dependent rendering here
System.out.println(g.getClipBounds());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(2000,2000);
}
}
主框架设置
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
public class ClipBoundsIssue {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClipBoundsIssue window = new ClipBoundsIssue();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ClipBoundsIssue() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
Content content = new Content();
scrollPane.setViewportView(content);
}
}
重现
只需运行代码,移动滚动条之一并检查 System.out
的控制台输出。下图描绘了在 x 轴上滚动条形图。
实际System.out
结果
产生以下结果
java.awt.Rectangle[x=0,y=0,width=416,height=244]
java.awt.Rectangle[x=416,y=0,width=16,height=244]
java.awt.Rectangle[x=432,y=0,width=15,height=244]
java.awt.Rectangle[x=447,y=0,width=16,height=244]
java.awt.Rectangle[x=463,y=0,width=15,height=244]
预期结果
我希望边界的宽度保持不变。但它从 416 变成了 16。
现在的问题是
有谁知道为什么会发生这种情况,或者如何避免这种情况?
废弃的WA
一个可能的解决方法是查找视口(viewport)的 View 边界。但如果可能的话,我想避免 Content
类进行任何此类查找。另一种选择是将信息传递到 Content
类中,但我也想避免这样做。
最佳答案
为什么?它太简单了,很难解释,但让我尝试一下。I would have expected to have the width of the bounds to keep the same.
当您滚动时,如果缓慢滚动,则仅出现 JPanel 的一小部分新部分。
生成的输出绝对正确:
java.awt.Rectangle[x=0,y=0,width=416,height=244]
控件首次显示,需要完全重绘
java.awt.Rectangle[x=416,y=0,width=16,height=244]
您向右滚动了 16 个像素,因此只有控件的窄条必须是重新绘制。
您必须了解这些坐标与您的控件相关,该控件的大小设置为 2000x2000 像素。
尝试滚动使用此代码创建的窗口,您将看到我在说什么:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class ScrollPaneRepaintDemo extends JPanel {
public ScrollPaneRepaintDemo() {
setPreferredSize(new Dimension(2000,2000));
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new JScrollPane(new ScrollPaneRepaintDemo()));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
@Override protected void paintComponent(Graphics g) {
Rectangle clip = g.getClipBounds();
g.setColor(new Color(new Random().nextInt()));
g.fillRect(clip.x, clip.y, clip.width, clip.height);
}
}
顺便说一下 - 它之所以如此工作是因为 JPanel 的内部实现。如果您扩展 JComponent,则整个视口(viewport)将被裁剪。我还补充说,JPanel 在调整大小时会完全重新绘制,其优化仅针对滚动。
关于java - getClipBounds 与 JScrollPane 结合使用错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24233722/