






















在 Processing 的 P2D(以及 P3D)渲染器模式下,由于底层使用 JOGL(Java OpenGL)库实现,约束鼠标在窗口内的方法与标准的 JAVA2D 渲染器有所不同。本报告详细阐述两种主要的鼠标约束方法及其适用场景。
P2D 渲染器底层使用 JOGL 的 GLWindow 对象来管理窗口和输入。通过 surface.getNative() 方法可以获取这个原生窗口对象,然后调用 confinePointer(true) 将鼠标物理限制在窗口边界内。
import com.jogamp.newt.opengl.GLWindow;
void setup() {
size(640, 480, P2D);
GLWindow window = (GLWindow) surface.getNative();
window.confinePointer(true);
}
| 方法 | 说明 |
|---|---|
confinePointer(boolean) |
启用/禁用鼠标指针约束。true=限制在窗口内 |
setPointerVisible(boolean) |
显示/隐藏鼠标指针 |
warpPointer(int x, int y) |
将鼠标指针移动到指定窗口坐标 |
mouseX 和 mouseY 无需额外处理,天然就在窗口范围内import com.jogamp.newt.opengl.GLWindow;
float rotX = 0, rotY = 0;
float sensitivity = 0.01;
void setup() {
size(640, 480, P2D);
GLWindow window = (GLWindow) surface.getNative();
window.confinePointer(true);
window.setPointerVisible(false);
}
void draw() {
background(40);
// 计算鼠标移动增量(从中心计算)
float dx = mouseX - width / 2;
float dy = mouseY - height / 2;
rotY += dx * sensitivity;
rotX += dy * sensitivity;
// 将鼠标重置到中心
GLWindow window = (GLWindow) surface.getNative();
window.warpPointer(width / 2, height / 2);
// 使用旋转值绘制场景
pushMatrix();
translate(width / 2, height / 2);
rotateX(rotX);
rotateY(rotY);
box(100);
popMatrix();
}
使用 Processing 内置的 constrain() 函数,确保 mouseX 和 mouseY 的值被限制在指定范围内。这种方法不会物理限制鼠标,但可以确保程序逻辑中使用的坐标值始终在有效范围内。
void draw() {
float cx = constrain(mouseX, 0, width);
float cy = constrain(mouseY, 0, height);
ellipse(cx, cy, 20, 20);
}
mouseX/mouseY 会是负值或超出范围float brushX, brushY;
int brushSize = 20;
void setup() {
size(640, 480, P2D);
}
void draw() {
background(255);
// 约束画笔位置
brushX = constrain(mouseX, brushSize/2, width - brushSize/2);
brushY = constrain(mouseY, brushSize/2, height - brushSize/2);
// 绘制画笔预览
noFill();
stroke(200);
ellipse(brushX, brushY, brushSize, brushSize);
// 绘制信息
fill(0);
text("brushX: " + brushX, 10, 20);
text("brushY: " + brushY, 10, 35);
}
对于使用 JAVA2D 渲染器的 sketch,需要使用 java.awt.Robot 类:
import java.awt.Robot;
import java.awt.Point;
Robot robot;
void setup() {
size(640, 480, JAVA2D);
robot = new Robot();
}
void mouseMoved() {
// 获取窗口屏幕坐标
Point p = ((PSurfaceAWT)surface).getFrame().getLocationOnScreen();
int centerX = p.x + width / 2;
int centerY = p.y + height / 2;
// 将鼠标重置到窗口中心
robot.mouseMove(centerX, centerY);
}
注意:JAVA2D 模式下
surface.getNative()返回的是 AWT Frame,不是 GLWindow。
| 特性 | P2D / P3D | JAVA2D |
|---|---|---|
| 底层技术 | JOGL (NEWT) | AWT |
| 获取原生窗口 | surface.getNative() → GLWindow |
((PSurfaceAWT)surface).getFrame() |
| 指针约束 | GLWindow.confinePointer() |
java.awt.Robot |
| 指针隐藏 | GLWindow.setPointerVisible() |
java.awt.Robot + 自定义光标 |
| 窗口坐标 | 原生支持 | 需要计算偏移 |
当鼠标移出窗口时,P2D 模式下 mouseX/mouseY 会变成负值。解决方案:
void draw() {
float safeX = constrain(mouseX, 0, width);
float safeY = constrain(mouseY, 0, height);
// 使用 safeX, safeY 代替 mouseX, mouseY
}
boolean isMouseInside() {
return mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height;
}
确保:
setup() 中调用(不是在 draw() 中)import com.jogamp.newt.opengl.GLWindow;这是正常的,因为 warpPointer 和 mouseMoved 事件之间存在竞态条件。可以使用标志位跳过第一次重置:
boolean initialized = false;
void mouseMoved() {
if (initialized) {
// 重置到中心
GLWindow window = (GLWindow) surface.getNative();
window.warpPointer(width / 2, height / 2);
}
initialized = true;
}
游戏类应用:使用 GLWindow.confinePointer(true) 配合 warpPointer() 实现 FPS 风格控制
交互式绘画/设计工具:使用 constrain() 函数确保绘制内容始终在画布内
需要鼠标按下拖拽:先 confinePointer(true) 再隐藏指针,提供沉浸式体验
跨渲染器兼容:封装成工具类,根据渲染器类型选择正确的方法
void constrainMouse(boolean enable) {
if (enable) {
if (useGL) {
GLWindow window = (GLWindow) surface.getNative();
window.confinePointer(true);
} else {
// JAVA2D 降级处理
}
}
}
/**
* Processing P2D 模式 - 鼠标约束示例
*
* 演示两种约束鼠标的方法:
* 1. 物理约束:真正限制鼠标在窗口内移动
* 2. 数值约束:仅限制 mouseX/mouseY 的返回值
*/
// 方法一:使用 GLWindow 物理约束鼠标
import com.jogamp.newt.opengl.GLWindow;
boolean usePhysicalConstraint = true; // 切换两种模式
void setup() {
size(640, 480, P2D);
// 方法一:使用 GLWindow 限制鼠标在窗口内
if (usePhysicalConstraint) {
GLWindow window = (GLWindow) surface.getNative();
window.confinePointer(true);
// window.setPointerVisible(false); // 如果需要可以隐藏指针
}
}
void draw() {
background(40);
// 绘制窗口边界
stroke(100);
noFill();
rect(0, 0, width-1, height-1);
// 绘制鼠标位置指示
float displayX, displayY;
if (usePhysicalConstraint) {
// 方法一:物理约束 - mouseX/mouseY 天然就在窗口内
displayX = mouseX;
displayY = mouseY;
fill(0, 255, 0);
text("模式: 物理约束 (GLWindow.confinePointer)", 10, 25);
} else {
// 方法二:数值约束 - 确保值在窗口范围内
displayX = constrain(mouseX, 0, width);
displayY = constrain(mouseY, 0, height);
fill(255, 200, 0);
text("模式: 数值约束 (constrain 函数)", 10, 25);
}
// 绘制十字准星
stroke(255);
strokeWeight(1);
line(displayX - 15, displayY, displayX + 15, displayY);
line(displayX, displayY - 15, displayX, displayY + 15);
// 绘制圆形
noStroke();
fill(255, 100);
ellipse(displayX, displayY, 30, 30);
// 显示鼠标坐标
fill(255);
textSize(12);
text("mouseX: " + displayX + " mouseY: " + displayY, 10, height - 15);
}
// 按空格键切换模式
void keyPressed() {
if (key == ' ') {
usePhysicalConstraint = !usePhysicalConstraint;
// 注意:物理约束需要在 setup 中设置,这里只是演示切换提示
if (!usePhysicalConstraint) {
GLWindow window = (GLWindow) surface.getNative();
window.confinePointer(false);
} else {
GLWindow window = (GLWindow) surface.getNative();
window.confinePointer(true);
}
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。