【发布时间】:2020-06-29 03:26:35
【问题描述】:
这个问题是java- repaint() method is misbehaving?的延伸 (阅读,可选)
我正在处理Music Player
我使用JSlider 作为搜索栏并使用JLabel 在屏幕上绘制文本,例如歌曲名称。
我是Graphics2D的新手
这是最小化的代码:
public class JSliderDemo extends JFrame
{
JLabel label;
JSlider seek = new JSlider();
int y = 10;
public JSliderDemo()
{
setSize(400, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
createWindow();
setVisible(true);
startThread();
}
public void createWindow()
{
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(true);
panel.setBackground(Color.BLUE);
panel.setBorder(new LineBorder(Color.YELLOW));
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 310));
label = new Component();
label.setSize(300, 300);
createSlider();
layeredPane.add(seek, new Integer(50));
layeredPane.add(label, new Integer(100));
panel.add(layeredPane);
add(panel);
}
protected void createSlider()
{
seek.setUI(new SeekBar(seek, 300, 10, new Dimension(20, 20), 5,
Color.DARK_GRAY, Color.RED, Color.RED));
seek.setOrientation(JProgressBar.HORIZONTAL);
seek.setOpaque(false);
seek.setLocation(10, 50);
seek.setSize(300, 20);
seek.setMajorTickSpacing(0);
seek.setMinorTickSpacing(0);
seek.setMinimum(0);
seek.setMaximum(1000);
seek.setBorder(new MatteBorder(5, 5, 5, 5, Color.CYAN));
}
protected void startThread()
{
Thread thread = new Thread(new Runnable(){
@Override
public void run()
{
try
{
while(true)
{
if(y == label.getHeight()){y = 1;}
label.repaint();
y += 1;
Thread.sleep(100);
}
}
catch(Exception ex){}
}
});
thread.start();
}
protected class Component extends JLabel
{
@Override
public void paintComponent(Graphics g)
{
Graphics2D gr = (Graphics2D) g;
gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gr.setColor(Color.RED);
gr.setFont(new Font("Calibri", Font.PLAIN, 16));
gr.drawString("Song Name", 50, y);
gr.dispose();
}
}
public static void main(String[] args)
{
new JSliderDemo();
}
}
问题是,当我为JLabel 调用repaint() 时,它会自动用它重新绘制JSlider,即使JSlider 不包含在JLabel 中。
输出:
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........
现在,如果我从Thread 中删除label.repaint(),则不会重新绘制JSlider。
输出:
Slider re-painted
Slider re-painted
repaint() 方法应该像这样工作吗?
在我的最后一个问题中,有人告诉我使用Layout Manager,而当我使用GridLayout 只是为了检查它是否是解决方案时,它就起作用了!
仅重绘了JLabel。
但是我想在JSlider上重叠JLabel,所以我想到了使用JLayeredPane。而现在,问题又回来了。
我该如何解决这个问题?
底线:如何在JSlider 上重叠JLabel 而不会导致repaint() 方法行为不端?
或
repaint() 方法是这样工作的吗?
【问题讨论】:
-
我认为swing的RepaintManager也可以考虑脏区,而且由于你自己处理组件的大小和位置,它们是否有可能重叠并导致RepaintManager重新绘制脏区中的所有组件?
-
问题是,当我为 JLabel 调用 repaint() 时,即使 JSlider 不包含在 JLabel 中,它也会自动用它重新绘制 JSlider。 - 为什么会出现问题? JLabel 是透明的。在绘制透明组件时,Swing首先需要重新绘制不透明标签的父组件,以便正确绘制背景。
-
为什么要扩展 JLabel 来绘制文本字符串?如果您想要动画,请使用常规 JLabel 并更改标签的位置。
-
@camickr 我不明白!在这个答案中,stackoverflow.com/a/62631255/13824394 你说,你不应该设置组件的位置。这是布局管理器的工作,但在这里你建议我手动更改
JLabel的位置以模拟动画。 -
标签和滑块的边界重叠。重绘标签时,这种摆动将需要重绘它们,因为单独重绘标签可能会覆盖滑块的一部分。请注意,即使重新绘制了标签,它实际上也只会重新绘制与滑块重叠的部分(因此实际上可能不会做任何事情)。
标签: java swing graphics2d jlayeredpane null-layout-manager