I have a class to allow the user to select a serial port using a kind-of dropdown. It lists the available ports and the user can select using the up and down arrows.
An object is instantiated when the user presses ‘P’ on the keyboard and the class shows the ‘form’. When the user is done (either canceled or accepted the selected port), the 'form should no longer be visible.
What is the correct approach? I currently set the instance to null and in the main draw() method I check for null to decide if I need to draw it or not. Or should the class contain a flag the can hide and show it? Or should I really try to “destroy” the instantiated object (I will need to read up on that, I did find some stuff regarding it).
If the user wants to show the port selection again, ‘P’ is pressed and a new instance of the class is created.
The class
///////////////////////////////
// SerialSelector class
///////////////////////////////
class SerialSelector
{
// list of ports
private String ports[];
// index selected port in 'dropdown'
private int portIdx = -1;
// indicate that we can / should close the 'form'
public boolean closing = false;
/*
SerialSelector constructor
*/
SerialSelector()
{
// get list of available ports
ports = Serial.list();
}
/*
SerialSelector keypress handler
Returns:
true if the key was handled, else false
*/
boolean onKeypress()
{
boolean keyHandled = false;
// if it was a coded key
if (key == CODED)
{
switch(keyCode)
{
case UP:
if (portIdx != -1)
{
portIdx--;
if (portIdx < 0 )
{
portIdx = ports.length - 1;
}
}
keyHandled = true;
break;
case DOWN:
if (portIdx != -1)
{
portIdx++;
if (portIdx >= ports.length )
{
portIdx = 0;
}
}
keyHandled = true;
break;
case 0x73: // <F4>
portIdx = -1;
closing = true;
keyHandled = true;
break;
}
} // end-of-if (key == CODED)
else
{
switch(key)
{
case ' ':
case '\r':
case '\n':
closing = true;
keyHandled = true;
break;
}
}
return keyHandled;
}
/*
SerialSelector get selected port
Returns:
null if selection was canceled, else selected port name
*/
public String getPort()
{
if (portIdx == -1)
{
return null;
} else
{
return ports[portIdx];
}
}
/*
SerialSelector draw method
*/
void draw()
{
String displayedPort = "No ports available";
// if there are ports
if (ports.length != 0)
{
// if no port selected, select the first one
if (portIdx == -1)
{
portIdx = 0;
}
displayedPort = ports[portIdx];
} //
textSize(14);
float txtWidth = textWidth(displayedPort);
// form width determined by text size
int formWidth = (int)txtWidth + 40;
int formHeight = 40;
int innerWidth = formWidth - 10;
int innerHeight = formHeight - 10;
int posX = (width - formWidth) / 2;
int posY = (height - formHeight) / 2;
fill(0xFF010101);
noStroke();
rect(posX, posY, formWidth, formHeight, 10);
// draw inner form with border
stroke(0xFF0060FF);
rect(posX + 5, posY + 5, innerWidth, innerHeight, 5);
textAlign(CENTER, CENTER);
fill(0xFFE0E0E0);
text(displayedPort, posX + formWidth / 2, posY + formHeight / 2 - 3);
}
} // end-of-SerialSelector
The class has its own draw() method that is (conditionally, see above) called from the ‘normal’ draw.
/*
Main draw
*/
void draw()
{
background(0xFF406060);
// if the serial selector is open
if (portSelector != null)
{
portSelector.draw();
}
visualData.draw();
textAlign(LEFT, CENTER);
textSize(16);
noStroke();
if (selectedPort == "")
{
fill(0xFF010101);
text("No port selected; press 'P' to select a port", 20, 20);
} //
else
{
if (serialSynced == true)
{
fill(0xFF00C000);
text(selectedPort + " synced", 20, 20);
} //
else
{
fill(0xFF70EFC0);
text(selectedPort + " not synced", 20, 20);
}
}
noLoop();
}
It also has it’s own keyPress handler (onKeypress(), called from the ‘normal’ keyPressed().
/*
Main keyPressed
*/
void keyPressed()
{
println("main key pressed");
// if the serial selector is open
if (portSelector != null)
{
// handle the key
portSelector.onKeypress();
// if user accepted the choice (space, <CR> or <LF>) or canceled (<F4>)
if (portSelector.closing == true)
{
String x = portSelector.getPort();
// if it was not a cancel
if (x != null)
{
// if port was open and newly selected port does not match current port
if (mySerial != null && x.equals(selectedPort) == false)
{
closePort();
}
// if port is closed
if (mySerial == null)
{
openPort(x);
}
} //
else
{
println("canceled");
}
// close (destroy)
portSelector = null;
}
} //
else
{
// 'P' opens the serial selector
if (key == 'P' || key == 'p')
{
portSelector = new SerialSelector();
}
}
redraw();
}
portSelector is the instance of the SerialSelector.
I hope I’ve provided sufficient information.
Note:
- I know that there is a garbage collector.
- I come from an environment with malloc/free (and a little new/delete)