If keyPressed in processing - processing

I'm trying to make a simple program to calculate loan interest. The code I have here works but will only display the result when the 'c' key is pressed down. How can i change the logic so that once 'c' is pressed the result appears on the screen. Any help is appreciated in advanced.
import controlP5.*;
ControlP5 cp5;
Textfield loan;
Textfield interest;
Textfield months;
Button calculate;
Double loan1;
Double months1;
double interest1;
void setup(){
size(700,400);
PFont font = createFont("arial",20);
cp5 = new ControlP5(this);
loan = cp5.addTextfield("Loan Amount")
.setPosition(20,100)
.setSize(200,40)
.setFont(font)
.setFocus(true)
.setColor(color(255,0,0));
loan.setInputFilter(ControlP5.INTEGER)
;
interest = cp5.addTextfield("Interest Rate")
.setPosition(20,190)
.setSize(200,40)
.setFont(font)
.setFocus(false)
.setColor(color(255,0,0));
interest.setInputFilter(ControlP5.INTEGER)
;
months = cp5.addTextfield("Length in months")
.setPosition(450,100)
.setSize(200,40)
.setFont(font)
.setFocus(false)
.setColor(color(255,0,0));
months.setInputFilter(ControlP5.INTEGER)
;
}
void draw(){
background(120);
fill(255);
noStroke();
rect(0,0,750,70);
fill(20);
textSize(32);
text("Monthly Loan Repayment Calculator ", 70, 45);
fill(41,194,214);
ellipse(340,170,130,130);
fill(24,74,140);
ellipse(340,170,125,125);
fill(255);
textSize(18);
text("Enter 'c'",305,155);
text("to calculate", 295,175);
fill(0);
rect(0,260,700,1);
String loan2 = loan.getText();
String interest2 = interest.getText();
String months2 = months.getText();
if(keyPressed)
{
if(key=='c'||key=='C'&&!loan2.equals("")&&!interest2.equals("")&&!months2.equals ("")){
loan1 = Double.parseDouble(loan2);
interest1 = Double.parseDouble(interest2);
months1 = Double.parseDouble(months2);
interest1=interest1/100/12;
double payment = (loan1*interest1)/(1-Math.pow(interest1+1,-months1));
payment = (double)Math.round(payment*100)/100;
//println(payment);
//text(payment,20,20);
int total = (int)payment;
text(total,200,350);
}
}
}

