java-repaint()方法行为不正常-2?

java-repaint()方法行为不正常-2?,java,swing,graphics2d,jlayeredpane,null-layout-manager,Java,Swing,Graphics2d,Jlayeredpane,Null Layout Manager,这个问题是问题的延伸 (阅读它是可选的) 我正在开发一款音乐播放器 我使用JSlider作为搜索栏,并使用JLabel在屏幕上绘制文本,例如歌曲名称 我不熟悉Graphics2D 以下是最小化的代码: public class JSliderDemo extends JFrame { JLabel label; JSlider seek = new JSlider(); int y = 10; public JSliderDemo() { setSize(400, 400

这个问题是问题的延伸 (阅读它是可选的)

我正在开发一款
音乐播放器

我使用
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
,即使
JLabel
中不包含
JSlider

输出:

Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........
现在,如果我从
线程中删除
label.repaint()
,则
JSlider
不会重新绘制

输出:

Slider re-painted
Slider re-painted
repaint()
方法应该是这样工作的吗

在我的最后一个问题中,我被告知使用
layoutmanager
,当我使用
GridLayout
只是为了检查它是否是解决方案时,它就起作用了

仅重新绘制了
JLabel

但是我想在
JSlider
上重叠
JLabel
,所以我想使用
JLayeredPane
。现在,问题又回来了

我怎样才能解决这个问题

底线:如何在
JSlider
上重叠
JLabel
,而不导致
repaint()
方法行为不当


repaint()
方法是这样工作的吗?

正如评论中已经提到的,重新绘制
JSlider
的原因是它与
JLabel
的边界重叠。即使您的标签没有在滑块区域上绘制,swing仍会将重叠区域标记为脏(即滑块的重叠部分需要重新绘制),因为swing不知道您仅在组件的一个部分上绘制

要减少重绘量,您需要将
JLabel的大小减小。通过调用其
getPreferredSize()
方法,最好只将其设置为需要的大小。然后可以通过移动标签的位置来移动文本

另外,您不应该在普通的
线程中更新gui。改用
javax.swing.Timer
。它确保对gui的所有更新都发生在swing事件线程上,这是进行更新的地方

在对代码进行这些调整后,滑块仅在标签实际位于滑块上方时重新绘制

公共类jslideremo扩展了JFrame{
公共静态void main(字符串[]args){
invokeLater(JSliderDemo::new);
}
私有最终JLabel标签=新CustomLabel();
公共JSliderDemo(){
设置大小(400400);
setLocationRelativeTo(空);
setDefaultCloseOperation(在关闭时处理);
createWindow();
setVisible(真);
startTimer();
}
public void createWindow(){
JPanel panel=newjpanel(newborderlayout());
JLayeredPane layeredPane=新的JLayeredPane();
layeredPane.setPreferredSize(新维度(300310));
label.setLocation(0,0);
label.setboorder(新线条边框(颜色为红色));
label.setSize(label.getPreferredSize());
layeredPane.add(createSlider(),Integer.valueOf(50));
layeredPane.add(标签,Integer.valueOf(100));
panel.add(分层窗格);
设置内容窗格(面板);
}
受保护的JSlider CreateSloider(){
JSlider seek=new CustomSlider();
seek.setOrientation(JProgressBar.HORIZONTAL);
seek.set不透明(false);
seek.setLocation(10,50);
seek.setSize(300,20);
seek.setMajorTickSpacing(0);
seek.setMinorTickSpacing(0);
seek.setMinimum(0);
seek.setMaximum(1000);
seek.setboorder(新的线边框(颜色.蓝色));
寻回;
}
私有void startTimer(){
新定时器(100,e->{
int y=label.getY();
int maxY=label.getParent().getHeight();
如果(y==maxY){
y=-label.getHeight();
}
label.setLocation(label.getX(),y+1);
label.repaint();
}).start();
}
私有静态类CustomLabel扩展了JLabel{
受保护的自定义标签(){
setFont(新字体(“Calibri”,Font.PLAIN,16));
setText(“歌曲名称”);
}
@凌驾
受保护组件(图形g){
超级组件(g);
System.out.println(“喷漆标签”);
}
}
受保护的静态类CustomSlider扩展JSlider{
@凌驾
受保护组件(图形g){
超级组件(g);
System.out.println(“绘制滑块”);
}
}
}

我认为Swing的RePrimtMeor也可以考虑脏区域,因为您自己处理组件的大小和位置,是否有可能重叠并导致RePrtMeStor重新绘制脏区域中的所有组件?问题是,当我调用RePrimeTo()对于JLabel,即使JSlider未包含在JLabel中,它也会自动使用它重新绘制JSlider。-为什么这是个问题?。JLabel是透明的。绘制透明组件时,Swing首先需要重新绘制不透明标签的父组件,以便正确绘制背景。为什么要扩展JLabel以绘制文本字符串?如果需要动画,请使用常规JLabel并更改标签的位置。@camickr我不明白!在这个答案中,您说过,您不应该设置组件的位置。这是布局管理器的工作,但这里您建议我手动更改
JLabel
的位置以模拟动画。标签和滑块的边界重叠。重新绘制图形时,此swing需要重新绘制这两个图形