在 JScrollPane 的视口上绘制静态图像
我正在尝试在 JScrollPane 上绘制一个红色方块。我下面的代码做得很好,但有时当我滚动视口太快时,红色方块会向上或向下跳跃。
这让我感到很奇怪,因为 JScrollPane 本身是静止的,所以我认为 Swing 不会尝试移动在其中绘制的组件。我猜测实际发生的情况是红色方块与视口相关联,视口显示移动的图形。
无论如何,如何防止红色方块跳跃并成功在列表上绘制红色方块?也许我完全采取了错误的方法。
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();
}
});
}
}
I am trying to draw a red square over a JScrollPane. The code I have below does an okay job of this, but sometimes when I scroll the viewport too fast, the red square jumps up or down.
This struck me as odd since the JScrollPane itself is stationary, so I assumed Swing would not try to move around the components painted within it. I'm guessing that what's actually happening is that the the red square gets associated with viewport, which display graphics that do move.
Anyway, how do I prevent the red square from jumping around and successfully draw a red square over the list? Maybe I'm taking the wrong approach altogether.
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();
}
});
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
JScrollPane 应该在 JViewport 后面绘制,而 JViewport 应该在列表后面绘制。我猜这只是有效的,因为您覆盖了paint而不是paintComponent,并始终在JScrollPane上调用repaint,以便它在绘制其组件后再次绘制自身。
也许您想使用 JLayeredPane 并让它容纳 JScrollPane,并在其上绘画。
编辑:或者玻璃窗格,正如我现在看到的mre建议的那样,但我担心如果你这样做,并将玻璃窗格设置为可见,你将失去与底层滚动窗格交互的能力。
编辑2
例如,
The JScrollPane should be painting behind the JViewport which should be painting behind the list. I'm guessing that this is only working because you're overriding paint and not paintComponent and calling repaint on the JScrollPane all the time so that it paints itself again after its components are painted.
Perhaps you want to use a JLayeredPane and have it hold the JScrollPane, and paint on it.
edit: or the glasspane as I now see that mre suggests, but I'm afraid if you do that, and set the glasspane visible, you'll lose the ability to interact with the underlying scrollpane.
Edit 2
For e.g.,