Java 在JScrollPane的视口上绘制静态图像
我正试图在一个JScrollPane上画一个红方块。下面的代码在这方面做得不错,但有时当我滚动视口太快时,红方块会上下跳跃 这让我感到奇怪,因为JScrollPane本身是静止的,所以我假设Swing不会试图在它内部绘制的组件周围移动。我猜实际发生的是,红方块与视口关联,视口显示的图形确实在移动 不管怎样,我如何防止红方块跳来跳去,并成功地在列表上画出一个红方块?也许我采取了完全错误的方法Java 在JScrollPane的视口上绘制静态图像,java,swing,jscrollpane,Java,Swing,Jscrollpane,我正试图在一个JScrollPane上画一个红方块。下面的代码在这方面做得不错,但有时当我滚动视口太快时,红方块会上下跳跃 这让我感到奇怪,因为JScrollPane本身是静止的,所以我假设Swing不会试图在它内部绘制的组件周围移动。我猜实际发生的是,红方块与视口关联,视口显示的图形确实在移动 不管怎样,我如何防止红方块跳来跳去,并成功地在列表上画出一个红方块?也许我采取了完全错误的方法 package components; import java.awt.*; import java.
package components;
import java.awt.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.*;
@SuppressWarnings("serial")
public class DialogWithScrollPane extends JFrame {
public DialogWithScrollPane() {
super();
setResizable(false);
Container pane = getContentPane();
Vector<Object> listOfStuff = new Vector<Object>();
for (int i = 0; i < 100; i++) {
listOfStuff.add(Integer.toString(i));
}
final JScrollPane scrollPane = new JScrollPane() {
public void paint(Graphics g) {
System.out.println("JScrollPane.paint() called.");
super.paint(g);
g.setColor(Color.red);
g.fillRect(20, 50, 100, 200);
}
};
JList list = new JList(listOfStuff) {
public void paint(Graphics g) {
System.out.println("JList.paint() called.");
super.paint(g);
// Well, I could do this...
//
// scrollPane.repaint();
//
// ...and it would solve the problem, but it would also result in an
// infinite recursion since JScrollPane.paint() would call this
// function again.
}
};
// Repaint the JScrollPane any time the viewport is moved or an item in the
// list is selected.
scrollPane.getViewport().addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
scrollPane.repaint();
}
});
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
scrollPane.repaint();
}
});
scrollPane.setViewportView(list);
pane.add(scrollPane);
setMinimumSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(500, 250);
setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DialogWithScrollPane();
}
});
}
}
封装组件;
导入java.awt.*;
导入java.util.Vector;
导入javax.swing.*;
导入javax.swing.event.*;
@抑制警告(“串行”)
公共类DialogWithScrollPane扩展了JFrame{
公共对话框WithScrollPane(){
超级();
可设置大小(假);
容器窗格=getContentPane();
Vector listOfStuff=新向量();
对于(int i=0;i<100;i++){
add(Integer.toString(i));
}
final JScrollPane scrollPane=新JScrollPane(){
公共空间涂料(图g){
System.out.println(“调用了JScrollPane.paint()”);
超级油漆(g);
g、 setColor(Color.red);
g、 fillRect(20,50,100,200);
}
};
JList list=新JList(listofsuff){
公共空间涂料(图g){
System.out.println(“调用了JList.paint()”);
超级油漆(g);
//好吧,我可以这么做。。。
//
//scrollPane.repaint();
//
//…这会解决问题,但也会导致
//无限递归,因为JScrollPane.paint()会调用
//再次发挥作用。
}
};
//在移动视口或视图中的项目时重新绘制JScrollPane
//列表已选中。
scrollPane.getViewport().addChangeListener(新的ChangeListener()){
公共无效状态已更改(更改事件e){
scrollPane.repaint();
}
});
addListSelectionListener(新的ListSelectionListener(){
public void值已更改(ListSelectionEvent e){
scrollPane.repaint();
}
});
scrollPane.setViewportView(列表);
添加(滚动窗格);
设置最小尺寸(新尺寸(300300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
设置位置(500250);
setVisible(真);
}
公共静态void main(字符串[]args){
javax.swing.SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
新建对话框WithScrollPane();
}
});
}
}
JScrollPane应该在JViewport后面绘制,JViewport应该在列表后面绘制。我猜这只是因为您正在重写paint而不是paintComponent,并一直在JScrollPane上调用repaint,以便它在绘制组件后再次绘制自己
也许您希望使用JLayeredPane,让它握住JScrollPane并在其上绘制
编辑:或者我现在看到的mre建议的glasspane,但我担心如果您这样做,并将glasspane设置为可见,您将失去与底层滚动窗格交互的能力
编辑2例如
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Vector;
import javax.swing.*;
@SuppressWarnings("serial")
public class DialogWithScrollPane2 extends JFrame {
public DialogWithScrollPane2() {
super();
//setResizable(false);
final JPanel pane = (JPanel) getContentPane();
Vector<Object> listOfStuff = new Vector<Object>();
for (int i = 0; i < 100; i++) {
listOfStuff.add(Integer.toString(i));
}
final JScrollPane scrollPane = new JScrollPane();
JList list = new JList(listOfStuff);
scrollPane.setViewportView(list);
final JPanel blueRectPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(20, 50, 100, 200);
}
};
blueRectPanel.setOpaque(false);
final JLayeredPane layeredPane = new JLayeredPane();
layeredPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(blueRectPanel, JLayeredPane.PALETTE_LAYER);
layeredPane.addComponentListener(new ComponentAdapter() {
private void resizeLayers() {
final JViewport viewport = scrollPane.getViewport();
scrollPane.setBounds(layeredPane.getBounds());
blueRectPanel.setBounds(viewport.getBounds());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
blueRectPanel.setBounds(viewport.getBounds());
}
});
}
@Override
public void componentShown(ComponentEvent e) {
resizeLayers();
}
@Override
public void componentResized(ComponentEvent e) {
resizeLayers();
}
});
pane.add(layeredPane);
setPreferredSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocation(500, 250);
setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DialogWithScrollPane2();
}
});
}
}
import java.awt.*;
导入java.awt.event.ComponentAdapter;
导入java.awt.event.ComponentEvent;
导入java.util.Vector;
导入javax.swing.*;
@抑制警告(“串行”)
公共类对话框WithScrollPane2扩展了JFrame{
公共对话框WithScrollPane2(){
超级();
//可设置大小(假);
最终JPanel窗格=(JPanel)getContentPane();
Vector listOfStuff=新向量();
对于(int i=0;i<100;i++){
add(Integer.toString(i));
}
final JScrollPane scrollPane=新JScrollPane();
JList list=新的JList(listOfStuff);
scrollPane.setViewportView(列表);
最终JPanel blueRectPanel=新JPanel(){
@凌驾
受保护组件(图形g){
超级组件(g);
g、 setColor(Color.blue);
g、 圆角(20、50、100、200);
}
};
blueRectPanel.set不透明(false);
最终JLayeredPane layeredPane=新JLayeredPane();
layeredPane.add(滚动窗格,JLayeredPane.DEFAULT_层);
layeredPane.add(blueRectPanel、JLayeredPane.PALETTE_层);
layeredPane.addComponentListener(新的ComponentAdapter(){
私有void resizeLayers(){
final JViewport viewport=scrollPane.getViewport();
scrollPane.setBounds(layeredPane.getBounds());
blueRectPanel.setBounds(viewport.getBounds());
SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
blueRectPanel.setBounds(viewport.getBounds());
}
});
}
@凌驾
显示的公共无效组件(组件事件e){
resizeLayers();
}
@凌驾
公共无效组件已恢复(组件事件e){
resizeLayers();
}
});
窗格。添加(分层窗格);
setPreferredSize(新尺寸(300300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
包装();
设置位置(500250);
setVisible(真);
}
公共静态void main(字符串[]args){
javax.swing.SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
新对话框WithCrollPane2();
}
});
}
}
此解决方案对此可能过于强大,但您可以尝试在玻璃窗格上绘制。例如-但我可能错了,这个解决方案可能不适用。@masson:请参阅“编辑我的答案”,我不确定您的编辑是否正确。在该示例中,我确实有意阻止所有输入事件,而玻璃窗格确实拦截了它们,但我不确定它是否会阻塞