Implement Processing's "thread" function.
This implements feature request
MODIFY
runtime/src/jycessing/PAppletJythonDriver.java
runtime/src/jycessing/PAppletJythonDriver.java
@@ -29,7 +29,9 @@ import java.lang.reflect.Modifier;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -167,6 +169,12 @@ public class PAppletJythonDriver extends PApplet {
}
}
+ /**
+ * We maintain a map from function name to function in order to implement {@link
+ * PApplet#method(String)}.
+ */
+ private final Map<String, PyFunction> allFunctionsByName = new HashMap<>();
+
// These are all of the methods that PApplet might call in your sketch. If
// you have implemented a method, we save it and call it.
private PyObject setupMeth, settingsMeth, drawMeth, pauseMeth, resumeMeth;
@@ -539,6 +547,36 @@ public class PAppletJythonDriver extends PApplet {
finishedLatch.countDown();
}
+ /** Call the user-defined Python function with the given name. */
+ @Override
+ public void method(final String name) {
+ final PyFunction f = allFunctionsByName.get(name);
+ if (f != null) {
+ f.__call__();
+ } else {
+ super.method(name);
+ }
+ }
+
+ /**
+ * Python Mode's {@link PApplet#thread(String)} can take a {@link String} (like Java mode) or a
+ * function object.
+ *
+ * @param obj either a {@link PyString} or a {@link PyFunction} to run in a thread.
+ */
+ public void thread(final Object obj) {
+ if (obj instanceof String) {
+ super.thread((String) obj);
+ } else if (obj instanceof PyFunction) {
+ new Thread() {
+ @Override
+ public void run() {
+ ((PyFunction) obj).__call__();
+ }
+ }.start();
+ }
+ }
+
public void findSketchMethods() throws PythonSketchError {
if (mode == Mode.ACTIVE) {
// Executing the sketch will bind method names ("draw") to PyCode
@@ -547,6 +585,15 @@ public class PAppletJythonDriver extends PApplet {
processSketch(PREPROCESS_SCRIPT);
}
+ for (final Object local : ((PyStringMap) interp.getLocals()).items()) {
+ final PyTuple t = (PyTuple) local;
+ final String k = t.get(0).toString();
+ final Object v = t.get(1);
+ if (v instanceof PyFunction) {
+ allFunctionsByName.put(k, (PyFunction) v);
+ }
+ }
+
// Find and cache any PApplet callbacks defined in the Python sketch
drawMeth = interp.get("draw");
setupMeth = interp.get("setup");

MODIFY
runtime/src/jycessing/core.py
runtime/src/jycessing/core.py
@@ -427,6 +427,7 @@ __builtin__.textWidth = __papplet__.textWidth
__builtin__.texture = __papplet__.texture
__builtin__.textureMode = __papplet__.textureMode
__builtin__.textureWrap = __papplet__.textureWrap
+__builtin__.thread = __papplet__.thread
__builtin__.tint = __papplet__.tint
__builtin__.translate = __papplet__.translate
__builtin__.triangle = __papplet__.triangle

ADD
testing/resources/test_thread.py
+import time
+
+def setup():
+ size(10, 10)
+
+n = 0
+
+def func1():
+ global n
+ n += 1
+
+def func2():
+ global n
+ n += 4
+
+def draw():
+ noLoop()
+ thread("func1")
+ while n < 1:
+ time.sleep(0.02)
+ thread(func2)
+ while n < 5:
+ time.sleep(0.02)
+ print('OK')
+ exit()

MODIFY
testing/src/test/jycessing/JycessingTests.java
testing/src/test/jycessing/JycessingTests.java
@@ -329,4 +329,10 @@ public class JycessingTests {
public void keyPressed_redefined() throws Exception {
expectOK("keyPressed_redefined");
}
+
+ //https://github.com/jdf/processing.py/issues/281
+ @Test
+ public void thread() throws Exception {
+ expectOK("thread");
+ }
}

Implement Processing's "thread" function.

This implements feature request #281.