Text Prompt and Response

Hi there -

I’d like to create a text prompt in Processing, where a user can input a string and get a “response” - similar to how a text-based adventure would work - does anyone have an example of how something like that might work?

Thanks!

1 Like
5 Likes

Small Text Editor. Use Backspace and Enter (or Submit button).

  • Also try to enter ‘red’, ‘black’ or ‘green’.


boolean boolEnteringText=true;  // entering text yes/no
String textBeingEntered = "";   // current text input
String result = ""; // list of text on the right  
boolean showBlinkingLine=true;  // show blinking cursor yes/no

float buttonYPos = 5; 

color backgroundColor = 0; 

//---------------------------------------------------------------------------
// Core functions 

void setup() {
  size(800, 800);
  background(0);
}

void draw() {
  background(backgroundColor);

  // show current text input 
  fill(255); 
  text(textBeingEntered + blinkingLine(), 22, 22);

  //show help text (bottom)
  text("Small Text Editor. Use Backspace and Enter (or Submit button). Also try to enter 'red', 'black' or 'green'.", 
    22, height-19);

  // show result in right colummn
  fill(211, 0, 211); 
  text(result, width-192, 22);

  // show submit button
  noFill();
  stroke(0, 255, 0); 
  rect(210, buttonYPos, 61, 27);
  fill(0, 255, 0);
  text("submit", 222, buttonYPos + 18);
}

//---------------------------------------------------------------------------
// Key Inputs 

void keyPressed() {
  if (boolEnteringText && key==BACKSPACE) {
    // delete last char
    if (textBeingEntered.length()>0) {
      textBeingEntered=textBeingEntered.substring(0, textBeingEntered.length()-1);
    }
  } else if  (boolEnteringText && (key==RETURN||key==ENTER)) {
    // submit
    submit();
  }//else if
  else if (boolEnteringText && key != CODED && key>=32) {
    // add char 
    textBeingEntered += key;
  }
}

//---------------------------------------------------------------------------
// Mouse Inputs 

void mousePressed() {
  if (mouseIsBetween(210, buttonYPos, 280, buttonYPos+27)) {
    submit();
  }
}

boolean mouseIsBetween(float x1, float y1, 
  float x2, float y2) {
  if (mouseX >= x1 && 
    mouseX <= x2 &&
    mouseY >= y1 &&
    mouseY <= y2) {
    return true;
  } else {
    return false;
  }//else
}//func

//---------------------------------------------------------------------------
// Tools

String blinkingLine() {
  // toggle showBlinkingLine
  if (frameCount%17==0) 
    showBlinkingLine = ! showBlinkingLine;

  // return line or nothing     
  if (showBlinkingLine) 
    return "|";
  else return "";
}

void submit() {
  // submit

  // add to list 
  result+=textBeingEntered+"\n";

  // execute command 
  switch (textBeingEntered) {
  case "green":
    backgroundColor = color(0, 255, 0); 
    break;
  case "red":
    backgroundColor = color( 255, 0, 0); 
    break;
  case "black":
    backgroundColor = color(0); 
    break;
  }//switch  

  // reset
  textBeingEntered="";
  showBlinkingLine=true;
}
//

6 Likes

Hello @panko
If you have access to the Nyhoff & Nyhoff book Processing: An Introduction to Programming they walk you through the steps. On pp 167–174.

A brief outline is that you import a JAVA pkg at the top of your sketch:

import static javax.swing.JOptionPane.*;

Then there are two functions you will need to
1/ ask for the user’s input
and
2/ show the responding message

These are built-in functions:

The 1st function is:

showInputDialog(your prompt);

The 2nd function is:

showMessageDialog(frame, your responding message)

////////////////////////////////////////////////////////////////////////////////////////////////////////////

The resulting code looks like this:

import static javax.swing.JOptionPane.*;

String input;
input = showInputDialog("Enter your favorite color:");

String response;
response = (input);

showMessageDialog(frame, response + " is my favorite color.");

////////////////////////////////////////////////////////////////////////////////////////////////////////////

Please note, on my OS system there’s a lag for a couple of seconds before the dialog box pops up. Not sure why… but the box will appear.

BTW, the Nyhoff book is an EXCELLENT introduction to programming written for both the classroom as well as self-teaching students. The explanations are granular and often demystify what is going on under the hood.

