# How does EventHandler work inside a Graphic

I've created an application with the User Interface being a Graphic with lines, polygons etc. The functionality I need is:

1. to be able to place the objects anywhere in {x,y} coords of the Graphic.
2. to change the size of the object depending on how its used.
3. to click each object and trigger color changes and execution of various functions.

The application works fine when there are only a few (say 20 objects) but noticeably slows as the number of objects increase. Any ideas why, and can it be made more responsive?

Note in the code below that the Print[] statement at line 91 inside the DynamicModule is currently commented out, and performance is still poor, when its made active performance gets a lot worse .

function1[p_, scale_, state_] :=
Module[
{body, ghost},
{ax, by} = scale {1, 0.7};
body = Polygon[
{
{-ax, -by} + p, {-ax, by} + p, {ax, -by} +
p, {ax, by} + p
}];
ghost = Rectangle[{-ax, -by} + p, {ax, by} + p];
{
FaceForm[state],
EdgeForm[Black],
body,
EdgeForm[None],
Opacity[0.],
ghost,
FaceForm[None]
}
]

function2[p_, scale_, state_] :=
Module[
{body, plug, ghost},
{ax, by} = scale {1, 0.7};
body = Polygon[
{
{-ax, -by} + p, {-ax, by} + p, {ax, -by} +
p, {ax, by} + p
}];
plug = Polygon[
{
{0, -by/2} + p, {-0.4, 0} + p, {0., by/2} +
p, {0.4, 0} + p, {0., -by/2} + p
}];
ghost = Rectangle[{-ax, -by} + p, {ax, by} + p];
{
FaceForm[state],
EdgeForm[Black],
body,
plug,
EdgeForm[None],
Opacity[0.],
ghost,
FaceForm[None]
}
]

function3[p_, scale_] := Module[
{actuator, stem},
{ax, by} = scale {0.75, 0.75};
actuator =
{
FaceForm[None], EdgeForm[Black],
Polygon[
{
{-ax, 1.5 by} + p, {ax, 1.5 by} + p, {ax, 3. by} + p, {-ax, 3. by} + p
}],
Line[{{-ax, 2.25 by} + p, {ax, 2.25 by} + p}]
};
stem = Line[{p, {0, 2.25 by} + p}];
{actuator, stem}
]

function13[p_, scale_, rotation_, state_: White] :=
Rotate[
Flatten@{function3[p, scale], function1[p, scale, state]},
rotation Degree, p
]

function23[p_, scale_, rotation_, state_: White] :=
Rotate[
Flatten@{function3[p, scale], function2[p, scale, state]},
rotation Degree, p
]

myCol = Black;

list = Table[Null, {i, 1, 100}];

objectDynamic[valveType_, p_, scale_, orientation_ , ID_Integer] :=
DynamicModule[
{myCol = Black},
EventHandler[
Dynamic@valveType[p, scale, orientation, myCol],
{
"MouseDown" :>
(
myCol =
myCol /. {Black -> Green, Green -> Red, Red -> Black};
list[[ID]] = myCol; (*Print[p]*)
)
},
Method -> "Queued", PassEventsDown -> False, PassEventsUp -> False
]
]

tableOfObjects =
Table[
{
objectDynamic[function13, {5 i , 5 j}, 1., 0. , 1  ],
objectDynamic[function23, {5 i , 5 j + 10}, 1., 0. , 1  ]}, {i, 0, 9}, {j, 0, 4}];

CreateDocument[
Dynamic[
Graphics[
Flatten@{
Line[{{0, -5}, {0,0}, {4,0}, {4,4}, {8,4}, {12,4}, {12,0}}],
tableOfObjects
},
Frame -> True, ImageSize -> {700, 500}],
SynchronousUpdating -> False
],
WindowSize -> {1600, 1000}
];

• Please post some code and descriptions of the problems each block of code is giving. A minimal reproducible example would be even better. Jul 2 '16 at 23:01
• Did you try setting PassEventsDown and PassEventsUp to False? Jul 2 '16 at 23:01
• I don't see a problem with 100 objects: Graphics[ DynamicModule[{col = 1}, EventHandler[{Dynamic@GrayLevel[col], Disk[#, 1/2]}, {"MouseClicked" :> (col = 1 - col)}] ] & /@ Tuples[Range[10], 2], Background -> Gray ]. It is important to see the details of your code. Jul 3 '16 at 7:41
• Thanks guys, I've been trying to create an example that behaves like the application but like your snippet they all work fine. I'll try stripping out the application specific code and will post tomorrow. Jul 3 '16 at 22:02
• Try Dynamic[valveType[p, scale, orientation, myCol], TrackedSymbols :> {myCol}]. Jul 5 '16 at 19:06

From my comment:

Try Dynamic[valveType[p, scale, orientation, myCol], TrackedSymbols :> {myCol}]

This worked for me and seemed to work for the OP, so I'll post it as an answer. One might normally expect an explanation, but the OP's code is rather too complicated (or at least long, at first glance) to really track down the problem quickly. I will explain how I figured it out, or guessed if you prefer.

First, I noticed that the front end, and indeed my whole computer was a little sluggish after executing the code. I checked and the kernel was running at about 70%, so I concluded that the code was continually updating due to dynamic dependencies. As I said in a earlier comment before the code was posted (now deleted due to a horrible typo) was something like this:

What happens in dynamic update comes from the dependencies in the code.

My experience has generally taught me to program complicated Dynamic code with TrackedSymbols explicitly set. It was fairly easy to see that a mouse-down only changed the color as far as updating the display goes. It seemed easier to try this, instead tracking down the cause, which would probably prove irrelevant to the solution in the end anyway.

In a more complicated application, one might need to sprinkle a few Dynamic[Refresh[...]] around judiciously to manage performance. For a start, read the two tutorials linked in the docs to Dynamic; also there is What is the point of Refresh if Dynamic has an UpdateInterval option? and its linked questions. And there is a whole bunch of questions under the tag , which goes to show how difficult many people find it.

I got a reply from Wolfram Technical Support. It turns out the slow response was caused by not localizing the variables ax and by inside the Module statements. The MouseDown was triggering their update, which in turn caused the whole graphic to be recreated. Thanks to John Fultz. I am told the only way to track down unexpected dependencies is by selectively planting print statements.