Java:无法重绘(repaint)?

3

我正在编写一些代码来创建彩色文本可视化效果。下面的代码负责可视化面板,并且 setCT(String c) 方法会被程序中的其他地方(正确地)调用。

不幸的是,在窗口大小未改变时,所需的可视化效果并没有发生。在那之前,该可视化面板只会保持黑色!出了什么问题?我尝试使用 validate() 方法以及像其他指南中所述创建一个新的 Runnable(),但都没有成功。以下是我的代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Visualiser extends JPanel implements ActionListener {

    /**
     * 
     */
    private static final long serialVersionUID = -3936526023655045114L;
    public static final Color DEFAULT_BG_COL = Color.black;
    private static Color bgCol;
    private static String ct;
    private static BufferedImage stat;
    private static boolean doVis=false;
    private Timer refreshTimer=new Timer(100, this);

    public Visualiser() {
        this(200, 250);
    }

    public Visualiser(int w, int h) {

        super.setSize(new Dimension(w, h));
        super.setPreferredSize(new Dimension(w, h));
        bgCol = Visualiser.DEFAULT_BG_COL;      
        super.setBackground(bgCol);
        stat = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        refreshTimer.start();


    }


    /*public void paint(Graphics g) {
     * REPLACED BY paintComponent() METHOD AS PER SUGGESTION
        super.paint(g);
        if (Visualiser.doVis==true) {
            System.out.println("passed doVis test");
            doVis(g);
        }

    }*/

    public void paintComponent(Graphics g) {
        if(Visualiser.doVis) {
            doVis(g);
        }
    }

    public Color getBGCol() {
        return bgCol;
    }

    public void setBGCol(Color b) {
        bgCol = b;
        super.setBackground(bgCol);
    }

    public void doVis(Graphics g) {
        // all of my code to actually paint the visualisation is here
        //doStatic(g);
        // establish the block size and height using length of the string
        int numBlocks = 3*ct.length();
        if (numBlocks != 0) {
            int blockSize = (int) Math.sqrt((this.getWidth()*this.getHeight())/numBlocks) ;
            Graphics2D g2 = stat.createGraphics();
            int blocksX=Math.round(this.getWidth()/blockSize);
            int blocksY=Math.round(this.getHeight()/blockSize);
            char chars[]=ct.toCharArray();
            int c=0;
            int cc=0;
            for(int i = 1; i< blocksX; i++) {
                for(int j=1; j<blocksY; j++) {
                    cc=c+4;
                    if(cc < chars.length) {
                        //System.out.println("char length is: " + chars.length + " and c is: " + c);
                        g2.setColor(new Color((int) chars[c]%255, (int) chars[c+1]%255, (int)chars[c+2]%255));
                        //System.out.println("color: " + g2.getColor().toString());
                    }
                    g2.fill(new Rectangle2D.Double(i*blockSize, j*blockSize, blockSize, blockSize));
                    c++;
                }
            }

            g.drawImage(stat, 0, 0, this);
        }




    }

    private void doStatic(Graphics g) {
        Graphics2D g2 = stat.createGraphics();
        int x=this.getWidth();
        int y=this.getHeight();
        //System.out.println("x, y: " + x + " " + y);
        for (int i=1; i<x; i++) {
            for(int j=1; j<y; j++) {
                g2.setColor(new Color(getRandom(0, 255), getRandom(0,255), getRandom(0,255)));
                g2.fill(new Rectangle2D.Double(i, j, 1, 1));
            }
        }
        g.drawImage(stat,  0, 0, this);

    }


    private int getRandom(int min, int max) {
        int random = min + (int) (Math.random() * (max - min));

        return random;

    }


    public void setCT(String c) {
        Visualiser.doVis=true;
        ct=c;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                System.out.println("got to the new runnable thingie");

                repaint();
            }
        });


    }

    public void actionPerformed(ActionEvent e) {
        if(e.getSource().equals(this.refreshTimer)) {
            // the timer is the source so do some refreshing!

            repaint();
        }

    }




}

doVis和ct变量分别是该(可视化器)类的公共静态布尔值和字符串,paint方法在决定要绘制什么之前检查doVis的值。这部分没问题。强制Java进行适当的重绘才是问题所在!


你已经从一个 JPanel 扩展了,而且 setCT 方法在这个扩展类中吗? - lhlmgr
听起来你的代码有问题,但是你没有展示出来;-) 是时候提供一个SSCCE来演示问题了... - kleopatra
1个回答

2
作为一个扩展了 JPanel 的类,实现你所需要的功能的快速、简单和干净的方法是重写 JPanel.paintComponent() 方法并在其中进行渲染。
如果你想要自动刷新GUI,我建议你使用swing定时器,在其中每隔一段时间调用 JPanel.validate()。你的面板可以像这样:
public class TextRendererPanel extends JPanel{
   protected void paintComponent(Graphics g){
       // Do your rendering stuff here.
   }
}

创建后,可以通过以下方式刷新面板:
TextRendererPanel textRendererPanel = new TextRendererPanel();
textRendererPanel.invalidate();

这里有一个关于Swing定时器的教程,您可以从中开始学习。


非常愉快 :) 请查看我的更新,了解如何覆盖 paintComponent 方法。 - GETah
1
感谢您的回复。我已编辑原始问题,以显示Visualiser类的完整代码。关键是创建一个带有定期刷新的计时器对象,并在调用此可视化的类中,在Visualiser.setCT()调用之后直接包含Visualiser.invalidate(); 调用。这似乎解决了问题! - user1509862
太好了!很高兴它起作用了。如果您认为它解决了您的问题,请不要忘记将其标记为答案 ;) - GETah
@GETah:只是一个小建议,为了保持封装性完整,当你重写paintComponent()时,尽可能保持与父类/基类中使用的访问修饰符相同,即protected,因此它是protected void paintComponent(...)。对于其他部分,给你点赞+1 :-) - nIcE cOw
@GETah:非常欢迎你,保持微笑 :-) - nIcE cOw
1
@user1509862 和 GETah:paintComponent 的实现在两个 JPanel 中都是无效的 :-) JPanel 的透明度默认为 true,也就是说它负责完全填充其背景,始终如此。因此,请将其更改为返回 false 或调用 super.paintComponent 或任何其他方法来填充背景。 - kleopatra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接