I hope this helps! :slightly_smiling_face:

:nerd_face:

4 Likes

This reminds me I had this very old textbox example which doesn’t rely on JOptionPane: :writing_hand:

http://studio.ProcessingTogether.com/sp/pad/export/ro.9Zo$UbIWYZEDR

4 Likes

Hey @Chrisir !
I didn’t realize there was another way of doing this without relying on the java import.
I continue to learn that I don’t know what I don’t know. :upside_down_face:
Very interesting!!
:nerd_face:

3 Likes

this is so much fun…

:grin:

1 Like

@Chrisir walks into a dark room and sees an axe, a rope, and a lighter:

1 Like

I didn’t want to spoil the fun for him. :laughing:

Nice tshirt btw

2 Likes

Hi @panko,

Just for fun here is a fake message application (not optimized and uses some hacks):

ezgif-4-a07ddb1038

import java.util.List;

class TextInput {
  int x, y, w, h;
  
  String text = "";
  String placeHolder;
  int margin = 15;
  int blinkTime = 400;
  boolean hasFocus = false;

  TextInput(String placeHolder, int x, int y, int w, int h) {
    this.placeHolder = placeHolder;
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
  }
  
  boolean mouseInside() {
    return mouseX >= x && mouseX <= x + w &&
           mouseY >= y && mouseY <= y + h;
  }
  
  boolean mousePressed() {
    boolean inside = mouseInside();
    hasFocus = inside;
    return inside;
  }
  
  void update() {
    if (mouseInside()) cursor(TEXT);
  }
  
  void keyPressed() {
    if (!hasFocus) return;
    
    // Alphanumeric letter (and special characters)
    if (key == ' ' || (keyCode >= 48 && keyCode <= 90)) {
      text += key;
    }
    
    if (key == BACKSPACE && text.length() > 0) {
      text = text.substring(0, text.length() - 1);
    }
  }

  void display() {
    boolean focusMouse = hasFocus || mouseInside();
    
    rectMode(CORNER);
    pushMatrix();
    translate(x, y);

    // Input box
    stroke(50);
    strokeWeight(2);
    fill(focusMouse ? 255 : 230);
    rect(0, 0, w, h, h / 2);

    // Text
    translate(margin, h / 2);
    textAlign(LEFT, CENTER);
    
    // Placeholder
    if (this.text.length() == 0) {
      fill(120);
      textSize(h / 2.5);
      text(this.placeHolder, 0, 0);
    } else { // Normal text
      fill(0);
      textSize(h / 2);
      text(this.text, 0, 0);
    }
    
    // Blinking bar
    if (hasFocus && ((millis() / blinkTime) % 2 == 0)) {
      float barX = textWidth(this.text) + 2;
      float barHeight = h * 0.5;
      strokeWeight(2);
      line(barX, -barHeight / 2, barX, barHeight / 2);
    }
    
    popMatrix();
  }
}

class SendButton {
  int x, y, size;
  
  SendButton(int x, int y, int size) {
    this.x = x;
    this.y = y;
    this.size = size;
  }
  
  boolean mouseInside() {
    return dist(mouseX, mouseY, x, y) <= size / 2;
  }
  
  void update() {
    if (mouseInside()) cursor(HAND);
  }
  
  boolean mousePressed() {
    if (!mouseInside()) return false;
    return true;
  }
  
  void display() {
    boolean mouseInside = mouseInside();
    
    pushMatrix();
    translate(x, y);
    
    fill(mouseInside ? #5cb7de : #18a0db);
    noStroke();
    circle(0, 0, size);
    
    fill(255);
    float halfSize = size / 2.8;
    
    rotate(mouseInside ? -QUARTER_PI : -QUARTER_PI / 2);
    
    beginShape();
    vertex(halfSize, 0);
    
    float angle = HALF_PI + QUARTER_PI;
    vertex(cos(angle) * halfSize, sin(angle) * halfSize);
    
    vertex(-halfSize / 2, 0);
    
    angle += HALF_PI;
    vertex(cos(angle) * halfSize, sin(angle) * halfSize);
    
    endShape(CLOSE);
    
    popMatrix();
  }
}

enum Author {
    USER,
    BOT
}

class Message {
  String content;
  Author author;
  
