Loading...
Logo
Processing Forum
Hi,

I'm really new to programming and I need a bit of help. I want to write an app that has a bank of elements (PImage or Shape elements) on the left and a background image on the right. I want to be able to click on the elements on the left to add them to the image one at a time (or drag it on to the canvas), and I want to be able to resize the elements individually.

Is Processing capable of this? I know that might sound confusing, so I'll start with just one question. In this example have commented out the images and replaced them with rectangles. I want to be able to manipulate each rectangle individually, without affecting the other one. In my app, I want these to be images (.png) rather than shapes.

Now that I've typed this out. I feel like I should be able to answer my own question, but I'm stumped. Maybe I've been looking at this too long.

Thanks in advance!

Copy code
  1. //PImage clv;
  2. Tree tree;
  3. Tree tree2;

  4. void setup() {
  5.   size(800, 500);
  6.   smooth();
  7.   imageMode(CENTER);
  8. //  clv = loadImage("clv.png");
  9. //  tree = new Tree("tree.gif", 50, 50);
  10. //  tree2 = new Tree("tree.gif", 33, 60);
  11.   tree = new Tree(50,50);
  12.   tree2 = new Tree(150,150);
  13. }

  14. void draw() {
  15. //  background(clv);
  16.   background(150);
  17.   tree.display();
  18.   tree.move();
  19.   tree2.display();
  20.   tree2.move();
  21. }

  22. class Tree {
  23.   PImage tree;
  24.   float x,y;

  25.   Tree(
  26.   //String filename,
  27.   float x_, float y_) {
  28. //    tree = loadImage(filename);
  29.     x = x_;
  30.     y = y_;
  31.   }
  32.   
  33.   void display() {
  34. //    translate(x,y);
  35. //    image(tree, x, y);
  36.     rect(x,y,100,200);
  37.   }
  38.   
  39.   void move() {
  40.     if (mousePressed) {
  41.       x=mouseX;
  42.       y=mouseY;
  43.     }
  44.   }
  45. }

Replies(13)

PDE > File > Examples... > GUI > Handles or Scrollbar examples from Processing show how to handle dragging a shape.
Humm, I had a look at those. I'll look again. I think I need to try again and start from scratch. 

Thanks
look at



for drag handle re-sizing. Note moving and re-sizing both are drag operations, So there needs to be mode change to display the drag handles, while still supporting the move drag. The example above just addresses the drag handles. Adding the move capability should give you what you need.

Note the drag re-size example supports edge and corner move, but does not support shift-corner move,needed to maintain aspect ratio during re-size. It should be easy to add.


Note, your code is stacking the rectangles, thus the second one disappears.

 Being new to programming you might want to tackle creating a class for you bank element. This will permit creating a set of attributes you would be manipulating via the mouse actions.

Creating you first classes can be daunting. Outlining possible scenario can be very helpful in organizing requirements. For example:

Setup: 
5 pictures to be arranges, movable and re-sizable.

Scenario A: select picture
1. User clicks on picture (mouse pressed and mouse released)
Question to answer:
  which picture?
Action to take: 
2.  for picture selected show resize handles.
(need global variable for 
      current selected picture
      selection state)
Scenario B: move picture
1. user presses mouse
Question: which picture
Action take: record start mouse position
                  current selected picture
                  dragging state (mouse pressed & picture found)
2. Mouse moves:
     compute delta from initial mouse position
      adjust current selected picture x & y position based on delta 
      store new start mouse position
      draw picture
   repeat 2 until mouse released
3. mouse released
      clear drag state
      clear current selection

Note: when checking mouse presses there are 5 pictures that need to be checked and if in select mode 8 resize handles.

Maintaining an arrayList of the pictures and adding support in the bank element class to support dragging will make checking to see if the mouse press is in a target.

Scenario 3: Re-size operation
1. user selects picture (Scenario A)
2. use mouse presses re-size handle.
Which picture or if selection mode which handle
      resize handle NW corner pressed.
      record start mouse position
      in selected picture record handle selected
3. mouse moved
      compute delta
      call drag method of selected picture with mouse delta (this will resize picture and adjust handles)
      record start mouse position
      draw picture
      repeat 3 until mouse released
4. Mouse released
      resize selected picure based on handle positions
      in selected picture clear resize handle state

So roughly the Bank Element will keep track: of
   x, y, width, height
   resize handle state
   active resize handle
  selected state 
  DragHandles
with methods to
   draw()
   check mouse click in picture(x,y)
   check mouse click in resize handles(x,y)
   handleMove(x,y)
  set & get selection state
  set & get resize handle state
   
The above is just an example of how one can organize one's thoughts when construction a class. In this case the Bank Element class. This may not be anything like what you want of have imagined and is presented more to illustrate the organization and thought process using scenarios.

Hope this helps.

Wow, thanks. Your resize example is better than what I had in mind. 

I was reworking my code and I was just thinking that an outline would be useful when I saw your second post. Thanks for the example, it really helps.
I'm learning in small steps. I now have two shapes that can be moved around individually. But I have two questions.

1. When the shapes over lap, why does the mouse move the shape behind rather than the one on top? I know this has something to do with the order that things are displayed, but I'm not sure.

2. I want to use this with processing.js, but when I tried it (with the background image) all I got was a grey box, with no shapes inside it and no background image. My image file was in the same folder as html file and the processing.min.js file. Any tips?

Here's the code with the images commented out. 

Now I'm going to figure out how to resize them.  

Thanks again.
Copy code
  1. //PImage clv;
  2. int x, y, h, w;
  3. boolean captured;
  4. ShapeMove[] shapeMove = new ShapeMove[2];

  5. void setup()
  6. {
  7.   size(800, 500);
  8.   //clv = loadImage("clv.png");
  9.   int i;
  10.   i = 0;
  11.   shapeMove[0] = new ShapeMove(x, y, 250, 250);
  12.   shapeMove[1] = new ShapeMove(x, y, 250, 250);
  13. }

  14. void draw()
  15. {
  16.   background(255); 
  17. //  fill(255);
  18.   shapeMove[0].update();
  19.   shapeMove[0].display();
  20.   shapeMove[1].update();
  21.   shapeMove[1].display();
  22. }

  23. class ShapeMove
  24. {
  25.   int x, y, h, w, origx, origy, deltax, deltay, posXdiff, posYdiff;
  26.   boolean over;
  27.   boolean locked = false;
  28.   boolean press;
  29.   boolean imCaptured = false;
  30.   int xdragdelta, ydragdelta;

  31.   ShapeMove(int _x, int _y, int _h, int _w)
  32.   {
  33.     x = _x;
  34.     y = _y;
  35.     h = _h;
  36.     w = _w;
  37.   }

  38.   boolean over()
  39.   {
  40.     if (mouseX >= x && mouseX <=x+w &&
  41.       mouseY >= y && mouseY <= y+h)
  42.     {
  43.       over = true;
  44.       return true;
  45.     }
  46.     else 
  47.     {
  48.       over = false;
  49.       return false;
  50.     }
  51.   }

  52.   void update()
  53.   {
  54.     if (over() && mousePressed && !imCaptured && !captured)
  55.     {
  56.       deltax = x - mouseX;
  57.       deltay = y - mouseY;
  58.       origx = x;
  59.       origy = y;
  60.       captured = true;
  61.       imCaptured = true;
  62.     }
  63.     if(!mousePressed && imCaptured)
  64.     {
  65.       captured = false;
  66.       imCaptured = false;
  67.     }
  68.     if (imCaptured)
  69.     {
  70.       xdragdelta = x - (mouseX + posXdiff);
  71.       ydragdelta = y - (mouseY + posYdiff);
  72.       x = mouseX + deltax;
  73.       y = mouseY + deltay;
  74.     }
  75.   } 

  76.   void display()
  77.   {
  78.     if (over()) {
  79.       fill (0);
  80.     }
  81.     else { 
  82.       fill (80);
  83.     }  
  84.     rect(x, y, h, w);
  85.   }
  86. }

Change the order that you do your Shapemove to match the stacking order. Then the move will grab the one on top. 

As written the mouse can be over multiple shapes so each will have the fill changed. To avoid this you would need a global to maintain the isOver state. Otherwise multiple shapes will be fill(0) when the mouse if over more than one.

Try not setting captured and as you move you will collect multiple shapes in the move process, which is analogous to what is happening with fill.
---------------
Editorial comments:
1. In draw use for loops for the Shapemove[i]. This makes adding more shapes only require setup changes.
2. Have the shapes be different size so you can tell them apart. It makes deducing what is happening easier.
Thanks, Jas0501. I changed the order that of ShapeMove in draw and it worked, but when I use a 'for' loop, I can't control the order. This isn't too big a deal since I need the loop to add other shapes. Maybe I'm doing it wrong, though.

I want to add a button so that the screen is blank to start and when the button is pressed a new ShapeMove is displayed. Eventually I want to have multiple buttons for various styles of ShapeMoves. I think it's possible to do this with only two classes (Button and ShapeMove), but I don't know how.

How do I get the button to insert a new ShapeMove?

Also, I feel like this should be simple, but how do I stop all three rects from changing fill color? I know this has to do with a global that maintains the isOverstate, but I'm stumped there. 

You'll notice I didn't use your resize yet. It's quite elegant, but I don't have the experience to know how to make it work. For now 's' and 'b' with a mouseover will work.

Thanks in advance.
Copy code
  1. //PImage clv;
  2. int x, y, h, w;
  3. boolean captured;
  4. boolean selected = false;
  5. ShapeMove[] shapeMove = new ShapeMove[2];
  6. Button button;

  7. void setup()
  8. {
  9.   size(800, 500);
  10.   //clv = loadImage("clv.png");
  11.   int i;
  12.   i = 0;
  13.   shapeMove[0] = new ShapeMove(0, 0, 200, 200);
  14.   shapeMove[1] = new ShapeMove(250, y, 250, 250);
  15.   button = new Button(200, 300);
  16. }

  17. void draw()
  18. {
  19.   background(255);
  20.   button.display();
  21.   for (int i = 0; i < 2; i++) {
  22.     shapeMove[i].update();
  23.     shapeMove[i].display();
  24.   }
  25. }

  26. //////////////////////////////////////////////////////////////////////////
  27. class ShapeMove
  28. {
  29.   int x, y, h, w, origx, origy, deltax, deltay, posXdiff, posYdiff;
  30.   boolean over;
  31.   boolean locked = false;
  32.   boolean press;
  33.   boolean imCaptured = false;
  34.   int xdragdelta, ydragdelta;

  35.   ShapeMove(int _x, int _y, int _h, int _w)
  36.   {
  37.     x = _x;
  38.     y = _y;
  39.     h = _h;
  40.     w = _w;
  41.   }

  42.   boolean over()
  43.   {
  44.     if (mouseX >= x && mouseX <=x+w &&
  45.       mouseY >= y && mouseY <= y+h)
  46.     {
  47.       over = true;
  48.       return true;
  49.     }
  50.     else 
  51.     {
  52.       over = false;
  53.       return false;
  54.     }
  55.   }

  56.   void update()
  57.   {
  58.     if (over() && mousePressed && !imCaptured && !captured)
  59.     {
  60.       deltax = x - mouseX;
  61.       deltay = y - mouseY;
  62.       origx = x;
  63.       origy = y;
  64.       captured = true;
  65.       imCaptured = true;
  66.     }
  67.     if (!mousePressed && imCaptured)
  68.     {
  69.       captured = false;
  70.       imCaptured = false;
  71.     }
  72.     if (imCaptured)
  73.     {
  74.       xdragdelta = x - (mouseX + posXdiff);
  75.       ydragdelta = y - (mouseY + posYdiff);
  76.       x = mouseX + deltax;
  77.       y = mouseY + deltay;
  78.     }
  79.   } 

  80.   void changesize() 
  81.   {
  82.     if (over() && keyPressed)
  83.     {
  84.       if (key == 'b')
  85.       {
  86.         h += 2;
  87.         w += 2;
  88.       }
  89.       if (key == 's')
  90.       {
  91.         h -= 2;
  92.         w -= 2;
  93.       }
  94.     }
  95.   }
  96.   
  97.   void display()
  98.   {
  99.     rect(x, y, h, w);
  100.     changesize(); 
  101.   }
  102. }
  103. /////////////////////////////////////////////////////////////////////////
  104. class Button
  105. {
  106.   int rectX, rectY;      // Position of square button
  107.   int rectSize = 50;     // Diameter of rect
  108.   color rectColor;
  109.   color rectHighlight;
  110.   boolean rectOver = false;
  111.   
  112.   Button(int _rectX, int _rectY)
  113.   {
  114.     smooth();
  115.     rectColor = color(0);
  116.     rectHighlight = color(51);
  117.     rectX = _rectX;
  118.     rectY = _rectY;
  119.   }
  120.   
  121.   void display()
  122.   {
  123.     update(mouseX, mouseY);    
  124.     if(rectOver) {
  125.       fill(rectHighlight);
  126.     } else {
  127.       fill(rectColor);
  128.     }
  129.     stroke(255);
  130.     rect(rectX, rectY, rectSize, rectSize);
  131.   }
  132.   
  133.   void update(int x, int y)
  134.   {
  135.     if ( overRect(rectX, rectY, rectSize, rectSize) ) {
  136.       rectOver = true;
  137.     } else {
  138.       rectOver = false;
  139.     }
  140.   }
  141.   
  142.   void mousePressed()
  143.   {
  144.     if(rectOver) {
  145. //      currentColor = rectColor;
  146.     }
  147.   }
  148.   
  149.   boolean overRect(int x, int y, int width, int height) 
  150.   {
  151.     if (mouseX >= x && mouseX <= x+width && 
  152.         mouseY >= y && mouseY <= y+height) {
  153.       return true;
  154.     } else {
  155.       return false;
  156.     }
  157.   }
  158. }
You can control the order with for via:

 for (int i = shapeMove.length-1; i >=0; i--) {
      shapeMove[i].update();
      shapeMove[i].display();
}
The fill color needs to be set for each rectangle. As the code stands the fill color is remembered from the button display so all rectangles get displayed as the button color.
Use global
 
boolean isOverSomething;

 and class attribute 

boolean overMe = false;

 with class method 

boolean over(){};


and a check in the form

if(isOverSomething) // over something
{
if(overMe) // over me!
{
    if(!over())
    {
overMe = false;
isOverSomething = false;
}
}
    }
}
else // not over anything at the moment
{
if(over()) // over me!
{
overMe = true;
isOverSomething = true;
}

}
   
Thanks again for the help.

 for (int i = shapeMove.length-1; i >=0; i--) {
      shapeMove[i].update();
      shapeMove[i].display();
}

This changes the stack order of the squares, but the mouse still grabs the one on the bottom. What I need for it to work is something like the following, but that gives me a null pointer error.

  for (int i = 0; i < 2; i++) {
    shapeMove[i].display();
  }
  for (int i = shapeMove.length-1; i >=0; i--) 
  {
    shapeMove[i].update();
  }

It works properly if I write it out like this: 
  shapeMove[1].update();
  shapeMove[0].update();
  shapeMove[0].display();
  shapeMove[1].display();
Woops, the shapeMove.update loop should be before the shapeMove.display loop.