2
$\begingroup$

I am currently attempting to write code that allows users to add shapes to a window and arrange them to create an image. To do this, I make each shape into a locator. This method seems to work well. However, whenever I add a new shape in to the window using the buttons, all of the shapes move back to the initial point they were set to. Clearly, this isn't ideal for creating a good user experience. I have tried making the locator initial point dynamic; however, all of the shapes are still reset to their initial point and also stick together. Does anyone have suggestions as to how I could alter this code so that the shapes retain the position they were moved to even when a new shape is added? Any help is much appreciated. Thanks!

designWindowTest[] := CreateWindow[DialogNotebook[{
DynamicModule[{pt = {0, 0}, listOfShapes = {}, ptList = {}},
 Row[{
   Column[{
     Button["Red Disk", AppendTo[ptList, pt]; 
      AppendTo[listOfShapes, 
       Locator[ptList[[Length[ptList]]], 
        Graphics[{Red, Disk[]}, ImageSize -> Small]]]],

     Button["Blue Disk", AppendTo[ptList, pt]; 
      AppendTo[listOfShapes, 
       Locator[ptList[[Length[ptList]]], 
        Graphics[{Blue, Disk[]}, ImageSize -> Small]]]],

     Button["Green Disk", AppendTo[ptList, pt]; 
      AppendTo[listOfShapes, 
       Locator[ptList[[Length[ptList]]], 
        Graphics[{Green, Disk[]}, ImageSize -> Small]]]],

     Button["Exit", DialogReturn[]],

     Graphics[{Dynamic@Text[ptList]}]
     }],(*end of column*)
   Dynamic@
    Graphics[{listOfShapes}, PlotRange -> 1, 
     ImageSize -> {1100, 1000}]
   }](*end of row*)

 ]}], WindowSize -> Full, Background -> White]
$\endgroup$
  • $\begingroup$ Did I answer your question? $\endgroup$ – Pinti Apr 19 '17 at 7:21
  • $\begingroup$ Yes- thank you very much! $\endgroup$ – Emily Apr 19 '17 at 16:34
  • $\begingroup$ I suggest that you upvote the answers you like and accept the one that you like the most or the one that works for you. Please, take the quick tour to see how this site works. $\endgroup$ – Pinti Apr 20 '17 at 7:17
0
$\begingroup$

You need to save the value Length[ptList] in a different context each time you create a new shape, otherwise it always points to the last element in the list. I have done this with With.

By using Dynamic@ptList[[np]] the values in ptList are updated if the locator is moved. This prevents the reset of the positions when a new shape is added.

designWindowTest[] := 
 CreateWindow[
  DialogNotebook[{DynamicModule[{pt = {0, 0}, listOfShapes = {}, 
      ptList = {}}, 
     Row[{Column[{Button["Red Disk", AppendTo[ptList, pt];

          AppendTo[listOfShapes, 
           Locator[With[{np = Length[ptList]}, Dynamic[ptList[[np]]]],
             Graphics[{Red, Disk[]}, ImageSize -> Small]]]], 
         Button["Blue Disk", AppendTo[ptList, pt];

          AppendTo[listOfShapes, 
           Locator[With[{np = Length[ptList]}, Dynamic[ptList[[np]]]],
             Graphics[{Blue, Disk[]}, ImageSize -> Small]]]], 
         Button["Blue Disk", AppendTo[ptList, pt];

          AppendTo[listOfShapes, 
           Locator[With[{np = Length[ptList]}, Dynamic[ptList[[np]]]],
             Graphics[{Blue, Disk[]}, ImageSize -> Small]]]], 
         Button["Exit", DialogReturn[]], 
         Graphics[{Dynamic@Text[ptList]}]}],(*end of column*)
       Dynamic@Graphics[{listOfShapes}, PlotRange -> 1, 
         ImageSize -> {400, 400}]}](*end of row*)]}], 
  WindowSize -> 600, Background -> White] 
$\endgroup$
1
$\begingroup$

I can't exactly say what is the problem with your example, but I can show you my approach to solve the problem. It may not be the most robust and elegant code, although I think it can be easily extended with additional functionality.

Helper functions, to increase the readability of the main function/expression.

ClearAll[shape];
Attributes[shape] = {HoldFirst};
shape[pt_, color_] := Locator[Dynamic[pt], Graphics[{color, Disk[]}, ImageSize -> 20]]

ClearAll[removeShape];
Attributes[removeShape] = {HoldAll};
removeShape[crds_, colors_] := Button["remove shape",
  If[Length[crds] > 1,
   crds = Most[crds]; colors = Most[colors];
   ]
  ]

ClearAll[addShape];
Attributes[addShape] = {HoldAll};
addShape[name_, col_, crds_, colors_] := Button[
  name <> " disk",
  AppendTo[crds, {0, 0}]; AppendTo[colors, col];
  ]

The main DynamicModule.

DynamicModule[{
  crds = {{0, 0}},
  colors = {Red}
  },
 Column[{
   Row[{
     addShape["red", Red, crds, colors],
     addShape["blue", Blue, crds, colors],
     addShape["random", RandomColor[], crds, colors],
     removeShape[crds, colors]
     },
    Spacer[3]
    ]
   ,
   Graphics[
    Dynamic[
     Table[
      With[{i = i},
       shape[crds[[i]], colors[[i]]]
       ],
      {i, 1, Length[crds]}
      ]
     ],
    ImageSize -> 300
    ]
   }, Frame -> All],
 SaveDefinitions -> True
 ]

canvas

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.