  Message(String content, Author author) {
    this.content = content;
    this.author = author;
  }
}

String[] randomMessages = {
  "How are you?",
  "Hello my friend!",
  "How's the weather today?",
  "Yes I am...",
  "Of course it's true!",
  "I am a bot, don't you know that?",
  "I am human for sure",
  "Life is beautiful",
  "Yes",
};

class Messages {
  int x, y, w, h;
  List<Message> messages = new ArrayList<Message>();
  int messageMargin = 25;
  boolean botAnswering = false;
  int botAnswerTime = 0;
  int botAnswerDuration = 0;
  
  Messages(int x, int y, int w, int h) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
  }
  
  void addMessage(String content, Author author) {
    messages.add(new Message(content, author));
    
    botAnswering = true;
    botAnswerTime = millis();
    botAnswerDuration = int(random(1000, 2000));
  }
  
  void update() {
    if (botAnswering && millis() - botAnswerTime >= botAnswerDuration) {
      botAnswering = false;
      messages.add(new Message(randomMessages[int(random(randomMessages.length))], Author.BOT));
    }
  }
  
  void display() {
    float messageHeight = 60;
    float messageWidth = w - messageMargin * 2;
    float startY = y + h - messageHeight / 2 - messageMargin;
    
    rectMode(CENTER);
    textAlign(LEFT, CENTER);
    textSize(messageHeight / 2.7);
    
    for (int i = messages.size() - 1; i >= 0; i--) {
      Message message = messages.get(i);
      
      float msgY = startY - (messages.size() - i - 1) * (messageHeight + messageMargin) - 40;
      
      switch (message.author) {
        case USER:
          fill(#1ab176);
          break;
        case BOT:
          fill(#00aaf6);
          break;
      }
       
      pushMatrix();
      translate(0, msgY);
      
      rect(x + w / 2, 0, messageWidth, messageHeight, 50);
      
      fill(255);
      text(message.content, messageMargin * 2, 0);
      popMatrix();
    }
    
    if (botAnswering) {
      float dotSize = 12;
      
      pushMatrix();
      translate(messageMargin * 1.5, h - 50);
      fill(#9cb0a4);
      
      for (int i = 0; i < 3; i++) {
        float size = map(cos(millis() / 100 + i * QUARTER_PI), -1, 1, 0.8, 1.2) * dotSize;
        circle(i * (dotSize + 5), 0, size);
      }
      
      popMatrix();
    }
  }
}

class MessageApp {
  TextInput textInput;
  SendButton sendButton;
  Messages messages;
  
  MessageApp() {
    int inputMargin = 30;
    int textInputHeight = 50;
    int textInputWidth = width - (2 * inputMargin);
    
    textInput = new TextInput(
      "Enter some text...",
      inputMargin, height - inputMargin - textInputHeight,
      textInputWidth, textInputHeight
    );
    
    sendButton = new SendButton(
      inputMargin + textInput.w - textInput.h / 2,
      textInput.y + textInput.h / 2,
      int(textInput.h * 0.7)
    );
    
    messages = new Messages(0, 0, width, height - inputMargin / 2 - textInputHeight);
  }
  
  void mousePressed() {
    boolean p = sendButton.mousePressed() || textInput.mousePressed();
  }
  
  void keyPressed() {
    if (keyCode == ENTER) {
      if (textInput.text.length() > 0) {
        messages.addMessage(textInput.text, Author.USER);
        textInput.text = "";
      }
    } else {
      textInput.keyPressed();
    }
  }
  
  void update() {
    textInput.update();
    sendButton.update();
    messages.update();
  }
  
  void display() {
    textInput.display();
    sendButton.display();
    messages.display();
  }
}

MessageApp messageApp;

void setup() {
  size(500, 800);

  messageApp = new MessageApp();
}

void draw() {
  background(230);
  
  messageApp.update();
  messageApp.display();
}

void mousePressed() {
  messageApp.mousePressed();
}

void keyPressed() {
  messageApp.keyPressed();
}
6 Likes

To add to the list. :upside_down_face: :slightly_smiling_face:
A detailed but very nice beginner-centric step-by-step walkthrough by Alex Lee via youtube here:

:nerd_face:

4 Likes