You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JOGL中myCanvas.addKeyListener(this)报错的原因咨询

问题:JOGL中调用myCanvas.addKeyListener(this)抛出类型不匹配错误

错误提示:

The method addKeyListener(KeyListener) in the type Component is not applicable for the arguments (Code)

用户需求:通过上下左右箭头控制立方体绕水平/垂直轴旋转,实现KeyListener接口后添加监听器时触发上述错误,完整代码如下:

import java.io.*;
import java.lang.Math;
import java.nio.*;
import javax.swing.*;
import static com.jogamp.opengl.GL4.*;
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.texture.*;
import com.jogamp.common.nio.Buffers;
import com.jogamp.newt.event.KeyListener;

import org.joml.*;
import java.awt.event.KeyEvent;

public class Code extends JFrame implements GLEventListener,KeyListener
{   private GLCanvas myCanvas;
    
    private int renderingProgram;
    private int vao[] = new int[1];
    private int vbo[] = new int[3];
    private float cameraX, cameraY, cameraZ;
    private float objLocX, objLocY, objLocZ;
    
    // allocate variables for display() function
    private FloatBuffer vals = Buffers.newDirectFloatBuffer(16);
    private Matrix4f pMat = new Matrix4f();  // perspective matrix
    private Matrix4f vMat = new Matrix4f();  // view matrix
    private Matrix4f mMat = new Matrix4f();  // model matrix
    private Matrix4f mvMat = new Matrix4f(); // model-view matrix
    private int mvLoc, pLoc;
    private float aspect;
    
    private int shuttleTexture;
    private int rotateX = 0,rotateY = 0;
    
    private int numObjVertices;
    private ImportedModel myModel;
    

    public Code()
    {   setTitle("Chapter6 - program3");
        setSize(600, 600);
        myCanvas = new GLCanvas();
        myCanvas.addKeyListener(this); //this line throws an error.
        myCanvas.addGLEventListener(this);
        
        this.add(myCanvas);
        myCanvas.setFocusable(true);
        this.setVisible(true);
    }

    public void display(GLAutoDrawable drawable)
    {   GL4 gl = (GL4) GLContext.getCurrentGL();
        gl.glClear(GL_COLOR_BUFFER_BIT);
        gl.glClear(GL_DEPTH_BUFFER_BIT);

        gl.glUseProgram(renderingProgram);

        int mvLoc = gl.glGetUniformLocation(renderingProgram, "mv_matrix");
        int pLoc = gl.glGetUniformLocation(renderingProgram, "p_matrix");

        vMat.identity().setTranslation(-cameraX,-cameraY,-cameraZ);

        mMat.identity();
        mMat.translate(objLocX, objLocY, objLocZ);

        mMat.rotateX((float)Math.toRadians(20.0f));
        mMat.rotateY((float)Math.toRadians(130.0f));
        mMat.rotateZ((float)Math.toRadians(5.0f));

        mvMat.identity();
        mvMat.mul(vMat);
        mvMat.mul(mMat);

        gl.glUniformMatrix4fv(mvLoc, 1, false, mvMat.get(vals));
        gl.glUniformMatrix4fv(pLoc, 1, false, pMat.get(vals));

        gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
        gl.glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        gl.glEnableVertexAttribArray(0);

        gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
        gl.glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
        gl.glEnableVertexAttribArray(1);

        gl.glActiveTexture(GL_TEXTURE0);
        gl.glBindTexture(GL_TEXTURE_2D, shuttleTexture);

        gl.glEnable(GL_DEPTH_TEST);
        gl.glDepthFunc(GL_LEQUAL);
        gl.glDrawArrays(GL_TRIANGLES, 0, myModel.getNumVertices());
    }

    public void init(GLAutoDrawable drawable)
    {   GL4 gl = (GL4) GLContext.getCurrentGL();
    
        myModel = new ImportedModel("cube1.obj");
        renderingProgram = Utils.createShaderProgram("src/code/vertShader.glsl", "src/code/fragShader.glsl");

        float aspect = (float) myCanvas.getWidth() / (float) myCanvas.getHeight();
        pMat.identity().setPerspective((float) Math.toRadians(60.0f), aspect, 0.1f, 1000.0f);

        setupVertices();
        cameraX = 0.0f; cameraY = 0.0f; cameraZ = 3.0f;
        objLocX = 0.0f; objLocY = 0.0f; objLocZ = 0.0f;

        shuttleTexture = Utils.loadTexture("Material5.jpg");
    }

