Hi, I would like to input a text into a ‘textbox’ and save the input into a variable when for example enter is pressed. So far I have come up with the following code: main.pde:
class TextBox{
TextBox(int x, int y, int boxWidth, int boxHeight){
this.x = x;
this.y = y;
this.boxWidth = boxWidth;
this.boxHeight = boxHeight;
}
void draw(){
drawBox();
drawText();
getUserInput();
}
void drawBox(){
stroke(205);
fill(205);
rect(x, y, boxWidth, boxHeight);
}
void drawText(){
textAlign(LEFT, CENTER);
textSize(16);
fill(255);
text(textValue + getCursor(), x + 5, y + boxHeight/2);
}
void getUserInput(){
if(!keyPressed){
keyReleased = true;
keyCounter = 0;
previousKeyCounter = 0;
}
if (keyPressed && c != key){
keyCounter = millis();
c = key;
if (c == BACKSPACE) textValue = "";
else if (c >= ' ') textValue += str(c);
if (textValue.length() > textLimit) textValue = "";
previousKeyCounter = keyCounter;
keyReleased = false;
}
}
String getCursor() {
return hovering() && (frameCount>>4 & 1) == 0 ? "|" : "";
}
boolean hovering(){
return mouseX >= x && mouseX <= x + boxWidth && mouseY >= y && mouseY <= y + boxHeight;
}
private int x, y, boxWidth, boxHeight, textLimit = 40;
private float currentValue, keyCounter, previousKeyCounter;
private String textValue;
private char keyInput, c;
private boolean keyReleased;
}
For now let’s focus on the typing aspect first. As you can experience, typing fast does not work as expected, if you type character by character it does work. How can I include this functionality of pressing multiple keys at the same time? I would like the code to be modular, so nothing in functions like mouseClicked() or mouseReleased() etc.
If anyone can give me an example of how to use a library which has this functionality, that would be much appreciated as well. I don’t have a lot of knowledge on how to import libraries.
A fast typist will be hitting approximately 375 chars per minute, and Processing defaults to 60fps. However, no matter what its frameRate, Processing doesn’t drop these events. Even at 1fps, it will catch dozens of keys correctly in each frame, in the correct order. Try it!
Don’t invoke key from inside draw() → textBox1.draw() → getUserInput() – that is a convenience keyword and will only give you a single event per frame. Call it from keyReleased(), which is invoked by every single queued event. Pass the unique key value each time.
Thank you for your answer. I installed the G4P library via the Processing IDE and made the following script using the examples provided in the IDE, to get a textfield:
import g4p_controls.*;
GTextField txf1;
public void setup() {
size(500, 300);
txf1 = new GTextField(this, 10, 10, 200, 20);
txf1.setPromptText("Text field 1");
txf1.setText("test1"); // works
}
public void draw() {
background(200, 128, 200);
if (keyPressed && key == ENTER){
println(txf1.getText());
txf1.setText("test2"); // gives nullpointerexception
}
}
However, when I try to set a new text in the textfield, I get a nullpointer exception. The setText() function does work as expected in the setup, but not in the draw. Does anyone know how I can solve this problem?
java.lang.NullPointerException
at g4p_controls.GTextField.keyEvent(Unknown Source)
at g4p_controls.GWindowImpl.sendKeyEvent(Unknown Source)
at g4p_controls.GWindowImpl.keyEvent(Unknown Source)
at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at processing.core.PApplet$RegisteredMethods.handle(PApplet.java:1432)
at processing.core.PApplet.handleMethods(PApplet.java:1634)
NullPointerException
at processing.core.PApplet.handleKeyEvent(PApplet.java:3014)
at processing.core.PApplet.dequeueEvents(PApplet.java:2648)
at processing.core.PApplet.handleDraw(PApplet.java:2486)
at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1547)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:313)
Looking at your sample code that uses GTextField there are a number of things worth mentioning but first of all the error is caused because you attempted to use setText("test2"); while the textfield still had focus (the text insertion cursor is flashing). If you enter some text in the textfield and then click outside the textfield before pressing ENTER then it works.
NEVER use setText(...) while the textfield has focus, same thing applies to GPassword and GTextArea.
All G4P control use event handlers to process events. Here is an example of how to use a textfield
import g4p_controls.*;
GTextField txf1;
String t0;
public void setup() {
size(500, 300);
txf1 = new GTextField(this, 10, 10, 200, 20);
txf1.setPromptText("Text field 1");
txf1.setText("test1"); // works
}
public void draw() {
background(200, 128, 200);
if (keyPressed && key == ENTER) {
println(t0);
}
}
public void handleTextEvents(GEditableTextControl textcontrol, GEvent event) {
if(txf1 == textcontrol && event == GEvent.ENTERED){
t0 = txf1.getText();
}
}
now thanks to that info you could overwrite the typed value?
or ( as i not fully understand your use case )
i try to empty it and give the user a new prompt text
public void handleTextEvents(GEditableTextControl textcontrol, GEvent event) {
if ( textcontrol == txf1 && event == GEvent.ENTERED) {
t0 = txf1.getText();
println("ENTER: "+t0);
txf1.setFocus(false); // @quark is the best
//txf1.setText("over write new?");
txf1.setText("");
txf1.setPromptText("next value");
}
}
even something like
public void handleTextEvents(GEditableTextControl textcontrol, GEvent event) {
if ( textcontrol == txf1 && event == GEvent.ENTERED) {
t[count] = txf1.getText();
count++;
txf1.setFocus(false);
txf1.setText("");
txf1.setPromptText("next value t["+count+"]");
}
}
No in the sense that setup, draw, and event handlers are part of the Processing loop. Draw is called and then events are processed, then draw is called again. You can’t put draw in a class, although you could choose to invoke redraw(). Your code puts event handlers in a class, but you then still need to pass the events from keyPressed() to the Objects of that class – for example, looping over an array in keyPressed and passing each event to each object.
OR you could use registerMethod("keyEvent") – for a previous discussion, see: