Processing button events - java

I'm trying to implement sort of a popup window to display information about authors in given country i managed to do this. I load my interactive map and I do get a popup message when I left click on the country. However soon as I release the button, the popup disappears.
I want to popup that is drawn to stay there until I right click on right click it should disappear.
So I'm having problems implementing it so that popup that is displayed in mouseReleased() method stays drawn.
// Import libaries
import org.gicentre.geomap.io.*;
import org.gicentre.geomap.*;
// Instance new GeoMap
GeoMap geoMap;
PImage bgImage;
void setup()
{
size(1280, 768);
// Load background pattern img and implement AA for shapes
bgImage = loadImage("bg.jpg");
smooth();
// New GeoMap instance
geoMap = new GeoMap(this);
// Load map shape
geoMap.readFile("world");
}
void draw()
{
// Fill ocean with bg image
background(bgImage);
// Change stroke color
stroke(255, 255, 255);
// Fill the continents color and draw the map
fill(26, 117, 181);
geoMap.draw();
// Get country id by mouse location
int countryID = geoMap.getID(mouseX, mouseY);
// Offgrid: -1
if (countryID != -1)
{
// Listen for mouse event and trigger action
mouseReleased(countryID);
// Color the select country
fill(14, 96, 166);
geoMap.draw(countryID);
}
}
void mouseReleased(int countryID)
{
// Act on left clicks
if(mouseButton == LEFT)
{
println(getCountryName(countryID, 3));
noStroke();
fill(255, 192);
rect(0, 0, width, 20);
if (countryID != -1)
{
String name = getCountryName(countryID, 3);
fill(0);
textAlign(LEFT, CENTER);
text(name, 0, 0, width, 20);
}
}
}
// Returns country name by id
String getCountryName(int id, int offset)
{
// Get country name for query
// getString(int id, int offset), int id: country id, int offset:
// Example USA
// offset 0 = Country Code -> 257
// offset 1 = Country Short Tag -> US
// offset 2 = Country Short Name -> USA
// offset 3 = Official Name -> United States
String name = geoMap.getAttributes().getString(id, offset);
return name;
}

The problem is that your draw function repeats continuously, but you are only drawing when the lmb is pressed. As soon as it is released, the next call to draw will draw over your popup.
One way to solve this would be to store a variable (say "shouldDraw") to tell you whether to draw or not. When the lmb is pressed, you would set this to true, and when the rmb is pressed, you would set it to false. Then instead of checking for LEFT, you would check shouldDraw.
I'm not familiar with the framework you're using, but there may be an onClick method or similar, which would be a more appropriate place than draw for changing you shouldDraw variable.
This will make the label change if you click and then move the mouse. If you want the same text to remain, you could instead store a String and set it to null when there is nothing to draw.

There is a built in function called mouseReleased that takes no parameter in Processing. You are overloading it intentionally?
Any way this is a bit confusing. I would do some thing like this:
(pseudocode)
void setup() {
// stuff
}
void draw()
{
if (id != -1)
drawPopup(id);
}
void mouseReleased() //default method called when mouse is released
{
if (mouseButton == LEFT)
id = geoMap.getID(mouseX, mouseY);
}
void drawPopup(int id){
println(getCountryName(countryID, 3));
noStroke();
fill(255, 192);
rect(0, 0, width, 20);
if (countryID != -1)
{
String name = getCountryName(id, 3);
fill(0);
textAlign(LEFT, CENTER);
text(name, 0, 0, width, 20);
}
}
This way there will always be a popup after the first, or you need to reset the id to -1 in proper condition or add the boolean suggested by mdgeorge. But usually it is better not to do draw stuff inside mouse functions. Things get easier to control.
edit: I should have pointed that there is also built in void mousePressed() and void mouseClicked() and some more check the reference.

Related

Java animation about reframing an image

