Input from stdin

Processing has provided a very good way to introduce students to programming (and to OO), and the immediate gratification of visual output is very effective.
However, the lack of keyboard input is very frustrating!
(This often forces me into very-distracting subterfuges in order to teach students how to write simple algorithms to process keyboard input!)

After years of frustration with this, I finally broke down and created some code to allow keyboard input in real time (rather than restricting input to prepared files).

My solution now allows students to write sketches that solicit user input, but this approach is not very slick and somewhat “klunky” (since you have to write code that detects missing input and prompts the user to supply it, while suspending the draw() method).

Therefore, I welcome comments and suggestions.

Here is a link to a code example that accepts keyboard input for missing values.
When the program begins, the user must input (x,y) coordinates.
If the ‘x’ or ‘w’ or ‘c’ key is pressed, values become undefined (negative) for porition, size, or color (respectively), and user input is solicited.

Yeah, it’s very klunky (and the coding is a bit tedious and ugly), so I am very open to a better solution (while preserving keyPressed() method for other things).

?where? pls. edit your post

I’ve got 2 “.java” sorta library files for it! Both based on JOptionPane: :smiley_cat:
Docs.Oracle.com/en/java/javase/11/docs/api/java.desktop/javax/swing/JOptionPane.html

“Keyboard Input Library” is more sophisticated. But it isn’t cross-mode compatible w/ Pjs:

“WindowJS” is simpler. But b/c it emulates some of JS’ API (mostly alert(), confirm(), prompt(), etc.), a sketch that relies on it can be run online via Pjs: :star_struck:

Check out a sample sketch using “WindowJS” online by copying & pasting the link below in another tab: :running_man:
http://Studio.ProcessingTogether.com/sp/pad/export/ro.9$Bjf6i21oXBw

1 Like

Hi! I’ve seen your windowJS code, and implemented it within my PDE code. Works perfectly. However, if I try to export the code for windows, the exe file won’t run anything, after searching for a solution, it seems that is caused by the java class, if I remove it and my calls to those input windows, the exporting works just fine. I’ve also found this question in the old forum, however, I do not understand how could I have a workaround it. Have you tried this code in an exported app?

I confess I haven’t used the PDE’s exported feature much; only for some small tests.

I believe you mean the class window within file “window.java”.
That “library” is written in actual Java syntax rather than Processing syntax.
If you’re having issues when exporting sketches containing files w/ the extension “.java”, you can attempt convert those files to “.pde” as a workaround.
In the case of “window.java”, you can convert it to “window.pde” by following the instructions in these 2 comments within the file:

// package js; // Uncomment "package js;" for ".java" and comment out for ".pde".

import static javax.swing.JOptionPane.*;
import java.lang.reflect.Array;

static // Uncomment "static" for ".pde" and comment out for ".java".
public abstract class window {

Another option would be compiling “window.java” using javac, and then compress it via jar.
The resulting “.jar” file can be moved into subfolder “code/” within your sketch.

1 Like

That’s about right! the class window. Sorry.

I’ve actually tried to comment/uncomment those lines, but ended with the following error:

"No library found for js
Libraries must be installed in a folder named 'libraries' inside the sketchbook folder (see the Preferences window)."
The package “js” does not exist. You might be missing a library.

I will try to compile it using javac, and I’ll get back to you with the result.

Thanks a lot for your response.

Have you renamed “window.java” to “window.pde” when you did those 2 comment changes?
Remember: “.java” files use Java syntax; while “.pde” is Processing syntax!

I’ve compiled “window.java” as “window.jar”:
https://GitHub.com/GoToLoop/Processing_Jar_Creation/raw/master/js/window.jar
You can download it and drag it into the PDE w/ your sketch.
The PDE will then automatically place “window.jar” inside subfolder “code/”.

1 Like

Hi @bam,

why not just provide a simple class for getting the required inputs on sketch startup ?
The class below could be improved in many ways (ie. allow a range for values [3.14,6.28] or specific Strings (like enum string values), etc.) but guess it demonstrates the general idea …

Hope that helps…

Cheers
— mnse

import processing.awt.*;
import javax.swing.*;
import java.awt.*;

ProgramInput input;

void setup() {
  size(500, 500);
  textSize(20);
  input = new ProgramInput(new Object[][] {
    {/*variable name*/ "someFloat", /*label*/ "Please enter a Float", /*type*/Float.class , /*default value*/3.14},
    {"someInteger", "Please enter an Integer", Integer.class, 42},
    {"someString", "Please enter a String", String.class, "Hallo!"}
  });
}

void draw() {
  background(0);
  fill(255);
  text("Value of someFloat   : "+input.get("someFloat"), 20, 30);
  text("Value of someInteger : "+input.get("someInteger"), 20, 50);
  text("Value of someString  : "+input.get("someString"), 20, 70);
}


// ProgramInput class, could be in a separate Tab
public class ProgramInput {
  private HashMap<String, Object> inputs = new HashMap<>();
  private Object[][] requirements;
  JFrame frame;
  
  public ProgramInput(Object[][] requirements) {    
    this.requirements = requirements;
    this.frame=(JFrame) ((PSurfaceAWT.SmoothCanvas)getSurface().getNative()).getFrame();
    createForm();
  }

  private void createForm() {
    JPanel panel = new JPanel(new GridLayout(requirements.length, 2, 5, 5));

    HashMap<String, JTextField> textFields = new HashMap<>();

    for (Object[] requirement : requirements) {
      String variableName = (String)   requirement[0];
      String prompt       = (String)   requirement[1];
      Class<?> type       = (Class<?>) requirement[2];
      Object   defaultVal =            requirement[3];
      if (textFields.get(variableName) != null) {
        println("ERROR: variableName " + variableName + " already declared!");
        continue;
      }
      panel.add(new JLabel(prompt + " (" + type.getSimpleName() + "):"));
      JTextField textField = new JTextField();
      textField.setText(defaultVal.toString());
      textFields.put(variableName, textField);
      panel.add(textField);
    }
    
    boolean isValid;
    do {
      isValid = true;
      JOptionPane.showOptionDialog(frame, panel, "Specify program parameters", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, new Object[]{"OK"}, "OK");
      for (Object[] requirement : requirements) {
        String variableName = (String) requirement[0];
        JTextField textField = textFields.get(variableName);
        String text = textField.getText();
        Class<?> type = (Class<?>) requirement[2];

        try {
          if (type == Integer.class) {
            inputs.put(variableName, Integer.parseInt(text));
          } else if (type == Float.class) {
            inputs.put(variableName, Float.parseFloat(text));
          } else if (type == String.class) {
            inputs.put(variableName, text);
          } else {
            throw(new java.lang.IllegalArgumentException());
          }
        }
        catch (NumberFormatException e) {
          JOptionPane.showMessageDialog(frame, "Invalid input for " + variableName + ". Expected " + type.getSimpleName() + ".", "Error", JOptionPane.ERROR_MESSAGE);
          isValid=false;
          break;
        }
        catch (java.lang.IllegalArgumentException e) {
          JOptionPane.showMessageDialog(frame, "Unsupported type: " + type.getSimpleName(), "Error", JOptionPane.ERROR_MESSAGE);
          isValid=false;
          break;
        }
      }
    } while (!isValid);
  }

  public Object get(String key) {
    return inputs.get(key);
  }
}


errorhandling:


1 Like