I have been working with G4P for four days.
I have a simple form to enter or modify data and I’m experiencing a problem with the two GTextField controls. The data will be saved to and read from a file.
The code that generated this is
GGroup gbxStateDialog;
GPanel pnlStateDialog;
GLabel lblStateIndex;
GTextField txtStateIndex;
GLabel lblStateName;
GTextField txtStateName;
GLabel lblStateDescription;
GTextArea txtStateDescription;
GLabel lblInitialState;
GCheckbox cbxInitialState;
GButton btnOK;
GButton btnCancel;
GTabManager tt;
void createStateDialog()
{
// create a group that can hold a panel. Note that a group does not have a size
gbxStateDialog = new GGroup(this);
gbxStateDialog.setVisible(true);
int pX1 = 2, pY1 = 2, pHeight1 = 240, pWidth1 = 400;
pnlStateDialog = new GPanel(this, pX1, pY1, pWidth1, pHeight1, "Information (drag to move : click to open/close)");
pnlStateDialog.setLocalColor(4, color(0xC0, 0xC0, 0xC0)); // changes the background (4)
pnlStateDialog.setLocalColor(2, color(0x00, 0x00, 0xC0)); // panel text (2); this is the title
pnlStateDialog.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 18));
gbxStateDialog.addControl(pnlStateDialog);
lblStateIndex = new GLabel(this, 10, 30, 150, 20, "Index");
lblStateIndex.setTextAlign(GAlign.LEFT, null);
lblStateIndex.setOpaque(true);
lblStateIndex.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblStateIndex);
txtStateIndex = new GTextField(this, 170, 30, 200, 20);
txtStateIndex.tag = "txtStateIndex";
txtStateIndex.setPromptText("State index");
txtStateIndex.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
//txtStateIndex.setFont(new java.awt.Font("Courier New", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(txtStateIndex);
lblStateName = new GLabel(this, 10, 55, 150, 20, "State name");
lblStateName.setTextAlign(GAlign.LEFT, null);
lblStateName.setOpaque(true);
lblStateName.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblStateName);
txtStateName = new GTextField(this, 170, 55, 200, 20);
txtStateName.tag = "txtStateName";
txtStateName.setPromptText("State name");
txtStateName.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
//txtStateName.setFont(new java.awt.Font("Courier New", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(txtStateName);
lblStateDescription = new GLabel(this, 10, 80, 150, 20, "State description");
lblStateDescription.setTextAlign(GAlign.LEFT, null);
lblStateDescription.setOpaque(true);
lblStateDescription.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblStateDescription);
txtStateDescription = new GTextArea(this, 170, 80, 200, 90, G4P.SCROLLBARS_VERTICAL_ONLY );
txtStateDescription.tag = "txtStateDescription";
txtStateDescription.setPromptText("State description");
txtStateDescription.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
//txtStateDescription.setFont(new java.awt.Font("Courier New", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(txtStateDescription);
lblInitialState = new GLabel(this, 10, 180, 150, 20, "Initial state");
lblInitialState.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblInitialState);
cbxInitialState = new GCheckbox(this, 170, 180, 20, 20);
cbxInitialState.tag = "cbxInitialState";
pnlStateDialog.addControl(cbxInitialState);
btnOK = new GButton(this, 10, 205, 80, 25, "OK");
btnOK.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
btnOK.tag = "StateDialogOK";
btnCancel = new GButton(this, 100, 205, 80, 25, "Cancel");
btnCancel.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
btnCancel.tag = "StateDialogCancel";
pnlStateDialog.addControls(btnOK, btnCancel);
// force focus on first control
txtStateIndex.setFocus(true);
//txtStateIndex.setText("-1"); // crashes the application when field has focus and and a character is entered
tt = new GTabManager();
tt.addControls(txtStateIndex, txtStateName, txtStateDescription);
// bugfix
//txtStateName.setFocus(true);
//txtStateIndex.setFocus(true);
}
which is called from setup(). The focus is forced on the first GTextField control.
The fun started when I tried to set a default value for the first GTextField with txtStateIndex.setText("-1"); at the end of the function. I did notice that the text cursor disappeared. Pressing the tab key to move to the next field (or any other key) resulted in the following exception
NullPointerException
NullPointerException
java.lang.NullPointerException: Cannot read field "startCharIndex" because "this.endTLHI.tli" is null
at g4p_controls.GTextField.keyEvent(Unknown Source)
at g4p_controls.GWindowImpl.sendKeyEvent(Unknown Source)
at g4p_controls.GWindowImpl.keyEvent(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at processing.core.PApplet$RegisteredMethods.handle(PApplet.java:1313)
at processing.core.PApplet.handleMethods(PApplet.java:1460)
at processing.core.PApplet.handleKeyEvent(PApplet.java:2663)
at processing.core.PApplet.dequeueEvents(PApplet.java:2270)
at processing.core.PApplet.handleDraw(PApplet.java:2112)
at processing.javafx.PSurfaceFX$1.handle(Unknown Source)
at processing.javafx.PSurfaceFX$1.handle(Unknown Source)
at javafx.graphics/com.sun.scenario.animation.shared.TimelineClipCore.visitKeyFrame(TimelineClipCore.java:239)
at javafx.graphics/com.sun.scenario.animation.shared.TimelineClipCore.playTo(TimelineClipCore.java:197)
at javafx.graphics/javafx.animation.Timeline.doPlayTo(Timeline.java:172)
at javafx.graphics/javafx.animation.AnimationAccessorImpl.playTo(AnimationAccessorImpl.java:39)
at javafx.graphics/com.sun.scenario.animation.shared.InfiniteClipEnvelope.timePulse(InfiniteClipEnvelope.java:120)
at javafx.graphics/javafx.animation.Animation.doTimePulse(Animation.java:1189)
at javafx.graphics/javafx.animation.Animation$1.lambda$timePulse$0(Animation.java:207)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/javafx.animation.Animation$1.timePulse(Animation.java:206)
at javafx.graphics/com.sun.scenario.animation.AbstractPrimaryTimer.timePulseImpl(AbstractPrimaryTimer.java:343)
at javafx.graphics/com.sun.scenario.animation.AbstractPrimaryTimer$MainLoop.run(AbstractPrimaryTimer.java:266)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:571)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:353)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
NullPointerException
To solve the issue I initially added an additional txtStateIndex.setFocus(true); at the end of the above function but that did not solve the issue. What solved the issue was first setting the focus to another control and next back to the one that hade the focus; e.g.
txtStateName.setFocus(true);
txtStateIndex.setFocus(true);
For further debugging I extended the basic draw() with an update of the GTextField every 4 seconds. Each time txtStateIndex.setText(String.valueOf(cnt)); was executed the issue showed.
int startTime = millis();
int cnt = 1;
void draw()
{
background(0xFF123456);
if (millis() - startTime >= 4000)
{
startTime = millis();
txtStateIndex.setText(String.valueOf(cnt));
cnt++;
// bugfix
//txtStateName.setFocus(true);
//txtStateIndex.setFocus(true);
}
}
The problem only shows with GTextField. I did modify the code to update the second GTextField resulting in the same issue; I also modified the code to update the GTextArea but no problem was experienced.
Full code (with bugfix)
import processing.javafx.*;
import g4p_controls.*;
void settings()
{
System.setProperty("glass.win.uiScale", "1");
size(600, 300, FX2D);
smooth();
}
void setup()
{
createStateDialog();
}
int startTime = millis();
int cnt = 1;
void draw()
{
background(0xFF123456);
if (millis() - startTime >= 4000)
{
startTime = millis();
txtStateIndex.setText(String.valueOf(cnt));
cnt++;
// bugfix
txtStateName.setFocus(true);
txtStateIndex.setFocus(true);
}
}
GGroup gbxStateDialog;
GPanel pnlStateDialog;
GLabel lblStateIndex;
GTextField txtStateIndex;
GLabel lblStateName;
GTextField txtStateName;
GLabel lblStateDescription;
GTextArea txtStateDescription;
GLabel lblInitialState;
GCheckbox cbxInitialState;
GButton btnOK;
GButton btnCancel;
GTabManager tt;
void createStateDialog()
{
// create a group that can hold a panel. Note that a group does not have a size
gbxStateDialog = new GGroup(this);
gbxStateDialog.setVisible(true);
int pX1 = 2, pY1 = 2, pHeight1 = 240, pWidth1 = 400;
pnlStateDialog = new GPanel(this, pX1, pY1, pWidth1, pHeight1, "Information (drag to move : click to open/close)");
pnlStateDialog.setLocalColor(4, color(0xC0, 0xC0, 0xC0)); // changes the background (4)
pnlStateDialog.setLocalColor(2, color(0x00, 0x00, 0xC0)); // panel text (2); this is the title
pnlStateDialog.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 18));
gbxStateDialog.addControl(pnlStateDialog);
lblStateIndex = new GLabel(this, 10, 30, 150, 20, "Index");
lblStateIndex.setTextAlign(GAlign.LEFT, null);
lblStateIndex.setOpaque(true);
lblStateIndex.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblStateIndex);
txtStateIndex = new GTextField(this, 170, 30, 200, 20);
txtStateIndex.tag = "txtStateIndex";
txtStateIndex.setPromptText("State index");
txtStateIndex.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
//txtStateIndex.setFont(new java.awt.Font("Courier New", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(txtStateIndex);
lblStateName = new GLabel(this, 10, 55, 150, 20, "State name");
lblStateName.setTextAlign(GAlign.LEFT, null);
lblStateName.setOpaque(true);
lblStateName.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblStateName);
txtStateName = new GTextField(this, 170, 55, 200, 20);
txtStateName.tag = "txtStateName";
txtStateName.setPromptText("State name");
txtStateName.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
//txtStateName.setFont(new java.awt.Font("Courier New", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(txtStateName);
lblStateDescription = new GLabel(this, 10, 80, 150, 20, "State description");
lblStateDescription.setTextAlign(GAlign.LEFT, null);
lblStateDescription.setOpaque(true);
lblStateDescription.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblStateDescription);
txtStateDescription = new GTextArea(this, 170, 80, 200, 90, G4P.SCROLLBARS_VERTICAL_ONLY );
txtStateDescription.tag = "txtStateDescription";
txtStateDescription.setPromptText("State description");
txtStateDescription.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
//txtStateDescription.setFont(new java.awt.Font("Courier New", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(txtStateDescription);
lblInitialState = new GLabel(this, 10, 180, 150, 20, "Initial state");
lblInitialState.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
pnlStateDialog.addControl(lblInitialState);
cbxInitialState = new GCheckbox(this, 170, 180, 20, 20);
cbxInitialState.tag = "cbxInitialState";
pnlStateDialog.addControl(cbxInitialState);
btnOK = new GButton(this, 10, 205, 80, 25, "OK");
btnOK.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
btnOK.tag = "StateDialogOK";
btnCancel = new GButton(this, 100, 205, 80, 25, "Cancel");
btnCancel.setFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 16));
btnCancel.tag = "StateDialogCancel";
pnlStateDialog.addControls(btnOK, btnCancel);
// force focus on first control
txtStateIndex.setFocus(true);
txtStateIndex.setText("-1"); // crashes the application when field has focus and and a character is entered
tt = new GTabManager();
tt.addControls(txtStateIndex, txtStateName, txtStateDescription);
// bugfix
txtStateName.setFocus(true);
txtStateIndex.setFocus(true);
}
It still needs a bit of polishing.
PDE version 4.5.0, operating system Windows 11 home.
G4P version (reported) V4.3.11
