I am writing some code to create coloured visualisations of text. The following managed the visualisation panel and the setCT(String c) method is (correctly) called from elsewhere in the program.
Unfortunately, the required visualisation only happens when the window is resized. Until then, the vis panel just stays black! What is going on? I've tried using the validate() method and also creating a new Runnable() as per the guides elsewhere, to no avail. Here is my code:
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();
}
}
}
The doVis and ct variables are both public static boolean & String respectively of this (the Visualiser) class and the paint method checks the doVis value before deciding what to paint. This part is OK. It is forcing Java to do a proper repaint that is the problem!
As you are extending a JPanel, the quick, easy and clean way to achieve what you want is to override the JPanel.paintComponent() method where you do your rendering.
If you want to automatically refresh your GUI then I suggest you go for swing timers in which you call JPanel.validate() every now and then. Your panel can look like:
public class TextRendererPanel extends JPanel{
protected void paintComponent(Graphics g){
// Do your rendering stuff here.
}
}
Once created, the panel can be refreshed like this:
TextRendererPanel textRendererPanel = new TextRendererPanel();
textRendererPanel.invalidate();
And here is a tutorial on swing timers that you can start with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With