You are currently checking within your draw() method if a key is pressed or not and only displaying the text field showing the interest computation if the key is currently pressed. This is what
if (keyPressed) {
...
is doing. A better method is to override the actual keyPressed() method (outside of draw()) and set a boolean flag once the 'c' key is pressed. So at the top of your program you'd create something like:
boolean showInterestText = false;
You'd then change your two nested if statements
if(keyPressed)
{
if(key=='c'||key=='C'&&!loan2.equals("")&&!interest2.equals("")&&!months2.equals ("")){
...
to a single if statement like
if (showInterestText) {
...
Finally, override the keyPressed() method to set showInterestText to true if the 'c' key is pressed. Something like:
void keyPressed() {
if (key == 'c' || key == 'C') {
showInterestText = true;
}
}
This way, the showInterestText boolean remains true after the key is no longer pressed.
PS. Welcome to stackoverflow, next time you post please format your code so that it is readable.

Related

How to pick a random string from an array on mouse press in Processing

I want to do the following in Processing:
Display text on the screen
When mouse is not pressed, always display the first string in the array
When mouse is pressed, choose a random string from the array and have this string persist until the mouse is pressed again
I tried moving "int index = int(random(0, 3));" two draw() but this picks a random string many times a second, and I want it to pick it once until I press the mouse again.
In draw(), the value of index is always zero. It only changes in mousePressed().
Here's my code:
String[] sentences = { // defines an array of three strings
"Sentence one",
"Sentence two",
"Sentence three",
};
int index = 0; // initializes variable "index" to zero
void setup() {
size(600, 600);
}
void draw() {
background(255);
fill(0);
text(sentences[index], 10, 100); // picks a random sentence from the array
}
void mousePressed() {
if (mousePressed == true) { // when mouse pressed
int index = int(random(0, 3)); // picks a random value for index: either 0,1,2
}
}
You're experiencing variable shadowing.
This line:
int index = int(random(0, 3)); // picks a random value for index: either 0,1,2
declares index as a local variable, so within that scope only it shadows the global variable.
you probably meant
index = int(random(0, 3)); // picks a random value for index: either 0,1,2
(you're defining and assigning index at the top of your code, but in mousePressed() you just want to assign a different variable to the previously defined variable)
Off topic:
if (mousePressed == true) is the same as if (mousePressed), but in this context (within the mousePressed() function is redundant since it will always be true there
you're not handling the "when the mouse is not pressed" case: mouseReleased() can help with that.
Here's a modified version of your code reflecting the above:
String[] sentences = { // defines an array of three strings
"Sentence one",
"Sentence two",
"Sentence three",
};
int index = 0; // initializes variable "index" to zero
void setup() {
size(600, 600);
}
void draw() {
background(255);
fill(0);
text(sentences[index], 10, 100); // displays sentence at index from the array
}
// when mouse pressed
void mousePressed() {
index = int(random(3)); // picks a random value for index: either 0,1,2
}
// when mouse released
void mouseReleased() {
index = 0; // always displays the 1st sentence when mouse is not pressed
}

Alter Textfield functionality ControlP5

I would like to remove some of the functionality of a Textfield.
When the enter or return keys are pressed, the field becomes empty. I would like the value entered to stay within the field.
I have tried overriding the submit method but this hasn't done the job:
widthTopField = new Textfield(controlP5, "widthField"){
# Override public Textfield submit(){
return this;
}
};
Demonstrates using .setAutoClear() to retain edit field contents after hitting return button. Field 1 is set to true and the other is set to false.
import controlP5.*;
ControlP5 cp5;
void setup() {
size(400,400);
PFont font = createFont("arial",18);
cp5 = new ControlP5(this);
cp5.addTextfield("Field 1")
.setPosition(40,50)
.setSize(200,40)
.setFont(font)
.setFocus(true)
.setColor(color(255))
.setAutoClear(true);
;
cp5.addTextfield("Field 2")
.setPosition(40,130)
.setSize(200,40)
.setFont(font)
.setAutoClear(false);
;
}
void draw() {
background(0);
}

Toggle function not working in Processing (ControlP5)

I just made my image generator work with PNG files. For now, it's divided into 3 categories (backgrounds, objects & texts). These are now all combined, and with every mouse click it randomises these PNGs.
I made three toggles, where you could to choose to show either the background and the objects on top, all of them, or all separate. Whenever I run the sketch, it shows the "grey" background, but when I use the toggles, it doesn't show anything, or shows a flickering image, where the mouse-click can't be used to go to the next image. I can't seem to find the problem. Hopefully, you can help. :)
import controlP5.*;
boolean showBackground = false;
boolean showObjects = false;
boolean showGrids = false;
ControlP5 cp5;
PImage[] myImageArray = new PImage[8];
PImage[] myImageArray2 = new PImage[15];
PImage[] myImageArray3 = new PImage[15];
void setup() {
size(1436, 847);
background(211, 211, 211);
for (int i=0; i<myImageArray.length; i++) {
myImageArray[i] = loadImage ( "o" + i + ".png");
myImageArray2[i] = loadImage ( "g" + i + ".png");
myImageArray3[i] = loadImage( "b" + i + ".jpg");
cp5 = new ControlP5(this);
// create a toggle and change the default look to a (on/off) switch look
cp5.addToggle("showBackground")
.setPosition(40, 250)
.setSize(50, 20)
.setValue(true)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showObjects")
.setPosition(40, 400)
.setSize(50, 20)
.setValue(true)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showGrid")
.setPosition(40, 600)
.setSize(50, 20)
.setValue(true)
.setMode(ControlP5.SWITCH);
}
display();
}
void display() {
image(myImageArray3[(int)random(myImageArray.length)], 0, 0, 1436, 847); // b
image(myImageArray2[(int)random(myImageArray.length)], 0, 0, 1436, 847); // g
image(myImageArray[(int)random(myImageArray.length)], 0, 0, 1436, 847); // o
}
void mousePressed() {
display();
}
void draw() {
pushMatrix();
if (showBackground==false) {
image(myImageArray3[(int)random(myImageArray.length)], 0, 0, 1436, 847); // b
} else {
background(211, 211, 211);
}
if (showGrids==false) {
image(myImageArray2[(int)random(myImageArray.length)], 0, 0, 1436, 847); // g
} else {
background(211, 211, 211);
}
if (showObjects==false) {
image(myImageArray[(int)random(myImageArray.length)], 0, 0, 1436, 847); // o
} else {
background(211, 211, 211);
}
popMatrix();
}
Here are a couple of things where the logic your wrote in your code might not match what you had in mind:
When you call display() on mouse it renders those 3 images once (also it will be different images within those since it's using a randomised index). Similarly in draw(), when an does get picked to be rendered, frames will be flickering fast as a random index is generated multiple times per second(each frame). You may want to randomise indices in a different event (e.g. mouse or key press) and store this value in a variable you can re-use.
the conditions you use in draw(): you probably meant to check if the values are true(toggled enabled/turned on in controlP5) ? (e.g. e.g. if (showBackground==true) and initialise the toggles with false, instead of true?)
a big one: in draw() , after each condition(showBackground,showGrids,showObjects), if it's false, you're clearing the the whole frame (so a previous image would be erased)
you have 3 arrays, but you use the size of the first(myImageArray.length) only, which means, even though you may have more images for myImageArray2 and myImageArray3, you're not loading, nor displaying them.
The third grid is labeled "showGrid" when it should be "showGrids": if you aren't consistent with the toggle labels and variable names, toggles won't update the variable names.
you should use more descriptive names for the arrays: it will make it easier to scan/follow your code on the long run.
there's no need to add toggles multiple times in the for loop where you load images: once will do.
Here's what I mean:
import controlP5.*;
boolean showBackground = false;
boolean showObjects = false;
boolean showGrids = false;
ControlP5 cp5;
PImage[] objects = new PImage[8];
PImage[] grids = new PImage[15];
PImage[] backgrounds = new PImage[15];
int currentImage = 0;
void setup() {
size(1436, 847);
//load objects
for (int i=0; i<objects.length; i++) {
objects[i] = loadImage ( "o" + i + ".png");
}
//load grids
for(int i = 0 ; i < grids.length; i++){
grids[i] = loadImage ( "g" + i + ".png");
}
//load backgrounds
for(int i = 0 ; i < grids.length; i++){
backgrounds[i] = loadImage( "b" + i + ".jpg");
}
//setup UI
cp5 = new ControlP5(this);
// create a toggle and change the default look to a (on/off) switch look
cp5.addToggle("showBackground")
.setPosition(40, 250)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showObjects")
.setPosition(40, 400)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH);
cp5.addToggle("showGrids")
.setPosition(40, 600)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH);
}
void mousePressed() {
//go to next image index
currentImage = currentImage + 1;
//check if the incremented index is still valid, otherwise, reset it to 0 (so it doesn't go out of bounds)
if (currentImage >= objects.length) {
currentImage = 0;
}
}
void draw() {
//clear current frame
background(211);//for gray scale value you can just use one value: the brightness level :)
if (showBackground==true) {
image(backgrounds[currentImage], 0, 0, 1436, 847); // b
}
if (showGrids==true) {
image(grids[currentImage], 0, 0, 1436, 847); // g
}
if (showObjects==true) {
image(objects[currentImage], 0, 0, 1436, 847); // o
}
}
Note that currently the same index is used for all 3 arrays.
You may want to add a separate index variable for each array (e.g. currentObjectIndex, currentBackgroundIndex, currentGridIndex) that you can increment independently of each other.
I recommend having a bit more patience and double checking your code first.
Visualise what each line of code will do, then check if it actually does what you expect it to do. Either you will learn something new or improve your logic.
Also, if mentally joggling 3 arrays is tricky (and it can be), go one step back: try your logic with one array only until you get the hang of it, then move on.
A step backwards is sometimes a step forward when you're going in the wrong direction.
As creative as you'd like to be with Processing, bare in mind, the interface to plugging your ideas to it is still a series of one instruction at a time, each precisely tuned to do exactly what you want it to do. There's room for fun, but unfortunately you need to get past the boring parts first

How Processing knows that user is pressing multiple key at the same time?

I have no idea how Processing knows that a user is pressing Ctrl and some character at the same time.
Multiple buttons at same time only. Is it possible?
ex: (Ctrl+r).
You have to first check if Ctrl has been pressed. If it has been pressed then you save a boolean as true. The next time you press a button you check if the button is the button you want (i.e. 'r') and if the boolean is true. If both are true then Processing knows...
Here's a demonstration:
boolean isCtrlPressed = false;
boolean isRPressed = false;
void draw() {
background(0);
fill(255);
if (isCtrlPressed) background(255, 0, 0);
if (isRPressed) background(0, 255, 0);
if (isCtrlPressed && isRPressed) background(255, 255, 0);
}
void keyPressed() {
if (keyCode == CONTROL && isCtrlPressed == false) isCtrlPressed = true;
if (char(keyCode) == 'R') isRPressed = true;
}
void keyReleased() {
if (keyCode == CONTROL) isCtrlPressed = false;
if (char(keyCode) == 'R') isRPressed = false;
}
I know this is a very old feed, but I have something that might help everyone with multiple key presses. This is for Processing's Python Mode, but I'm sure it can be implemented in some way for other modes.
import string
#string.printable is a pre-made string of all printable characters (you can make your own)
keys = {}
for c in string.printable:
#set each key to False in the keys dictionary
keys[c] = False
def keyPressed():
#If key is pressed, set key in keys to True
keys[key] = True
def keyReleased():
#If key is released, set key in keys to False
keys[key] = False
And then using multiple if statements, you can check the dictionary for whether the key is pressed or not.
if keys['w'] == True:
#Do something
if keys['s'] == True:
#Do something
if keys['a'] == True:
#Do something
if keys['d'] == True:
#Do something
if keys[' '] == True:
#Do something
And so on.
Hope this helps!
You could also override the keyPressed(KeyEvent) method and use the KeyEvent.isControlDown() method:
void keyPressed(KeyEvent ke) {
println(ke.isControlDown());
}
void draw(){
//need draw() method for keyPressed() to work
}
you can find out the "key" codes of any combination of "ctrl + *" or "Shift + *" by typing, but this method is not suitable for multi-clicking to control the game.
combination search code
void setup()
{
textAlign(CENTER,CENTER);
}
void draw()
{
background(0);
text(int(key),50,50);
}

List of Scrollable Checkboxes in Processing

I am a newbie to programming GUIs and Processing. My questions is how can I get a list of checkboxes that I can scroll through? What I want is exactly the list of countries on the right here (http://goo.gl/MIKHi4).
I looked through the ControlP5 library and was able to find Checkboxes, but I don't know how I can make a scrollable list of them.
Thank you.
I had also been searching for this last week and hoping that there was a ready-for-use library for me to easily add the scrollable checkboxes to my application, but finally I had no luck. At last, what I did was implementing my own scrollable list of checkboxes.
Firstly, I added a ControlP5 slider as the scroll bar, and then at each frame, got value from the slider and draw the specific checkboxes based on that value.
Suppose that you have a list of 200 countries for the user to select. Then the code will be like:
ControlP5 cp5;
Slider scrollBar;
PFont fLabel;
int boxOver = -1; //Indicate mouse is over which checkbox
boolean[] boxSelected; //Checkbox selected or not
void setup() {
size(1024, 800);
colorMode(HSB, 360, 100, 100);
cp5 = new ControlP5();
scrollbar = cp5.addSlider("scrollbar")
.setPosition(1005, 110)
.setRange(0, 180)
.setSize(15, 490)
.setHandleSize(30)
.setSliderMode(Slider.FLEXIBLE)
.setValue(180); //Put handler at top because 0 value is at bottom of slider
fLabel = createFont("Arial", 12, false);
boxSelected = new boolean[200];
for(int i=0;i<200;i++) {
boxSelected[i] = false;
}
}
void draw() {
noFill();
stroke(200, 255);
rect(820, 110, 200, 490); //The outline of the scrollable box
stroke(150, 255);
int count = 0;
//Suppose that you want to display 20 items each time
for(int i=180-(int)scrollBar.getValue();i<180-(int)scrollBar.getValue()+20;i++) {
if(boxOver < 0) {
if(mouseX>=825 && mouseX<837 && mouseY >= 120+count*24 && mouseY <= 132+count*24) {
boxOver = i;
cursor(HAND);
}
}
if(boxSelected[i]) {
fill(50); //If the box is selected, fill this box
} else {
fill(360);
}
rect(825, 120+count*24, 12, 12); //Draw the box
//Draw the label text
textFont(fLabel);
fill(50);
text(countries[i], 843, 132+count*24); //Suppose the country names are stored in countries[]
count++;
}
}
void mousePressed() {
if(boxOver >=0) {
boxSelected[boxOver] = !boxSelected[boxOver]; //Toggle selection
}
}
Hope this helps you, or anyone who may encounter the same problem in the future.
There is now an example in the experimental examples called ControlP5SliderList

Resources