Hi I am currently making a program that will show a spring that moves with the values that I enter and uses the formulas of physics. The problem is that, when I create a spring and make the animation start, the old image stays there and overrides without deleting the one before here's the code of the problem :
bouton3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
/*anime.animer();
anime.repaint();*/
for (int t = 0; t < 500; t += 5) {
for (int i = 105; i < 175; i += 5) {
Ellipse2D elp1 = new Ellipse2D.Double(i, 100, 15, 30);
((Graphics2D) dessinPanel.getGraphics()).draw(elp1);
}
for (int i = 105; i < 175; i += 5) {
Ellipse2D elp1 = new Ellipse2D.Double(i, 100, 15 + osi.simuler(t), 30);
((Graphics2D) dessinPanel.getGraphics()).draw(elp1);
dessinPanel.repaint();
Rectangle2D rect = new Rectangle2D.Double(186 + osi.simuler(t), 90, 50, 50);
((Graphics2D) dessinPanel.getGraphics()).draw(rect);
dessinPanel.repaint();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Here`s also some pictures to show the problem:
before
after
You need to decouple your painting from your value adjustments.
Your painting operation should start by clearing the background, then paint the spring and box using the current input values.
When an input value changes, simply update the variable and invalidate() the display area.
For better performance, clearing the background can also be done by drawing the spring and box at their current positions in the background color. This also makes the updating of the input values more difficult.
One more technique you might use would be to widen the brush and draw first in the background color, then shrink the brush and draw the actual spring and rectangle in their correct form. This would be equivalent to erasing the background as long as you control the amount either can move in a single frame.

How to merge two programs on processing ide in order to run them sequentially?

I am trying to merge two programs. One is for a video player that plays the intro video, and the other is for displaying a radar (I found the coding online). What I want to do is, play the video first, which is an introduction to the Radar, and then have the radar displayed. The radar display is linked with Arduino Mega 2560 and that has its own coding. Here are the two codes.
import processing.video.*;
String PATH = "D:\\FullZord.mp4";
Movie mov;
void setup()
{
size(1920, 1080);
frameRate(30);
mov = new Movie(this, PATH);
mov.play();
mov.speed(1);
mov.volume(10);
}
void movieEvent(Movie m)
{
m.read();
}
void draw()
{
image(mov, 0, 0, width, height);
}
and
import processing.serial.*; // imports library for serial communication
import java.awt.event.KeyEvent; // imports library for reading the data from the serial port
import java.io.IOException;
Serial myPort; // defines Object Serial
// defubes variables
String angle="";
String distance="";
String data="";
String noObject;
float pixsDistance;
int iAngle, iDistance;
int index1=0;
int index2=0;
PFont orcFont;
void setup()
{
size (1920, 1080);
smooth();
myPort = new Serial(this,"COM4", 9600); // starts the serial communication
myPort.bufferUntil('.'); // reads the data from the serial port up to the character '.'. So actually it reads this: angle,distance.
orcFont = loadFont("OCRAExtended-30.vlw");
}
void draw()
{
fill(98,245,31);
textFont(orcFont);
// simulating motion blur and slow fade of the moving line
noStroke();
fill(0,4);
rect(0, 0, width, 1010);
fill(98,245,31); // green color
// calls the functions for drawing the radar
drawRadar();
drawLine();
drawObject();
drawText();
}
void serialEvent (Serial myPort)
{ // starts reading data from the Serial Port
// reads the data from the Serial Port up to the character '.' and puts it into the String variable "data".
data = myPort.readStringUntil('.');
data = data.substring(0,data.length()-1);
index1 = data.indexOf(","); // find the character ',' and puts it into
the
variable "index1"
angle= data.substring(0, index1); // read the data from position "0" to position of the variable index1 or thats the value of the angle the Arduino Board sent into the Serial Port
distance= data.substring(index1+1, data.length()); // read the data from position "index1" to the end of the data pr thats the value of the distance
// converts the String variables into Integer
iAngle = int(angle);
iDistance = int(distance);
}
void drawRadar()
{
pushMatrix();
translate(960,1000); // moves the starting coordinats to new location
noFill();
strokeWeight(2);
stroke(98,245,31);
// draws the arc lines
arc(0,0,1800,1800,PI,TWO_PI);
arc(0,0,1400,1400,PI,TWO_PI);
arc(0,0,1000,1000,PI,TWO_PI);
arc(0,0,600,600,PI,TWO_PI);
// draws the angle lines
line(-960,0,960,0);
line(0,0,-960*cos(radians(30)),-960*sin(radians(30)));
line(0,0,-960*cos(radians(60)),-960*sin(radians(60)));
line(0,0,-960*cos(radians(90)),-960*sin(radians(90)));
line(0,0,-960*cos(radians(120)),-960*sin(radians(120)));
line(0,0,-960*cos(radians(150)),-960*sin(radians(150)));
line(-960*cos(radians(30)),0,960,0);
popMatrix();
}
void drawObject()
{
pushMatrix();
translate(960,1000); // moves the starting coordinats to new location
strokeWeight(9);
stroke(255,10,10); // red color
pixsDistance = iDistance*22.5; // covers the distance from the sensor from cm to pixels
// limiting the range to 40 cms
if(iDistance<40){
// draws the object according to the angle and the distance
line(pixsDistance*cos(radians(iAngle)),-pixsDistance*sin(radians(iAngle)),950*cos(radians(iAngle)),-950*sin(radians(iAn
gle)));
}
popMatrix();
}
void drawLine()
{
pushMatrix();
strokeWeight(9);
stroke(30,250,60);
translate(960,1000); // moves the starting coordinats to new location
line(0,0,950*cos(radians(iAngle)),-950*sin(radians(iAngle))); // draws the line according to the angle
popMatrix();
}
void drawText()
{ // draws the texts on the screen
pushMatrix();
if(iDistance>40)
{
noObject = "Out of Range";
}
else
{
noObject = "In Range";
}
fill(0,0,0);
noStroke();
rect(0, 1010, width, 1080);
fill(98,245,31);
textSize(25);
text("10cm",1180,990);
text("20cm",1380,990);
text("30cm",1580,990);
text("40cm",1780,990);
textSize(40);
text("Object: " + noObject, 240, 1050);
text("Angle: " + iAngle +" °", 1050, 1050);
text("Distance: ", 1380, 1050);
if(iDistance<40)
{
text(" " + iDistance +" cm", 1400, 1050);
}
textSize(25);
fill(98,245,60);
translate(961+960*cos(radians(30)),982-960*sin(radians(30)));
rotate(-radians(-60));
text("30°",0,0);
resetMatrix();
translate(954+960*cos(radians(60)),984-960*sin(radians(60)));
rotate(-radians(-30));
text("60°",0,0);
resetMatrix();
translate(945+960*cos(radians(90)),990-960*sin(radians(90)));
rotate(radians(0));
text("90°",0,0);
resetMatrix();
translate(935+960*cos(radians(120)),1003-960*sin(radians(120)));
rotate(radians(-30));
text("120°",0,0);
resetMatrix();
translate(940+960*cos(radians(150)),1018-960*sin(radians(150)));
rotate(radians(-60));
text("150°",0,0);
popMatrix();
}
You're going to have to read the reference material for the video library. You're looking for a way to detect when the movie is playing, or when it's stopped. It's probably something like an isPlaying() function in the Movie class.
When you have that, you can call that in the draw() function to detect whether the movie is still playing. If so, draw it. If not, then show the radar.
But start smaller. First off, can you just print something to the console when the movie is done playing? Build off of that.
Also, I highly recommend that you don't just use code that you copy-pasted from the internet. That's only going to give you a ton of headaches. Instead, try to understand exactly what the code is doing. Otherwise it's going to be impossible to debug or make changes. You need to really understand the code before you can use it.
Solved it! I just used a time-delay function. This one.
if (millis() > 1000) {
// do something
}

How to avoid overlapping of title of marker in unfolding maps?

I am using unfolding maps to create markers.When a user hovers over a marker the title is displayed.But the other markers overlap the title so it hides the information presented in title. To prevent from this, i used PGraphics to draw the title as:
public void showTitle(PGraphics pg, float x, float y)
{
String name = getCity() + " " + getCountry() + " ";
String pop = "Pop: " + getPopulation() + " Million";
/
/buffer is defined already.
buffer.beginDraw();
buffer.fill(255, 255, 255);
buffer.textSize(12);
buffer.rectMode(PConstants.CORNER);
buffer.rect(x, y-TRI_SIZE-39, Math.max(pg.textWidth(name), pg.textWidth(pop)) + 6, 39);
buffer.fill(0, 0, 0);
buffer.textAlign(PConstants.LEFT, PConstants.TOP);
buffer.text(name, x+3, y-TRI_SIZE-33);
buffer.text(pop, x+3, y - TRI_SIZE -18);
buffer.endDraw();
}
And then drawing buffer on screen through method
public void draw() {
map.draw();
image(buffer, 0,0);
}
It resolves the problem, now the title is not overlapped with markers but its not drawn right below the marker instead its drawn some where random on screen as shown in image
How can i avoid it? Any help please.
You need to store the position of the buffer before you draw it. Basically, you need to change this line:
image(buffer, 0,0);
To something like this:
image(buffer, bufferX, bufferY);
You'll have to calculate bufferX and bufferY depending on where you want the buffer to show up. A very dumb implementation might be something like this:
public void showTitle(PGraphics pg, float x, float y)
{
bufferX = x;
bufferY = y;
//rest of your code
I'm not familiar enough with Unfolding Maps to tell you exactly what to do, but those are the basics. Note that Unfolding Maps might be doing its own translations, so you might have to use the pushMatrix() and popMatrix() functions. Also note that you might need to project from map space to screen space. The Unfolding Maps library probably has documentation on how to do that.
In setup you created a map with some size and offset. Buffer should be created with same size.
But most important is to draw buffer with same offset.
Your title is just drawn with negative offset, not random.
private PGraphics buffer;
public void setup() {
size(900, 700);
//Create map with offset
map = new UnfoldingMap(this, 200, 50, 650 ,600, new Google.GoogleMapProvider());
//Create buffer, same size as map
buffer = createGraphics(650, 600);
//rest of the code..
}
public void draw() {
background(0);
map.draw();
//put buffer over the map, with same offset
image(buffer, 200, 50);
}
I took the same Coursera course (Object Oriented Programming in Java) and worked on fixing this feature as well. Here is how I fixed this problem.
I realized that the titles are covered because the markers are drawn over and over inside the map.draw() method in draw() section of the EarthquakeCityMap class. So the fix would be moving the showTitle implementation from marker classes to the EarthquakeCityMap class, and let the title be drawn at the screen position of the markers instead of latitude and longitude.
The SimplePointMarker class in UnfoldingMaps Library has a method getScreenPosition() inherited from AbstractMarker class. See the JavaDoc for more details. Because the CommonMarker class is a subclass of SimplePointMarker class, and EarthquakeMarker class is a subclass of the CommonMarker, EarthquakeMarker class has the getScreenPosition() method available as default as well.
Below is how the method of showing earthquake titles look like in the EarthquakeCityMap.java file. Please note that you can use Processing's graphics methods here automatically because the EarthquakeCityMap class extends PApplet.
/** Show the title of the earthquake if this marker is selected */
private void showEqTitle(EarthquakeMarker m, UnfoldingMap map)
{
float x = m.getScreenPosition(map).x;
float y = m.getScreenPosition(map).y;
String title = m.getTitle();
pushStyle();
rectMode(PConstants.CORNER);
stroke(110);
fill(255,255,255);
rect(x, y + 15, textWidth(title) + 6, 18, 5);
textAlign(PConstants.LEFT, PConstants.TOP);
fill(0);
text(title, x + 3 , y +18);
popStyle();
}
And here is how I implement the method above in the draw() function.
public void draw() {
background(0);
map.draw();
addKey();
for (Marker m: quakeMarkers) {
EarthquakeMarker eq = (EarthquakeMarker) m;
if (m.isSelected()) {
showEqTitle(eq, map);
}
}
}
Finally, here's the resulting image showing the titles are no longer covered by the markers. Horray~
The earthquake map display when the mouse hovers one of the earthquake marker

why is the Color of my object changing randomly?

I have two copies of an object in my container, and they are synchronized (not in the Java sense, only in that whatever I do to one, I also do to the other). They both trace out a pattern drawn using the arrow keys.
The problem is that the Color randomly reverts to black occasionally, unpredictably (and not at the same time for both objects).
Here is what I believe to be all the relevant code; surely all the times setColor is called:
public class UserRavelDialog extends Component implements Runnable {
...
in init():
colors = new Color[] {
new Color (245, 240, 80), //set colors for the elements
new Color (100, 50, 50),
new Color (255, 0, 0),
new Color (255, 0, 200),
new Color (0, 0, 200)};
bb.setColor(colors[0]); //bb is the backbuffer graphics object
public void render(){ //this draws the current color around a black cursor, or white if inactive
Color temp = bb.getColor();
if(temp.equals(Color.black))
System.out.print("!");
if (!isActive)
bb.setColor(Color.white);
bb.fillRect((int)p.x - 1, (int)p.y - 1, 3, 3); //p is a Point2D.Double for the cursor position
bb.setColor(Color.black);
bb.fillRect((int)p.x, (int)p.y, 1, 1);
bb.setColor(temp);
update(getGraphics());
}
private void toggleColour(int arg) {
if (arg < colors.length)
bb.setColor(colors[arg]);
}
public void keyPressed(KeyEvent e){
for (int i = 0 ; i < colors.length ; i++){
if (e.getKeyCode() == keys[i+9])
toggleColour(i);
}
}
So, setColor is called in init, when I create the possible color options, and in toggleColour when the user presses a key to change the color, and it is used in render, but always re-set to the current color.
The weird thing is the if (temp.equals(Color.black)) condition gets entered when the flip happens, so it seems like the bb.setColor(temp) just didn't happen on the previous render...
Why does this happen and how can I fix it?
This solution solves the problem, even though I don't understand why the original program doesn't work.
If you create a (global) Color variable, and set this variable in init and toggleColour, you can use it in render and you don't need to worry about the temp variable (the only instance of the color you want to get back) somehow being lost. So:
in init():
currColor = colors[0];
bb.setColor(currColor);
public void render(){
if (!iActive)
bb.setColor(Color.white);
bb.fillRect((int)p.x - 1, (int)p.y - 1, 3, 3);
bb.setColor(Color.black);
bb.fillRect((int)p.x, (int)p.y, 1, 1);
bb.setColor(currColor);
update(getGraphics());
}
private void toggleColour(int arg) {
if (arg < colors.length) {
currColor = colors[arg];
bb.setColor(currColor);
}
}

User-selected marker in time series data in Java

My code plots 5000 points of time series data in a panel that is 581 pixels wide by default, but this width changes when the user resizes the window. My code also plots several rectangular markers that each identify a local maximum/peak in this same space.
I need to enable the user to right click on any of the rectangular-peak-markers so that the user can manually delete any false peak. The problem is that my code is reporting different x-coordinates than expected when the user right-clicks on a peak-marker. I suspect that the reason may have to do with rounding error in converting from 581 x-pixels back to 5000 data indices. But I am not certain of the reason.
Can anyone suggest a solution that enables my users to manually select one of the above-described peak markers by right-clicking on it?
I am enclosing relevant sections of the code below. My actual code is very, very long, and too complicated to post. But the relevant portions below should be enough for someone to see the logic of my approach, and to then suggest a more effective approach.
The code that declares the class in question is:
class SineDraw extends JPanel implements MouseMotionListener, MouseListener {
// lots of code, including the two segments excerpted below
}
This segment of code overloads the paintComponent of the JPanel so that my data is plotted:
// declare some variables
ArrayList<Double> PeakList = new ArrayList<Double>() // this ArrayList is populated by an extraneous process
visiblePoints = 5000
hstep = getWidth()/visiblePoints //=581/5000 by default, but will change when user resizes window
int numPeaks = PeakList.size();
// scale (y-coordinate) data relative to height of panel
pts = new double[visiblePoints]
for (int i = 0; i < pts.length-1; i++){pts[i]=//data vertical scaled to fill panel;}
// plot the 5000 time-series-data-points within the 581 pixels in x-axis
for (int i = 1; i < visiblePoints; i++) {
int x1 = (int) ((i - 1) * hstep);
int x2 = (int) (i * hstep);
int y1 = (int)pts[i - 1];
int y2 = (int)pts[i];
g2.drawLine(x1, y1, x2, y2);
}
// plot a rectangle for each of the local peaks
for(int m=0;m<=(numPeaks-1);m++){
if(i==(int)(PeakList.get(m)){
int currentVal = (int)pts[(int)(PeakList.get(m)];
g2.drawRect((int)(PeakList.get(m), currentVal, 6, 6);
}
}
This section of code is for handling the right-clicking of the mouse:
public void mousePressed(MouseEvent e){
// check to see if right mouse button was clicked
boolean jones = (e.getModifiers()&InputEvent.BUTTON3_MASK)==InputEvent.BUTTON3_MASK;
if(jones==true){
// test the value returned as x-coordinate when user right-clicks (code always underestimates x-coordinate of local peaks by this test)
double ReverseHstep = visiblePoints/getWidth();
int getX_ConvertedTo_i = (int) (e.getX()*ReverseHstep);
System.out.println("getX_ConvertedTo_i is: "+getX_ConvertedTo_i );
// check to see if peaklist contains a value within the x-coordinates of the user-selected-rectangle
if(PeakList.contains((double)(e.getX()-3))
||PeakList.contains((double)(e.getX()-2))
||PeakList.contains((double)(e.getX()-1))
||PeakList.contains((double)(e.getX()))
||PeakList.contains((double)(e.getX()+1))
||PeakList.contains((double)(e.getX()+2))
||PeakList.contains((double)(e.getX()+3))
){
// handling code will go here, but for now it is a print test that never succeeds because x-coordinate is always underestimated
System.out.println("You just selected a peak!");
}
}
repaint();
}
I suggest you create objects (in this case Rectangles) for each thing you want to be clickable. Here is an over-simplified example of how you can make something you draw clickable. The key thing to take away from this is the mouseClicked method which will display a dialog only if the mouse clicked within the rectangle.
One tricky point is that I wasn't able to figure out how to make the rectangle filled in with color without drawing another rectangle over it. I'll leave that one for you ;-)
public class Canvas extends JPanel implements MouseListener{
private Rectangle rect = new Rectangle(100,100);
public Canvas(){
this.addMouseListener(this);
rect.setSize(100, 100);
}
#Override
public void paintComponent(Graphics g){
g.setClip(rect);
g.setColor(Color.RED);
g.fillRect(0, 0, 100, 100);
}
#Override
public void mouseClicked(MouseEvent e){
if(rect.contains(e.getPoint())){
JOptionPane.showConfirmDialog(this, "Click!");
}
}
// The rest of the MouseListener methods have been cut out
public static void main(String[] a){
JFrame frame = new JFrame("Canvas Thingy");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 300);
frame.add(new Canvas());
frame.setVisible(true);
}
}

Categories