樹脂が固まる前に

Web Frontend / Android / Designが好きな人のメモ

Mode Template for Processing 3.x を作った

前にMode Template for Processing 2.xを使ってProcessing 3.0.2で使えるMode作ったけど,なぜか動かなくなってたのでこの際だから3.x用作った
基本は2.xのまま借りてきている
少し直したのと,前はEclipseで作ってたけどIntelliJが好きだから,移行してIntelliJでつくった
ここからメンテナンスするかと言われればたぶんしない

github.com

String.prepend, String.append, String.minusの話

小ネタだけど,String関係で便利なやつ第2弾
解説すると,String.prepend(String)で前に追加,String.append(String)で後に追加
String - IntでInt文字数分削除

下の例だと,文字”STRING”にprepend("pre")で"preSTRING"
そのあとappend("app")で"preSTRINGapp"
最後にs - 1で最後の1文字を削除して"preSTRINGap"

operator fun String.minus(num: Int) = this.substring(0, this.length - num)

fun String.prepend(s: String) = this.javaClass.getDeclaredField("value").let {
    it.isAccessible = true
    it.set(this, s.toCharArray() + this.toCharArray())
    this
}

fun String.append(s: String) = this.javaClass.getDeclaredField("value").let {
    it.isAccessible = true
    it.set(this, this.toCharArray() + s.toCharArray())
    this
}

fun main(args: Array<String>) {
    val s = "STRING"
    s.prepend("pre").append("app")
    println(s - 1)  // ->  preSTRINGap
}

Stringに掛け算の演算子オーバーロードしたら捗った

最近Kotlinのoperatorとかinfix触っててよかった話をひとつ.

Stringで+を使うと結合になるわけだけど,なぜか*がない
なのでString.timesを作った
String * Int, String *= Intって感じ
これでいちいちfor回したりがなくなるので結構便利
デフォルトに組み込んでほしい^~

fun main(args: Array<String>) {
    operator fun String.times(num: Int): String {
        var s = ""
        for (i in 0..num) s += this
        return s
    }
    println("hell, " * 2 + "hell)//hell, hell, hell
}

ProcessingのTemplate Modeでビルドするときにスケッチ名とコードを取得する

続き: pvcresin.hatenablog.com

JavaModeを継承しているTemplateModeでhandleLaunchメソッドをOverrideする

メインのコードはhandleLaunchメソッドの中で,こんな感じ

String sketchName = sketch.getName();
System.out.println("handleLaunch: " + sketchName);
        
Editor editor = base.getActiveEditor();
String s = "";
for (int i = 0; i < editor.getLineCount(); i++){
    s += editor.getLineText(i);
}
System.out.println(s);

TemplateMode全体

package com.mydomain.mymode;

import java.io.File;
import processing.app.*;
import processing.app.ui.*;
import processing.mode.java.*;
import processing.mode.java.runner.Runner;

public class TemplateMode extends JavaMode {
    
    public TemplateMode(Base base, File folder) {
        super(base, folder);
    }

    /**
     * Return the pretty/printable/menu name for this mode. This is separate
     * from the single word name of the folder that contains this mode. It could
     * even have spaces, though that might result in sheer madness or total
     * mayhem.
     */
    @Override
    public String getTitle() {
        return "Template";
    }
    
    // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
   
    // Create a new editor associated with this mode.
//    @Override
//    public Editor createEditor(Base base, String path, EditorState state) {
//         return null;
//    }

    // Returns the default extension for this editor setup.
//    @Override
//    public String getDefaultExtension() {
//        return null;
//    }

    // Returns a String[] array of proper extensions.    
//    @Override
//    public String[] getExtensions() {
//        return null;
//    }

    // Get array of file/directory names that needn't be copied during "Save As".    
//    @Override
//    public String[] getIgnorable() {
//        return null;
//    }
    
    /**
     * Retrieve the ClassLoader for JavaMode. This is used by Compiler to load
     * ECJ classes. Thanks to Ben Fry.
     * @return the class loader from java mode
     */
//    @Override
//    public ClassLoader getClassLoader() {
//        for (Mode m : base.getModeList()) {
//            if (m.getClass() == JavaMode.class) {
//                JavaMode jMode = (JavaMode) m;
//                return jMode.getClassLoader();
//            }
//        }
//        return null;  // badness
//    }
    
    /** Handles the standard Java "Run" or "Present" */
    @Override
    public Runner handleLaunch(Sketch sketch, RunnerListener listener,
            final boolean present) throws SketchException {

        String sketchName = sketch.getName();
        System.out.println("handleLaunch: " + sketchName);
        
        Editor editor = base.getActiveEditor();
        String s = "";
        for (int i = 0; i < editor.getLineCount(); i++){
            s += editor.getLineText(i);
        }
        System.out.println(s);
        
      JavaBuild build = new JavaBuild(sketch);
      String appletClassName = build.build(true);
      
      if (appletClassName != null) {
        final Runner runtime = new Runner(build, listener);
        
        new Thread(new Runnable() {
          public void run() {   // these block until finished
            if (present) runtime.present(null);
            else runtime.launch(null);
          }
        }).start();
        
        return runtime;
      }
      return null;
    }    
  
}

KotlinのAnyを引数に持つ同名関数の優先順位について

fun(Any) < fun(String)
Anyが引数になってる関数よりStringとか限定された方が優先されるっぽい?

fun main(args: Array<String>) {
    p("hell")   // -> str
    p(10)       // -> int
    p(10.0)     // -> any
}

fun p(any: Any) = println("$any : any")

fun p(i: Int) = println("$i : int")

fun p(s: String) = println("$s : str")

Processing 3.0.2で動く自作ライブラリ(.jar)を作ろう

初めに

  • 自作クラスとか使いたい人向け
  • IntelliJ IDEA Community(free) 使用
  • Java ->.jar ファイル(ライブラリ本体)を吐き出す

プロジェクト作成

  • Processing が3.0.2なので,JDKは1.8を使用

  • IDEA: File>New>ProjectでtestLibを作成

  • その中のsrcにtestPackageを作成
  • またその中にJavaClass.javaを作成

今回はPApppletを扱えるライブラリにしたいので, IDEA: File>Project Structure>Librariesで+を押してcore.jar(Processing3.0.2>core>library)を入れる

Project表示ではこんな感じ

f:id:pvcresin:20160317220251p:plain

JavaClass.javaを書いてみる

最初にProcessing側からPAppletをもらってきて,bgというメソッドが呼ばれたらPAppletのバックグラウンドの色を変えるというだけのクラス.

package testPackage;

import processing.core.*;

public class JavaClass {
    PApplet pa;

    public JavaClass(PApplet pa) {
        this.pa = pa;
    }
    public void bg(int color){
        pa.background(color);
    }
    public static void main(String[] args) {

    }
}

.jar 作り

  1. IDEA: File>Project Structure>Artifacts
  2. +押す>JAR >From modules with dependencies
  3. Main ClassにJavaClassを選択する main()がないとかクラスに不備があると表示されないことがある
  4. JavaClass.javaのエディット画面に戻り,IDEA: Build>Build Artifactsからビルド
  5. testLib>out>artifacts>testLib_jarファイルのなかにtestLib.jarができているはず

f:id:pvcresin:20160317222510p:plain

Processingで使用

できた.jarを自分のスケッチにドラッグ&ドロップして下のコードをProcessingで書くだけ

import testPackage.JavaClass;

JavaClass j = new JavaClass(this);

void setup() {
  size(300, 300);
  background(255);
}
void draw() {
}
void mousePressed() {
  j.bg(color(255, 0, 0));
}

ライブラリ作りの参考:

Processingのライブラリを作る - gutugutu3030

IntelliJ IDEAでの .jarの作り方の参考:

qiita.com

Create original Mode for Processing 3.0.2

Original Mode extends Java Mode (Default Mode)
similar when create Tool

pvcresin.hatenablog.com

refer: ProcessingのModeを作る - gutugutu3030

Environment

  • Windows 10 (64 bit)
  • Eclipse (Mars)
  • Processing 3.0.2
  • JDK 1.8 (Java SE 8)
  • Mode Template for Processing 2.0 (for 2.0...)

github.com

Step

Download the zip

TemplateMode-master.zip (=archive file) from github

Create new project

Eclipse: new Java Project ("testMode": my case) -> import archive file (zip)

Copy jar files

Copy core.jar & pde.jar & many jar files(JavaMode.jar, jdi.jar, ...) -> Paste in : {your project name}>src>TemplateMode-master>lib - core.jar (Processing-3.0.2>core>library) - pde.jar (Processing-3.0.2>lib) - *.jar (Processing-3.0.2>modes>java>mode) = (18 jar files)

Add to Build Path

  1. select all jar files(TemplateMode-master>lib)
  2. right click
  3. Build Path>Add to Build Path (seemed to move)

f:id:pvcresin:20160317202945p:plain

Edit build.xml (src>TemplateMode-master)

path is my case

Edit at least

  • JDK version
  • core.jar path
  • pde.jar path
  • processing.exe path (Processing-3.0.2)
  • (if you want) Mode name, Version ...
<!-- java version -->
<property name="java.target.version" value="1.8" />

<!-- location of processing jars (core.jar, pde.jar, ..) -->
<property name="processing.classes.core" location="${user.home}\\Downloads\\PROGRAM\\Processing\\processing-3.0.2\\core\\library" />
<property name="processing.classes.pde" location="${user.home}\\Downloads\\PROGRAM\\Processing\\processing-3.0.2\\lib" />

<!-- folder to install modes in (probably a folder called "modes" inside your sketchbook folder) -->
<property name="processing.modes" location="${user.home}\\Documents\\Processing3\\modes"/>

<!-- path to your processing executable. -->
<property name="processing.executable" location="${user.home}\\Downloads\\PROGRAM\\Processing\\processing-3.0.2\\processing.exe"/>

Change import statements

Edit TemplateMode.java (src>TemplateMode-master>src>com>mydomain>mymode)

//package com.mydomain.mymode;

import java.io.File;
import processing.app.Base;
//import processing.app.Editor;  // 2.x
import processing.app.ui.Editor;  // 3.0.2
//import processing.app.EditorState;  // 2.x
import processing.app.ui.EditorState;  // 3.0.2
import processing.app.Mode;
import processing.mode.java.JavaMode;

public class TemplateMode extends JavaMode { 
    public TemplateMode(Base base, File folder) {
        super(base, folder);
    }

    /**
     * Return the pretty/printable/menu name for this mode. This is separate
     * from the single word name of the folder that contains this mode. It could
     * even have spaces, though that might result in sheer madness or total
     * mayhem.
     */
    @Override
    public String getTitle() {
        return "Mode Template";
    }    
    // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
   
    // Create a new editor associated with this mode.
//    @Override
//    public Editor createEditor(Base base, String path, EditorState state) {
//         return null;
//    }    

    // Returns the default extension for this editor setup.
//    @Override
//    public String getDefaultExtension() {
//        return null;
//    }

    // Returns a String[] array of proper extensions.    
//    @Override
//    public String[] getExtensions() {
//        return null;
//    }

    // Get array of file/directory names that needn't be copied during "Save As".    
//    @Override
//    public String[] getIgnorable() {
//        return null;
//    }
    
    /**
     * Retrieve the ClassLoader for JavaMode. This is used by Compiler to load
     * ECJ classes. Thanks to Ben Fry.
     * @return the class loader from java mode
     */
//    @Override
//    public ClassLoader getClassLoader() {
//        for (Mode m : base.getModeList()) {
//            if (m.getClass() == JavaMode.class) {
//                JavaMode jMode = (JavaMode) m;
//                return jMode.getClassLoader();
//            }
//        }
//        return null;  // badness
//    }

}

Ant build (Eclipse)

  1. show Ant tab
    • Eclipse: Window>show View>other -> click Ant -> Ant tab appear (int the lower window)
  2. build.xml (src>resources) -> drag & drop on Ant tab -> close Processing (while building)
  3. push Run button in Ant tab -> watch console (build finished in about 2 sec)
  4. if (BUILD SUCCESSFUL) -> Template Mode is in your Processing (PDE), else check build.xml and .jar file f:id:pvcresin:20160317202214p:plain