Processing3になってからウィンドウ(フレーム)操作が変更され、frame.setLocation()
のようなメソッドが現在のバージョン(3.3.6)のmacOS版では基本的に動作しなくなった。(WindowsやLinuxは未検証なので、誰か教えて)
さて、どうしてもウィンドウを操作したい場合は次のようにSurfaceから本物のフレームを取ってくる必要がある。
import processing.awt.PSurfaceAWT;
import java.awt.Frame;
import java.awt.Point;
void mousePressed() {
PSurfaceAWT.SmoothCanvas canvas =
(PSurfaceAWT.SmoothCanvas)surface.getNative();
Frame nativeFrame = canvas.getFrame();
Point pos = nativeFrame.getLocation();
nativeFrame.setLocation(pos.getX()+100, pos.getY())
}
Kotlinで開発している人は次のような感じ。
import processing.awt.PSurfaceAWT
import processing.core.*
import java.awt.Frame
class MainApplication : PApplet() {
// プロパティにしておくとProcessing2の頃みたいに操作できる
val nativeFrame: Frame
get() {
val canvas = surface.native as PSurfaceAWT.SmoothCanvas
return canvas.frame
}
override fun mousePressed() {
val pos = nativeFrame.location
nativeFrame.setLocation(pos.x + 100, pos.y)
}
fun run(args: Array<String>) : Unit
= PApplet.main(this.javaClass.name)
}
応用
以下は発展的?な付録として添えておく。ただし全てKotlinで記述しているので、純粋なProcessing使いの方は読み替えてください。
Notifyの役割
詳しくは分からないが、AWTの仮想的に作られたフレームをOSが提供するウィンドウやイベントに割り当てる機能のようだ。setup()
内でsetLocation()
などが上手く動かない場合はNotifyを一度解除してから実行すると良い。
ただし、一度ウィンドウが消えるので、起動時に多少チラついたりdraw()
の実行が遅れたりするかもしれない。
override fun settings() {
size(800, 600) // ウィンドウサイズ
}
override fun setup() {
nativeFrame.removeNotify()
nativeFrame.setSize(width, height) // Surfaceとズレる場合の対策
nativeFrame.setLocation(100, 100) // ウィンドウの初期座標
nativeFrame.addNotify()
}
不必要にremoveしたりaddしたりしていると、Surfaceのバッファ関連でAWTに怒られる。具体的な条件はよく分からなかった。
ウィンドウをフルスクリーンに変更する
基本的にProcessing2のframe
がnativeFrame
に置き換わっただけで、アプローチは変わらない。surfaceのリサイズを有効にすること。
// クリックすると接続されているディスプレイ順にフルスクリーン化される
override fun mousePressed() {
changeToFullScreen(i)
i++
}
// 使い方はProcessing標準の fullScreen() と同じ
fun changeToFullScreen(display: Int) {
// Get display information
val gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment()
val gDevice = if (display == 0 || display > gEnv.screenDevices.size)
gEnv.defaultScreenDevice
else
gEnv.screenDevices[display - 1]
val bound = gDevice.defaultConfiguration.bounds
// Change fullscreen
val reqFlush = !nativeFrame.isUndecorated
if (reqFlush) {
nativeFrame.removeNotify()
nativeFrame.isAlwaysOnTop = true
nativeFrame.isUndecorated = true
}
nativeFrame.setLocation(bound.x, bound.y)
nativeFrame.setSize(bound.width, bound.height)
surface.setSize(bound.width, bound.height)
if (reqFlush) {
nativeFrame.addNotify()
}
}
fun changeToFullScreen() : Unit
= changeToFullScreen(0)
フルスクリーンをウィンドウに変更する
前項と反対の処理をするだけ。
fun changeToWindow(width: Int, height: Int, x: Int?, y: Int?) {
val reqReset = nativeFrame.isUndecorated
if (reqReset) {
nativeFrame.removeNotify()
nativeFrame.isUndecorated = false
nativeFrame.isAlwaysOnTop = false
}
if (x != null && y != null) {
nativeFrame.setLocation(x, y)
}
nativeFrame.setSize(width, height)
surface.setSize(width, height)
if (reqReset) {
nativeFrame.addNotify()
}
}
fun changeToWindow(width: Int, height: Int) : Unit
= changeToWindow(width, height, null, null)
その他…
思いつき次第、追記する…かも。
参考文献
・Processing 3.0で実行中にwindowのsizeの変更やタイトルバーを非表示にする方法 (Qiita: kenji_5884)
・java.awt.Frame#addNotify (Oracle Java Platform SE8)
・Javaでマルチスクリーンな場所の指定 (Hatena: hidesuke)