Random rows/columns in a csv file and print text with typewriter effect

Wow, thanks for the feedback @Chrisir, it’s really helpful.

And again, a big thanks for your patience and guidance on what has been a pretty long thread, really appreciate it.

Opt out.

2 Likes

You are welcome!

Well done!

Chrisir

2 Likes

And I’m back @Chrisir !!

I decided to try something else with this project and combine the early project with the one above. What I am now trying to achieve is the following:

  • First Column appears on screen using typewriter effect.
  • It stays on screen by itself for 5 seconds
  • Then second line appears also with typewriter effect (it appears on a different part of the screen.
  • Both lines of text then stay on screen for five seconds.
  • Then the screen goes blank for 5 seconds and then reiterates through programme.

To start, I have been trying to get:

  • the first line to stay for 5 seconds (I can’t get this working - although there is a 5 second gap between texts
  • then the second one to appear and stay for 5 seconds (Yes, this works!)
  • and then screen clears and a gap of 5 seconds before iterating again (This doesn’t work it just reiterates straight away)

So my main problem seems to be with typeWriter1() and case 4:

full code below and any suggestion/advice would be most welcome.

/* This sketch randomly selects rows from a CSV file
 these rows are then printed out to screen using 
 a 'typewriter' style effect.
 I want the text to print out and then stay on screen for 5 seconds.
 I then want the screen to stay blank for 5 seconds before starting again. 
 */

int state=0; // state of the program 
Table table; // table object 
int timer; //creates a a timer variable
int counter = 0; //creates a counter variable and sets it to zero 
String full; //a string to combine amount + name 
String amount; //a string to combine amount + name 
String newAmount; // a string with new amount 
String newName; // a string ith newNames


void setup() {
  // size(1000, 1000); //size
  fullScreen();
  PFont font; //font 
  table = loadTable("nameISP.csv", "header");
  smooth(); 
  font = createFont("HoeflerText-Italic-48", 48); //creates font
  textFont(font, 120); //text font 
  textAlign(CENTER, CENTER); //aligns text to Center
  selectRow(); //calls selectRow fucntion 
  timer=millis();
}

void draw() {

  switch (state) { //this is the start of switch 


    //this calls typeWriter1
  case 0:
    // this will be exectued if state = 0
    background (0); //background 
    typeWriter1();

    break; // break for case 0 


  case 1:
    //this is the break between typewriter 1 + 2 
    background (0); 
    if (millis()-timer > 5000) { //if 5 seconds has passed 
      timer=millis();
      state=2;  // move on
    }
    break; //break for case 1 

    //this calls typeWriter2 
  case 2:
    background(0); //background 
    typeWriter2();
    break; //break for case 2


//this should keep typewriter2 text on screen for 5 seconds 
  case 3: 

    if (millis()-timer > 5000) {
      state=4;
    }
    break;
//this should wait 5 seconds before iteratating again. 
  case 4:
    if (millis()-timer > 5000) {
      selectRow();
      state=0;
    }
    break;
  }
}
//---------------------------------------------------------------------


// Tyewriter1 pulls the first column, prints it too screen, and waits a few seconds 
void typeWriter1() {

  text(newAmount.substring(0, counter), 
    0, 40, width, height); //text to print 
  if (millis()-timer > 100) { //this is the typewriter effect 
    counter++;      // go to next letter 
    timer=millis(); // reset timer
  }

  if (counter > newAmount.length()) { //this if statement resets counter to 0 when text is finished 
    counter = 0; // reset
    state = 1; //go to state one 
    timer=millis(); // reset timer
  }
}

void typeWriter2() {

  text(newName.substring(0, counter), 
    100, 40, width, height ); //text to print 
  if (millis()-timer > 100) { //this is the typewriter effect 
    counter++;      // go to next letter 
    timer=millis(); // reset timer
  }
  if (counter > newName.length()) { //this if statement resets counter to 0 when text is finished 
    counter = 0; // reset
    state = 3;
  }
}


void selectRow() {  

  TableRow row;  //Table row object 
  String amount="", name=""; //two strings representing columns in csv
  row = table.getRow((int)random(table.getRowCount())); //print a random row  
  amount = row.getString("IP"); //a string with amount
  name = row.getString("ISP"); // prints name for row
  full = amount + " " +  name;  //combines name and row into new String called full 
  newAmount = amount;
  newName = name; 
  println (full); //just prints to serial monitor so I can test all is working
}
//
1 Like

You forgot to write this at the end of case 3?

1 Like

Thanks @Chrisir . I tried it

case 3: 

    if (millis()-timer > 5000) {
    timer=millis();
      state=4;
       
    }
    
    break;

But it hasn’t changed anything…will keep trying :slight_smile:

1 Like

This is not a useful comment because everyone sees that.

I guess useful comments kind of tell the purpose of a paragraph/ section or give an over all view.

Eg // here we distinguish between different states of the sketch

1 Like

fair comment, to be honest I had put it in there to explain to myself as I went over the code…will avoid in future.

2 Likes

This is missing in typewriter2 !!!

Remark

You copied typewriter1 to typewriter2. I understand why. In general it’s better to write a more abstract version of the function and use it for both cases. Eg you could pass the String and what’s the next state as a parameter

2 Likes

Remember to hit ctrl-t regularly in processing especially prior to posting

Also, You should have empty lines between the case sections not inside them

2 Likes

Yeah, I thought I was being smart, by reusing the same code, as in I thought the logic was the same:

This is missing in typewriter2 !!!

Yes, but even with it in, it is still not changing anything.

In general it’s better to write a more abstract version of the function and use it for both cases. Eg you could pass the String and what’s the next state as a parameter

Could I ask you to elaborate on this, as I’m not sure what you mean, in particular ‘pass the String and what’s the next state as a parameter’

Thanks

1 Like

What distinguishes the 2 functions is the string and the next state we go to.

So we have to clearify this when we want to unify the two.

We could move the state line out of the function two both respectively case sections

We could pass the String as parameter

[quote=“OptOut, post:64, topic:12889”]
void typeWriter1() {
[/ quote]

void typeWriterNew(String stringLocal) {

and then use stringLocal in the function

When we call the function typeWriterNew use 2 different variables as parameter: newAmount and newName

2 Likes

No background in case 1

2 Likes

Prior to using the timer you need to reset it using timer=millis(); every time

You forgot this twice

Does it work now?

If not please post your entire code

2 Likes

I just spent 3 days trying to fix/find that :man_facepalming:

2 Likes

Not using background() command makes the text less crisp optically.

Alternatively you would text() out the text after background() in this case section.

2 Likes

I’ve just checked again and from what I can see timer is reset each time.

/* This sketch randomly selects rows from a CSV file
 these rows are then printed out to screen using 
 a 'typewriter' style effect.
 I want the text to print out and then stay on screen for 5 seconds.
 I then want the screen to stay blank for 5 seconds before starting again. 
 */

int state=0; // state of the program 
Table table; // table object 
int timer; //creates a a timer variable
int counter = 0; //creates a counter variable and sets it to zero 
String full; //a string to combine amount + name 
String amount; //a string to combine amount + name 
String newAmount; // a string with new amount 
String newName; // a string ith newNames


void setup() {
  // size(1000, 1000); //size
  fullScreen();
  PFont font; //font 
  table = loadTable("nameISP.csv", "header");
  smooth(); 
  font = createFont("HoeflerText-Italic-48", 48); //creates font
  textFont(font, 120); //text font 
  textAlign(CENTER, CENTER); //aligns text to Center
  selectRow(); //calls selectRow fucntion 
  timer=millis();
}

void draw() {
  switch (state) { 

    //this calls typeWriter1
  case 0:
    // this will be exectued if state = 0
    background (0); //background 
    typeWriter1();
    break; // break for case 0 


  case 1:
    //this is the break between typewriter 1 + 2 

    if (millis()-timer > 5000) { //if 5 seconds has passed 
      timer=millis();
      state=2;  // move on
    }
    break; //break for case 1 

    //this calls typeWriter2 
  case 2:
    background(0); //background 
    typeWriter2();
    break; //break for case 2

    //this should keep typewriter2 text on screen for 5 seconds 
  case 3: 

    if (millis()-timer > 5000) {
      timer=millis();
      state=4;
    }

    break;

    //this should wait 5 seconds before iteratating again. 
  case 4:
    if (millis()-timer > 5000) {
      timer=millis();
      selectRow();
      state=0;
    }
    break;
  }
}

//---------------------------------------------------------------------


// Tyewriter1 pulls the first column, prints it too screen, and waits a few seconds 
void typeWriter1() {

  text(newAmount.substring(0, counter), 
    0, 40, width, height); //text to print 
  if (millis()-timer > 100) { //this is the typewriter effect 
    counter++;      // go to next letter 
    timer=millis(); // reset timer
  }

  if (counter > newAmount.length()) { //this if statement resets counter to 0 when text is finished 
    counter = 0; // reset
    state = 1; //go to state one 
    timer=millis(); // reset timer
  }
}

void typeWriter2() {

  text(newName.substring(0, counter), 
    100, 40, width, height ); //text to print 
  if (millis()-timer > 100) { //this is the typewriter effect 
    counter++;      // go to next letter 
    timer=millis(); // reset timer
  }
  if (counter > newName.length()) { //this if statement resets counter to 0 when text is finished 
    counter = 0; // reset
    state = 3;
    timer=millis(); // reset timer
  }
}


void selectRow() {  

  TableRow row;  //Table row object 
  String amount="", name=""; //two strings representing columns in csv
  row = table.getRow((int)random(table.getRowCount())); //print a random row  
  amount = row.getString("IP"); //a string with amount
  name = row.getString("ISP"); // prints name for row
  full = amount + " " +  name;  //combines name and row into new String called full 
  newAmount = amount;
  newName = name; 
  println (full); //just prints to serial monitor so I can test all is working
}
//

1 Like

when it works now, all timers are reset correctly

Almost!

Now first line appears for 5 seconds as does second…however I would like for there to be a blank screen after the second line appears - so a five second blank screen between iterations.

I tried to introduce another state to acheive this, but it just keeps the second line on screen for longer:


void draw() {
  switch (state) { 

    //this calls typeWriter1
  case 0:
    // this will be exectued if state = 0
    background (0); //background 
    typeWriter1();
    break; // break for case 0 


  case 1:
    //this is the break between typewriter 1 + 2 

    if (millis()-timer > 5000) { //if 5 seconds has passed 
      timer=millis();
      state=2;  // move on
    }
    break; //break for case 1 

    //this calls typeWriter2 
  case 2:
    background(0); //background 
    typeWriter2();
    break; //break for case 2

    //this should keep typewriter2 text on screen for 5 seconds 
  case 3: 

    if (millis()-timer > 5000) {
      timer=millis();
      state=4;
    }

    break;


    // trying to create a 5 second delay before iterations
  case 4: 

    if (millis()-timer > 5000) {
      timer=millis();
      state=5;
    }

    break;

    //this should wait 5 seconds before iteratating again. 
  case 5:
    if (millis()-timer > 5000) {
      timer=millis();
      selectRow();
      state=0;
    }
    break;
  }
}

Also, If I wanted to keep the first line on screen for the whole iteration, would I need to implement a boolean?

Thanks again.

Okay, both typewriter need a timer=millis();

when you want to show a blank screen use background() in this case section

When you want a message to stay on the screen: just have a text() command in all appropriate case sections

1 Like

So simple, so obvious …yet so frustratingly difficult to do!

I won’t say goodbye this time (learnt my lesson last time) but for now, I think I’m good :slight_smile:

Thanks again @Chrisir

1 Like