欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

【Swing】JPanel重写paint()后按钮被遮挡,点击按钮键盘监听失效

程序员文章站 2022-03-15 09:54:57
效果图内容说明上图是我们小组做的泡泡堂,在接近项目结尾时,我接手一个小任务,就是在游戏进行界面底部增加截图中的3个按钮,并实现部分功能(有些按钮的功能组员已经实现了,我只需要调用他们的方法就可以了)。下面,我来将遇到的问题抽离出来,记录到博客。我相信应该也有同学会遇到这些问题。1、如何布局能更好的将按钮组放在面板的底部居中位置?并且看起来像悬浮在地图之上。2、由于面板中复写了paint()方法,导致按钮组被遮挡。但是当鼠标移上去,按钮组又可以显现出来。3、点击底部任意一个按钮后,键...

效果图

【Swing】JPanel重写paint()后按钮被遮挡,点击按钮键盘监听失效

内容说明

上图是我们小组做的泡泡堂,在接近项目结尾时,我接手一个小任务,就是在游戏进行界面底部增加截图中的3个按钮,并实现部分功能(有些按钮的功能组员已经实现了,我只需要调用他们的方法就可以了)。下面,我来将遇到的问题抽离出来,记录到博客。我相信应该也有同学会遇到这些问题。

1、如何布局能更好的将按钮组放在面板的底部居中位置?并且看起来像悬浮在地图之上。

2、由于面板中复写了paint()方法,导致按钮组被遮挡。但是当鼠标移上去,按钮组又可以显现出来。

3、点击底部任意一个按钮后,键盘监听失效。按键盘,无法操作游戏中的人物。

问题1

其实我对于Java Swing的布局也不是太熟悉,并且感觉不太好用。要实现上述布局效果,可以利用布局嵌套。

(1)首先,按钮组(可以是多个按钮),无论宽度多少,都居中显示,我们可以想到FlowLayout.CENTER

(2)那么如何将按钮组布局到底部呢?显然,我们可以将这多个按钮放到一个JPanel(可命名为:btnPanel)中,然后将该面板利用BorderLayout.SOUTH放到底部。

(3)又有一个问题,我们想要看到的想过是按钮组像是悬浮在游戏地图之上。但是,放按钮组的btnPanel的面板是灰色的,它会遮挡游戏地图。那么,我们可以通过setOpaque(false)将面板背景设置为透明,这样只有按钮是显示的,背景是透明的。

下面,给出具体代码

// 布局嵌套。BorderLayout.SOUTH和FlowLayout.CENTER)实现按钮组底部居中
// 游戏面板的布局
this.setLayout(new BorderLayout()); 

// 按钮组面板
JPanel btnPanel = new JPanel();
btnPanel.setOpaque(false);	// 将面板设置为透明,否则灰色面板会遮挡地图
btnPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
bgmBtn = new JButton("开启BGM");
runBtn = new JButton("暂停游戏");
overBtn = new JButton("结束游戏");
btnPanel.add(bgmBtn);
btnPanel.add(runBtn);
btnPanel.add(overBtn);

// 将按钮组面板,放置到游戏面板的南部
this.add(btnPanel, BorderLayout.SOUTH);

问题2

经测试,有两种解决方法。

(1)重写paint()方法时,最后加上super.paintChildren(g),重写组件。

(2)不要重写paint()方法,而是直接重写paintComponent()方法

下面我已第(1)种解决方法,给出代码

        /**
	 * 重写绘画方法。绘画时是有固定的顺序,先绘画的图片会在底层,后绘画的图片会覆盖先绘画的
	 * 约定:本方法只执行一次,想实时刷新需要使用多线程
	 */
	@Override
	public void paint(Graphics g) {
		super.paint(g);

        /*
        // 自己的代码......
		// 所有元素的显示
		Map<GameElement, List<ElementObj>> all = em.getGameElements();
		// GameElement.values()是隐藏方法,无法点进去
		// 返回的数组的顺序时是枚举变量声明时的顺序
		for (GameElement ge : GameElement.values()) {
			List<ElementObj> list = all.get(ge);
//			if(ge.equals(GameElement.MAPS)) {
////			if(ge == GameElement.MAPS) {
//				Collections.sort(list);
//			}
			for (int i = 0; i < list.size(); i++) {
				ElementObj obj = list.get(i);
				obj.showElement(g);
			}
		}
        */
		
		// !!!重新绘制子组件,否则paint之后会遮挡住组件!!!
		super.paintChildren(g);
			
	}

问题3

显然,键盘监听是用来操作游戏中的人物的。那么在游戏进行过程中,点击了底部按钮,键盘监听为什么会失效?

因为,我们的键盘监听是作用在窗体上(JFrame),当点击底部按钮,窗体失去了焦点,焦点落在了按钮上。所以键盘会失效。所以,只需要通过requestFocus()让窗体重新获得焦点即可。

代码如何操作呢?在按钮的点击事件中,在完成了点击事件的所以逻辑之后,拿到当前窗体的实例对象,调用它的requestFocus()让它重新获得焦点即可。

代码比较简单,我就不把我项目中的代码贴出来了。

本文地址:https://blog.csdn.net/qq_43290318/article/details/107612241