java - 尽管使用 flowlayout,JFrame 组件仍能够通过 repaint 调用 PaintComponent

标签 java swing concurrency jframe paintcomponent

我在 FlowLayout 中有一个 JFrame,其中添加了多个 JLabel,但是当我在 JLabels 上调用 repaint 时,它们的paintComponent 没有被调用。如果我删除 FlowLayout,则只有最后添加的 JLabel 会显示并正确重新绘制。我尝试使用面板,但没有成功。但我不确定我是否正确使用它。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import javax.swing.JFrame;

public class RacingLetters {

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                final JFrame jframe = new JFrame();
                jframe.setTitle("Racing letters");
                jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                //jframe.setExtendedState(Frame.MAXIMIZED_BOTH);
                Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
                int x = (int) ((dimension.getWidth() - jframe.getWidth()) / 2);
                int y = (int) ((dimension.getHeight() - jframe.getHeight()) / 2);
                jframe.setLocation(x, y);
                jframe.setMinimumSize(new Dimension(500, 200));
                FlowLayout fl = new FlowLayout();
                jframe.setLayout(fl);
                //jframe.setLayout(null);
                jframe.setVisible(true);    

                StringBuffer[] stringBufferArray = new StringBuffer[20];
                char ch = 'A';

                int yy = 20;
                for (int i = 0; i < 5; i++) {
                    stringBufferArray[i] = new StringBuffer("");
                    BufferThread bt = new BufferThread(stringBufferArray[i], ch, 10, yy);
                    //pane.add(bt);
                    jframe.add(bt);

                    new Thread(bt).start();
                    ch++;
                    yy += 20;
                }

            }
        });

    }
}

..

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;


public class BufferThread extends JLabel implements Runnable {

    char ch;
    StringBuffer sb;
    int x,y;

    BufferThread(StringBuffer sb, char ch,int x, int y) {
        this.sb = sb;
        this.ch = ch;
        this.x = x;
        this.y = y;
    }

    @Override
    public void run() {
        Random rand = new Random();

        for (int i = 0; i < 5; i++) {
            sb.append(ch);
            System.out.println(x + " " + y + " " + ch);
            repaint();

            try {
                Thread.sleep(rand.nextInt(500));
            } catch (InterruptedException ex) {
                Logger.getLogger(BufferThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void paintComponent(Graphics g) {
        //System.out.println(x + " " + y + " " + ch);
        //System.out.println("aaaa");
        //stem.out.println(sb);
        Graphics2D g2 = (Graphics2D) g;

        Font f = new Font("Serif", Font.PLAIN, 24);
        //if (sb.toString().indexOf("E") < 0)
            g2.drawString(sb.toString(), x, y);

    }

}

最佳答案

核心问题是,JLabel 没有向框架的布局管理器提供任何有关其大小的信息。它实际上也没有告诉框架的布局管理器它已更新并且需要调整大小。

为什么你要尝试在标签上绘制文本超出了我的范围,因为这就是标签设计的目的。

处理 Swing 组件时应避免使用 Thread,并应尽可能使用 javax.swing.TimerSwingWorker

import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Ticker {

    public static void main(String[] args) {
        new Ticker();
    }

    public Ticker() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new FlowLayout());
                frame.add(new TickerLabel());
                frame.setSize(100, 100);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TickerLabel extends JLabel {

        private int counter;

        public TickerLabel() {
            Timer timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (counter > 4) {
                        ((Timer)e.getSource()).stop();
                    } else {
                        String text = getText();
                        text += (char)(((int)'A') + counter);
                        setText(text);
                    }
                    counter++;
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

    }

}

关于java - 尽管使用 flowlayout,JFrame 组件仍能够通过 repaint 调用 PaintComponent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15841496/

相关文章:

java - 如何在 SpannableStringBuilder 中将可绘制对象放置在 2 个字符串资源之间而不使用索引号

Java Socket 阻止面板?

java - 向 JTextfield 添加提示文本属性

java - 将 DefaultComboBoxModel 用于 JComboBox

mongodb - MongoDB 上的并发读取操作

java - 全文搜索 api 无法与 objectify java : index. put() 一起使用,抛出 nosuchmethod

java - 下拉刷新时,新获取的数据未显示在回收站列表中

java - 从 Java 调用 MySQL 查询 - 配置 "WHERE"参数

java - 我从基于 Java 的 AWS lambda 处理程序启动一个单独的线程,有时会完成,有时不会,为什么?如何保证线程完成?

c++ - flock 不会阻塞