首页 > 解决方案 > java- repaint() 方法行为不端 - 2?

问题描述

这个问题是java-repaint() 方法 的扩展,行为不端?(阅读它,是可选的)

我正在做一个Music Player

我正在使用JSlider搜索栏并使用 aJLabel在屏幕上绘制文本,例如歌曲名称。

我是新手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();
}
    
}

问题是,当我调用它时repaint()JLabel它会自动重新绘制JSlider,即使它JSlider不包含在JLabel.

输出 :

Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........

现在,如果我label.repaint()从 中删除Thread,则JSlider不会重新绘制。

输出:

Slider re-painted
Slider re-painted

repaint()方法应该像这样工作吗?

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

只是JLabel被重新粉刷了。

但我想在 上重叠JLabelJSlider所以我想到了使用JLayeredPane. 而现在,问题又回来了。

我该如何解决这个问题?

底线:如何JLabelJSlider不导致repaint()方法不当的情况下重叠?

或者

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

标签: javaswinggraphics2djlayeredpanenull-layout-manager

解决方案


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

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

此外,您不应该在 plain 中对 gui 进行更新Thread。改为使用javax.swing.Timer。它确保对 gui 的所有更新都发生在摇摆事件线程上,这是应该进行的地方。

在对您的代码进行这些调整后,只有在标签实际上在滑块上方时才重新绘制滑块。

public class JSliderDemo extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(JSliderDemo::new);
    }

    private final JLabel label = new CustomLabel();

    public JSliderDemo() {
        setSize(400, 400);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        createWindow();
        setVisible(true);
        startTimer();
    }

    public void createWindow() {
        JPanel panel = new JPanel(new BorderLayout());

        JLayeredPane layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize(new Dimension(300, 310));

        label.setLocation(0, 0);
        label.setBorder(new LineBorder(Color.RED));
        label.setSize(label.getPreferredSize());

        layeredPane.add(createSlider(), Integer.valueOf(50));
        layeredPane.add(label, Integer.valueOf(100));

        panel.add(layeredPane);
        setContentPane(panel);
    }

    protected JSlider createSlider() {
        JSlider seek = new CustomSlider();
        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 LineBorder(Color.BLUE));
        return seek;
    }

    private void startTimer() {
        new Timer(100, e -> {
            int y = label.getY();
            int maxY = label.getParent().getHeight();
            if (y == maxY) {
                y = -label.getHeight();
            }
            label.setLocation(label.getX(), y + 1);
            label.repaint();
        }).start();
    }

    private static class CustomLabel extends JLabel {

        protected CustomLabel() {
            setFont(new Font("Calibri", Font.PLAIN, 16));
            setText("Song Name");
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("Painting Label");
        }
    }

    protected static class CustomSlider extends JSlider {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("Painting Slider");
        }
    }
}

推荐阅读