Kotlin
processing
macos

Processing3のmacOS版でウィンドウやフルスクリーンを操作する

More than 1 year has passed since last update.

Processing3になってからウィンドウ(フレーム)操作が変更され、frame.setLocation()のようなメソッドが現在のバージョン(3.3.6)のmacOS版では基本的に動作しなくなった。(WindowsやLinuxは未検証なので、誰か教えて)

さて、どうしてもウィンドウを操作したい場合は次のようにSurfaceから本物のフレームを取ってくる必要がある。


Processing

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で開発している人は次のような感じ。


ProcessingKotlin.kt

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()の実行が遅れたりするかもしれない。


InitializeLocation.kt

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のframenativeFrameに置き換わっただけで、アプローチは変わらない。surfaceのリサイズを有効にすること。


ChangeToFullScreen.kt

// クリックすると接続されているディスプレイ順にフルスクリーン化される

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)



フルスクリーンをウィンドウに変更する

前項と反対の処理をするだけ。


ChangeToWindow.kt

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)