簡體   English   中英

java- repaint() 方法行為不端 - 2?

[英]java- repaint() method is misbehaving - 2?

這個問題是java-repaint() 方法的擴展,行為不端? (閱讀它,是可選的)

我正在開發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中。

Output:

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

現在,如果我從Thread中刪除label.repaint() ,則不會重新繪制JSlider

Output:

Slider re-painted
Slider re-painted

repaint()方法應該像這樣工作嗎?

在我的最后一個問題中,有人告訴我使用Layout Manager ,當我使用GridLayout只是為了檢查它是否是解決方案時,它就起作用了!

只有JLabel被重新繪制。

但是我想在JSlider上重疊JLabel ,所以我想到了使用JLayeredPane 而現在,問題又回來了。

我該如何解決這個問題?

底線:如何在JSlider上重疊JLabel而不會導致repaint()方法行為不端?

或者

repaint()方法是這樣工作的嗎?

正如評論中已經提到的,重新繪制JSlider的原因是它與JLabel有重疊的邊界。 Even though your label doesn't paint over the area of the slider swing will still mark the overlapping area as dirty (ie the overlapping part of the slider will need to be repainted) because swing doesn't know that you are only painting in one組件的一部分。

要減少重繪次數,您需要縮小JLabel的大小。 最好只通過調用它的getPreferredSize()方法來達到它需要的大小。 然后,您可以通過移動 label 的位置來移動文本。

此外,您不應該在普通的Thread中對 gui 進行更新。 請改用javax.swing.Timer 它確保對 gui 的所有更新都發生在 swing 事件線程上,這是它們應該進行的地方。

對您的代碼進行這些調整后,slider 僅重新繪制,而 label 實際上在視覺上超過 slider。

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");
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM