【问题标题】:How to force calling paintComponent?如何强制调用paintComponent?
【发布时间】:2013-11-25 18:59:20
【问题描述】:

我有一个覆盖了paintComponent() 的JLabel。我希望它被强制调用,因为更新我的标签UI 的代码就是这个事件。我怎样才能强制它调用和更新UI? (顺便说一下,重绘不起作用!)

这是我的代码:

BufferedImage background;
String Uri;

public CustomClockLabel(String Uri){
    init(Uri);
    this.Uri = Uri;
}

public void init(String Uri){
    try {
        URL inp = CustomClockLabel.class.getResource(Uri);
        background = ImageIO.read(inp);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
protected void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    if(background != null){
        g2.drawImage(background, 0, 0,getWidth(),getHeight(), this);
    }
    g2.dispose();
    super.paintComponent(g);
}

这是更新标签的代码,它被递归调用:

lblHour1 = new CustomClockLabel("/icons/noa_en/"+Hour.charAt(0)+".png");
lblHour1.repaint();
lblHour2 = new CustomClockLabel("/icons/noa_en/"+Hour.charAt(1)+".png");
lblHour2.repaint();
lblMin1 = new CustomClockLabel("/icons/noa_en/"+Minute.charAt(0)+".png");
lblMin1.repaint();
lblMin2 = new CustomClockLabel("/icons/noa_en/"+Minute.charAt(1)+".png");
lblMin1.repaint();

【问题讨论】:

    标签: java swing icons jlabel paintcomponent


    【解决方案1】:

    您可能会误以为创建新标签会更新屏幕上的内容,这样做...

    lblHour1 = new CustomClockLabel("/icons/noa_en/"+Hour.charAt(0)+".png");
    lblHour2 = new CustomClockLabel("/icons/noa_en/"+Hour.charAt(1)+".png");
    lblMin1 = new CustomClockLabel("/icons/noa_en/"+Minute.charAt(0)+".png");
    lblMin2 = new CustomClockLabel("/icons/noa_en/"+Minute.charAt(1)+".png");
    

    将更改变量的引用,因此它们将不再是与您添加到屏幕的变量相同的变量。

    假设上面的变量已经被添加到屏幕上,你可以简单地使用类似的东西来更新它们......

    lblHour1.init(new ImageIcon("/icons/noa_en/"+Hour.charAt(0)+".png"));
    lblHour2.init(new ImageIcon("/icons/noa_en/"+Hour.charAt(1)+".png"));
    lblMin1.init(new ImageIcon("/icons/noa_en/"+Minute.charAt(0)+".png"));
    lblMin2.init(new ImageIcon("/icons/noa_en/"+Minute.charAt(1)+".png"));
    revalidate();
    repaint();
    

    如果失败,您应该尝试设置一个标签边框的属性,以便查看它是否真的被添加到屏幕上。

    更新

    在对您提供的少量代码进行了一些实验之后,这里有一些更多建议...

    1. 如前所述,请确保您首先调用super.paintComponent,因为此方法的工作之一是清除准备绘制的图形...
    2. 确保为组件提供合适的大小提示,以便布局管理器对您希望组件的大小有所了解。这可确保组件的大小不适合0x0

    以下示例非常简单,但会使用您提供的(很少)代码并从中构建一个可运行的示例...

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.net.URL;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class PaintComponentTest {
    
        public static void main(String[] args) {
            new PaintComponentTest();
        }
    
        private int time = 0;
    
        public PaintComponentTest() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    final CustomClockLabel counter = new CustomClockLabel("/icons/0.png");
                    Timer timer = new Timer(1000, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            time++;
                            if (time > 9) {
                                time = 0;
                            }
                            counter.init("/icons/" + Integer.toString(time) + ".png");
                            counter.repaint();
                        }
                    });
                    timer.start();
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(counter);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class CustomClockLabel extends JPanel {
    
            BufferedImage background;
            String Uri;
    
            public CustomClockLabel(String Uri) {
                init(Uri);
                this.Uri = Uri;
            }
    
            public void init(String Uri) {
                try {
                    URL inp = getClass().getResource(Uri);
                    background = ImageIO.read(inp);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(100, 100);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g.create();
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
                if (background != null) {
                    g2.drawImage(background, 0, 0, getWidth(), getHeight(), this);
                }
                g2.dispose();
            }
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      在有问题的组件上调用repaint() 将强制它再次绘制。

      您遇到的问题似乎不是重新绘制,因为您实际上是在更改面板上的标签。确保删除旧标签并添加新标签并致电revalidate()。 (您发布的代码看起来只是在更新标签引用,而不是在面板上实际更改它们。)

      总体而言,通过让您的 CustomClockLabel 类接受一个更改图像的参数,从而允许您调用 repaint(),可以显着改进设计。

      【讨论】:

      • 你如何尝试repait()你的标签?它必须适合你。
      • 我确实在代码中添加了重绘,但它不起作用。即使重新验证它也没有改变。
      • 您是否在重新验证之前删除并添加了组件?如果不是,则没有什么新东西需要验证。
      • 因为我使用的是组布局,如果我删除它,它会弄乱我的 UI。
      • 这正是我提到你确实有一个糟糕的设计问题的原因,并且可以通过让你的时钟组件根据方法调用更改它们的显示而不是每次更新都创建一个新对象来改进。
      【解决方案3】:
      lblHour1 = new CustomClockLabel("/icons/noa_en/"+Hour.charAt(0)+".png");
      

      上面的代码没有做任何事情。所做的只是创建一个新组件。但该组件并未添加到 GUI 中,因此它显然不会重新绘制。

      您的课程中没有任何内容会导致它需要重新绘制,因此您的问题没有意义。你有一个设计问题。我认为没有任何理由创建自定义标签。

      如果您想更改图像,则只需使用带有图标的标准 JLabel。然后要更改图像,您只需使用setIcon(...) 方法,标签会自动重新绘制。

      【讨论】:

      • setIcon 不是一个选项,因为做出了设计选择。另请参阅我对代码所做的更改
      • @armin,你看我的回答了吗?我告诉你问题是什么。 Don't create a new component。这是一种资源浪费,并且根据您的代码,您已经有了对标签的引用。相反,您应该更新现有组件的属性。因此,您需要在方法中使用类似“changeImage(...). Inside that method you save the image and then invoke repaint()` 的方法。外部代码不应调用 repaint()。我只是想对您的设计选择发表评论,但 MadProgramer 击败了我去吧。
      • @camickr 是的,我知道,现在将重新设计它。看起来没有其他办法。
      【解决方案4】:

      (顺便说一下,重绘不起作用!)

      如果不是,那么我唯一可以怀疑的问题在于您的绘画顺序:您在绘制图像后调用super.paintComponent(g);。如果您的标签是不透明的并且有背景色,那么您将看不到图像,因为后面的绘画super.paintComponent(g) 将绘制在前面的绘画之上。

      尝试更改顺序:

      super.paintComponent(g);
      
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      
      if(background != null){
          g2.drawImage(background, 0, 0,getWidth(),getHeight(), this);
      }
      g2.dispose();
      

      【讨论】:

      • 好久不见。你好吗?
      • @MadProgrammer 请问你在哪里(以及你怎么可能有)你找到空闲时间来做一些有趣的事情,就像现在/现在是 hollydays
      • @armin,即使这不起作用,这也是您可能会面临的问题。无论如何,尝试按照其他人的建议更改您的设计。如果没有以正确的方式去做,你就不能指望一件事能奏效。
      • @mKorbel 实际上,这更像是我的妻子在度假(她是全职妈妈),所以我来照顾我们的女儿 ;)
      • @MadProgrammer 什么冬青...什么???这不是 hollydays :-),我有一对一岁的双胞胎,两只蜜蜂从根本上飞向相反的方向
      猜你喜欢
      • 1970-01-01
      • 2021-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-03
      相关资源
      最近更新 更多