    private void setupVertices()
    {   GL4 gl = (GL4) GLContext.getCurrentGL();
    
        numObjVertices = myModel.getNumVertices();
        Vector3f[] vertices = myModel.getVertices();
        Vector2f[] texCoords = myModel.getTexCoords();
        Vector3f[] normals = myModel.getNormals();
        
        float[] pvalues = new float[numObjVertices*3];
        float[] tvalues = new float[numObjVertices*2];
        float[] nvalues = new float[numObjVertices*3];
        
        for (int i=0; i<numObjVertices; i++)
        {   pvalues[i*3]   = (float) (vertices[i]).x() + rotateX;
            pvalues[i*3+1] = (float) (vertices[i]).y() + rotateY;
            pvalues[i*3+2] = (float) (vertices[i]).z();
            tvalues[i*2]   = (float) (texCoords[i]).x();
            tvalues[i*2+1] = (float) (texCoords[i]).y();
            nvalues[i*3]   = (float) (normals[i]).x();
            nvalues[i*3+1] = (float) (normals[i]).y();
            nvalues[i*3+2] = (float) (normals[i]).z();
        }
        
        gl.glGenVertexArrays(vao.length, vao, 0);
        gl.glBindVertexArray(vao[0]);
        gl.glGenBuffers(vbo.length, vbo, 0);
        
        gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
        FloatBuffer vertBuf = Buffers.newDirectFloatBuffer(pvalues);
        gl.glBufferData(GL_ARRAY_BUFFER, vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW);

        gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
        FloatBuffer texBuf = Buffers.newDirectFloatBuffer(tvalues);
        gl.glBufferData(GL_ARRAY_BUFFER, texBuf.limit()*4, texBuf, GL_STATIC_DRAW);

        gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
        FloatBuffer norBuf = Buffers.newDirectFloatBuffer(nvalues);
        gl.glBufferData(GL_ARRAY_BUFFER, norBuf.limit()*4,norBuf, GL_STATIC_DRAW);
    }
    
    

    public void keyTyped(KeyEvent e) {}
    

    public static void main(String[] args) { 
        new Code();}


    public void dispose(GLAutoDrawable drawable) {}
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
    {   float aspect = (float) myCanvas.getWidth() / (float) myCanvas.getHeight();
        pMat.identity().setPerspective((float) Math.toRadians(60.0f), aspect, 0.1f, 1000.0f);
    }

    public void keyPressed(com.jogamp.newt.event.KeyEvent arg0) {
        // TODO Auto-generated method stub
        int key = arg0.getKeyCode();
        System.out.println(arg0.getKeyCode());
        if ( key == KeyEvent.VK_LEFT )
        {
            rotateX +=2;
            System.out.println("Left arrow is pressed");
        }
        else if ( key == KeyEvent.VK_RIGHT )
            rotateY += 2;
        else if ( key == KeyEvent.VK_DOWN)
            rotateX += 2;
        else if ( key == KeyEvent.VK_UP )
            rotateX -= 2;
        else if ( key == KeyEvent.VK_HOME )
            rotateX = rotateY = 0;
        
    }

    public void keyReleased(com.jogamp.newt.event.KeyEvent arg0) {}
}

原因分析

核心问题是监听器类型不兼容:

  • 你导入的是com.jogamp.newt.event.KeyListener(JOGL NEWT框架的键盘监听器),但GLCanvas是AWT组件,它的addKeyListener方法要求传入的是AWT标准的java.awt.event.KeyListener,两者属于不同的UI工具链,类型无法匹配。
  • 代码还混合了两种KeyEvent(AWT和NEWT),会导致后续按键逻辑的混淆。

解决方法

方案1:改用AWT标准KeyListener

完全适配AWT组件体系:

  1. 替换监听器导入:
    // 删除 import com.jogamp.newt.event.KeyListener;
    import java.awt.event.KeyListener;
    
  2. 统一使用AWT的KeyEvent,修改按键方法的参数类型:
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            rotateX += 2;
        } else if (key == KeyEvent.VK_RIGHT) {
            rotateY += 2;
        } else if (key == KeyEvent.VK_DOWN) {
            rotateX += 2;
        } else if (key == KeyEvent.VK_UP) {
            rotateX -= 2;
        } else if (key == KeyEvent.VK_HOME) {
            rotateX = rotateY = 0;
        }
    }
    
    @Override
    public void keyReleased(KeyEvent e) {}
    
  3. 保留keyTyped方法的AWT参数类型即可。

方案2:改用NEWT组件替代GLCanvas

如果想使用NEWT的监听器体系(JOGL推荐的跨平台方案),替换AWT的GLCanvas为NEWT的GLWindow:

  1. 导入NEWT窗口类:
    import com.jogamp.newt.opengl.GLWindow;
    
  2. 修改窗口初始化代码:
    private GLWindow myWindow;
    
    public Code() {
        setTitle("Chapter6 - program3");
        GLProfile profile = GLProfile.get(GLProfile.GL4);
        GLCapabilities capabilities = new GLCapabilities(profile);
        myWindow = GLWindow.create(capabilities);
        myWindow.addKeyListener(this); // 此时NEWT监听器可正常添加
        myWindow.addGLEventListener(this);
        myWindow.setSize(600, 600);
        myWindow.setVisible(true);
    }
    
  3. 原有的NEWTKeyListener和KeyEvent方法无需修改。

额外优化提示

当前代码中修改rotateX/rotateY后不会实时更新画面,因为顶点数据只在初始化时生成一次。需要把旋转逻辑移到display方法的模型矩阵中:

public void display(GLAutoDrawable drawable) {
    // ... 其他代码不变 ...
    mMat.identity();
    mMat.translate(objLocX, objLocY, objLocZ);
    // 应用动态旋转
    mMat.rotateX((float)Math.toRadians(rotateX));
    mMat.rotateY((float)Math.toRadians(rotateY));
    // 保留原有固定旋转(如果需要)
    mMat.rotateX((float)Math.toRadians(20.0f));
    mMat.rotateY((float)Math.toRadians(130.0f));
    mMat.rotateZ((float)Math.toRadians(5.0f));
    // ... 其他代码不变 ...
}

内容的提问来源于stack exchange,提问作者DRV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 21:18:06