Java右键单击菜单 [英] Java Right Click Menu

查看:65
本文介绍了Java右键单击菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天。我希望你能帮助我。



我正忙着在JFrame上制作一个小型顶视2D游戏。玩家可以四处走动,并且需要能够右键单击对象。



我到目前为止一直在努力。我的问题是当你右键单击时,菜单会显示,但是当屏幕刷新时(backBuffer重新绘制屏幕),它会隐藏菜单。当您将鼠标移动到菜单必须的位置时,它会显示并在屏幕刷新时再次隐藏(FPS设置为50)。



我不确定它是否隐藏了图形背后的菜单。



有没有办法不断保持菜单最顶级?



编辑:

这是我的代码。我希望这会有所帮助。



Good day all. I hope you can help me.

I'm busy making a small top view 2D game on a JFrame. The player can walk around and needs to be able to right click on objects.

I have everything working up till this point. My problem is that when you right-click, the menu shows up but when the screen refreshes(backBuffer re-draws the screen) it hides the menu. When you move the mouse over where the menu must be it shows up and hides again when the screen refreshes(FPS is set to 50).

I'm not sure if it hides the menu behind the graphics.

Is there a way to constantly keep the menu top-most?


Here is my code. I hope this helps.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;

public class Driver extends JFrame {
	boolean isRunning = true;
	int fps = 50;
	int windowWidth = 400;
	int windowHeight = 400;

	BufferedImage backBuffer;
	Insets insets;
	InputHandler input;

	int x = 0;
	int y = 0;

	static Driver myGame;

	public static void main(String[] args) {
		myGame = new Driver();
		myGame.run();
	}

	public void run() {
		initialize();

		while (isRunning) {
			long time = System.currentTimeMillis();

			update();
			draw();

			time = (1000 / fps) - (System.currentTimeMillis() - time);

			if (time > 0) {
				try {
					Thread.sleep(time);
				} catch (Exception e) {
				}
			}
		}

		setVisible(false);

	}

	void initialize() {
		setTitle("Game Tutorial");
		setSize(windowWidth, windowHeight);
		setResizable(false);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);

		insets = getInsets();
		setSize(insets.left + windowWidth + insets.right, insets.top
				+ windowHeight + insets.bottom);

		backBuffer = new BufferedImage(windowWidth, windowHeight,
				BufferedImage.TYPE_INT_RGB);
		input = new InputHandler(this);

		myGame.addMouseListener(new PopClickListener());
	}

	void update() {
		if (input.isKeyDown(KeyEvent.VK_RIGHT)) {
			x += 20;
			try {
				Thread.sleep(100);
			} catch (Exception e) {
			}
		}
		if (input.isKeyDown(KeyEvent.VK_LEFT)) {
			x -= 20;
		}
		if (input.isKeyDown(KeyEvent.VK_DOWN)) {
			y += 20;
		}
		if (input.isKeyDown(KeyEvent.VK_UP)) {
			y -= 20;
		}
	}

	void draw() {

		Graphics g = getGraphics();

		Graphics bbg = backBuffer.getGraphics();

		bbg.setColor(Color.WHITE);
		bbg.fillRect(0, 0, windowWidth, windowHeight);

		bbg.setColor(Color.BLACK);
		bbg.drawOval(x, y, 20, 20);

		g.drawImage(backBuffer, insets.left, insets.top, this);

	}
}


import java.awt.Component;
import java.awt.event.*;

public class InputHandler implements KeyListener {
	boolean keys[] = new boolean[256];

	public InputHandler(Component c) {
		c.addKeyListener(this);
	}

	public boolean isKeyDown(int keyCode) {
		if (keyCode > 0 && keyCode < 256) {
			return keys[keyCode];
		}

		return false;
	}

	public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() > 0 && e.getKeyCode() < 256) {
			keys[e.getKeyCode()] = true;
		}
	}

	public void keyReleased(KeyEvent e) {
		if (e.getKeyCode() > 0 && e.getKeyCode() < 256) {
			keys[e.getKeyCode()] = false;
		}
	}

	public void keyTyped(KeyEvent e) {
	}
}

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class MenuActionListener implements ActionListener {
	public void actionPerformed(ActionEvent e) {
		System.out.println(e.getActionCommand());
	}
}


import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

class PopClickListener extends MouseAdapter {
	public void mousePressed(MouseEvent e) {
		if (e.isPopupTrigger()) {
			doPop(e);
		}
	}

	public void mouseReleased(MouseEvent e) {
		if (e.isPopupTrigger()) {
			doPop(e);
		}
	}

	private void doPop(MouseEvent e) {
		PopUpDemo menu = new PopUpDemo();
		menu.show(e.getComponent(), e.getX(), e.getY());
	}
}


import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

class PopUpDemo extends JPopupMenu {
	JMenuItem anItem;

	public PopUpDemo() {
		anItem = new JMenuItem("Click Me!");
		add(anItem);
		anItem.addActionListener(new MenuActionListener());
	}
}





提前致谢:)



Thanks in advance :)

推荐答案

问题似乎与你如何绘制到窗口有关。您的绘图功能不会考虑您需要绘制弹出菜单的事实。 Swing系统的工作方式是框架具有操作系统调用的重绘方法。此消息逐渐渗透到每个组件,使用框架的Graphics对象沿着它绘制它。您绕过该系统并手动绘制到屏幕上。



解决方案非常简单。您需要保留对您创建的PopUpDemo类的引用并使用它来绘制它。



对于PopClickListener:



The issue appears to be with how you're drawing to the window. Your draw function doesn't account for the fact that you need to draw the pop up menu too. The way the Swing system works is that the frame has its repaint method called by the operating system. This message trickles down to each component, painting it along the way using the frame's Graphics object. You're bypassing that system and painting to the screen manually.

The solution is fairly simple. You need to keep a reference to the PopUpDemo class you create and use that to paint it.

For the PopClickListener:

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
class PopClickListener extends MouseAdapter {
        PopUpDemo menu;
    
	public void mousePressed(MouseEvent e) {
		if (e.isPopupTrigger()) {
			doPop(e);
		}
	}
 
	public void mouseReleased(MouseEvent e) {
		if (e.isPopupTrigger()) {
			doPop(e);
		}
	}
 
	private void doPop(MouseEvent e) {
		menu = new PopUpDemo();
                menu.setIgnoreRepaint(true);
		menu.show(e.getComponent(), e.getX(), e.getY());
	}
}





注意添加菜单变量。



对于Driver类:





Note the addition of the menu variable.

For the Driver class:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
 
import javax.swing.JFrame;
 
public class Driver extends JFrame {
    
	boolean isRunning = true;
	int fps = 50;
	int windowWidth = 400;
	int windowHeight = 400;
 
	BufferedImage backBuffer;
	Insets insets;
	InputHandler input;
        
        PopClickListener popupClick;
 
        ...
 
	void draw() {
 
		Graphics g = getGraphics();
 
		Graphics bbg = backBuffer.getGraphics();
 
		bbg.setColor(Color.WHITE);
		bbg.fillRect(0, 0, windowWidth, windowHeight);
 
		bbg.setColor(Color.BLACK);
		bbg.drawOval(x, y, 20, 20);
                
                if(popupClick.menu != null && popupClick.menu.isVisible()){
                    if(popupClick.menu.getParent() != null){
                        bbg.translate(popupClick.menu.getParent().getX()
                                , popupClick.menu.getParent().getY());
                        popupClick.menu.paint(bbg);
                    }
                }
                
		g.drawImage(backBuffer, insets.left, insets.top, this);
	}
}





这里有两点需要注意。首先是添加popupClick变量,它跟踪您正在使用的PopClickListener。这样我们就可以访问前面提到的菜单变量了。第二是对draw()方法的改变。你会注意到我添加了两行,一行用于检查菜单是否存在,另一行用于调用弹出菜单的paint方法,向其传递用于缓冲的Graphics对象。另一个需要注意的重要事项是,我必须调用getParent()。getX()和getParent()。getY()来获取在正确位置绘制的菜单。这是因为菜单通常将自己绘制在0,0(在其父组件空间中)。该父组件通常是位于JFrame的LayeredPane内的JPanel。



另一种方法是在菜单组件上调用repaint()而不是翻译原点然后调用paint ,但这往往会产生闪烁,因为repaint()不会立即绘制,而是在JVM有机会绕过它时进行绘制。



Two things to note here. First is the addition of the popupClick variable, which keeps track of the PopClickListener you're using. This way we can access the menu variable I mentioned earlier. Second is the change to the draw() method. You'll note that I added two lines, one to check if the menu exists and the other to call the paint method of the popup menu, passing it the Graphics object you're using for your buffering. The other important thing to note is that I had to call getParent().getX() and getParent().getY() to get the menu to draw in the right place. This is because the menu normally draws itself at 0,0 (in its parent's component space). That parent component is normally a JPanel located inside the JFrame's LayeredPane.

An alternative is to call repaint() on the menu component instead of translating the origin and then calling paint, but that tends to generate flickering because repaint() doesn't paint immediately, but instead paints when the JVM has a chance to get around to it.


这篇关于Java右键单击菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