美好的一天! 我想使用具有全屏独占模式的标准Swing Timer。为此,我应用SwingWorker来控制应该设置图形模式的事件。以下所有步骤均在run方法中执行。从main调用run()。 1)首先,我创建我的SwingWorker对象并覆盖其两个方法(doInBackground和done)。 Init是一个重要的方法,因为它应该将所有需要的图形设置设置为当前的JFrame对象,并将其与我的密钥监听器对象(称为screen_list)绑定:
...
worker = new SwingWorker<Window, Void>()
{
public Window doInBackground()
{
init();
return gdev.getFullScreenWindow();
}
public void done()
{
try {
disp = get();
}
catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
...
2)然后我创建了我的screenlistener,它实现了一个ActionListener和一个Key Listener,在init()方法中它与disp绑定为KeyListener:
private void init()
{
...
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
gdev.setDisplayMode(use_dm);
disp.createBufferStrategy(2);
disp.setFocusTraversalKeysEnabled(false);
disp.addKeyListener((KeyListener)screen_list);
}
}
catch(IllegalArgumentException ex)
{
}
...
}
3)我创建并初始化我的Swing Timer并启动它; 4)最后我调用了execute方法:
public void run(int pause, int delay)
{
...
try
{
screen_list = new ScreenListener();
tm = new Timer(delay, screen_list);
tm.setInitialDelay(pause);
tm.setRepeats(true);
tm.start();
worker.execute();
}
catch(Exception e)
{}
...
}
我编写的类ScreenListener实现了一个KeyListener和一个ActionListener。在ActionPerfomed方法中,我检查了工作人员是否完成了它的工作(init方法),如果是的话,我会参考当前的显示模式并绘制一些东西:
class ScreenListener implements ActionListener, KeyListener
{
public void actionPerformed(ActionEvent e)
{
if(!worker.isDone())
{
return;
}
else
{
//gdev - GraphicsDevice type
disp = gdev.getFullScreenWindow();
if (disp != null)
{
...
draw(gr);
...
}
}
}
...
}
为什么不处理键盘事件?
答案 0 :(得分:0)
我没有从init进行所有那些Swing调用。 Init应该将所有需要的图形设置设置为当前的JFrame对象,并将密钥监听器与它绑定。
好的,我看到你已经改变了一些代码:
private void init()
{
...
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
gdev.setDisplayMode(use_dm);
disp.createBufferStrategy(2);
disp.setFocusTraversalKeysEnabled(false);
disp.addKeyListener((KeyListener)screen_list);
}
}
catch(IllegalArgumentException ex)
{
}
...
}
但是当你获得JFrame时,你仍然在init中进行Swing调用,设置它的显示模式和缓冲策略,它是焦点遍历业务,并添加一个键监听器。为什么这些调用是在后台线程中进行的,因为它们不会干扰Swing处理(所以不需要在后台完成),实际上是“Swing调用”,因为你正在改变Swing的状态与他们对象。 doInBackground用于运行长时间运行或CPU密集型进程,如果在EDT上运行,则会冻结GUI并使其无响应。您显示的代码不会这样做。在后台线程中进行Swing调用的危险在于,虽然它会在95%的时间内工作,但它会在意外时间失败,从而导致应用程序崩溃和刻录,通常是在最不合适的时间。
另外,为什么空挡块?我至少在那里放了一个ex.printStackTrace(),以免盲目飞行。
2)然后我创建了我的screenlistener,它实现了一个ActionListener和一个Key Listener,在init()方法中它与disp绑定为KeyListener:
我是否正确地声明您正在向JFrame添加KeyListener?我怀疑这是否有效,因为KeyListeners仅在绑定组件具有焦点时才响应,这是JFrame很少会做或想做的事情。也许您希望使用更通用的键绑定,因为这样可以在焦点和响应方面提供更大的灵活性。
3)然后我创建并初始化我的Swing Timer并启动它;
行
4)最后我调用了execute方法。 -
public void run(int pause, int delay)
{
...
try
{
screen_list = new ScreenListener();
tm = new Timer(delay, screen_list);
tm.setInitialDelay(pause);
tm.setRepeats(true);
tm.start();
worker.execute();
}
catch(Exception e)
{}
...
}
你又有一个空的挡块。
你能告诉我们更多你的具体问题吗?我们看到一些不相关的代码,其中含有模糊的描述,但实际上并没有完全了解任何东西。您能否详细介绍一下您的计划及其问题?您是否正在尝试按照Andrew的建议创建SSCCE?如果您可以创建并发布此文件,我们将能够更好地测试和修改您的程序并帮助您找到解决方案。祝你好运
答案 1 :(得分:0)
我使用了SwingWorker功能,因为时间计时器尚未设置全屏模式。 Ок。我放弃了使用SwingWorker。而不是这个,我添加了一个简单的条件:
class ScreenListener implements ActionListener, KeyListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("ScreenListener: actionPerformed");
disp = gdev.getFullScreenWindow();
if(disp == null)
{
return;
}
else
{
//draw something
...
}
}
}
所以现在我的run方法看起来像这样
public void run(int pause, int delay)
{
screen_list = new ScreenListener();
init();
try
{
tm = new Timer(delay, (ActionListener)screen_list);
tm.setInitialDelay(pause);
tm.setRepeats(true);
tm.start();
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
if(!tm.isRunning())
{
...
}
}
}
我做了一个可调焦的事情:
private void init()
{
JFrame frame = new JFrame();
...
disp = new Window(frame);
DisplayMode[] dms = gdev.getDisplayModes();
DisplayMode use_dm = null;
if(gdev.isFullScreenSupported())
{
disp.setBackground(Color.CYAN);
disp.setForeground(Color.WHITE);
gdev.setFullScreenWindow(disp);
}
use_dm = getMatchMode(dms, def_dm);
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
...
disp.setFocusable(true);
disp.addKeyListener((KeyListener)screen_list);
...
}
}
catch(IllegalArgumentException ex)
{
ex.printStackTrace();
}
}
但我仍然无法抓住我的键盘事件。 KeyTyped,KeyPressed,KeyReleased仍然没有被调用,所以这是我在该程序中的问题。
我的第一个目标是制作一个全屏模式的简单动画。起初我使用了一个简单的线程方法 - sleep - 就像主线程一样。然后我添加了一个摆动计时器用于相同的目的,但你看起来我遇到了一个问题:我无法使我的KeyListener工作。
答案 2 :(得分:0)
我决定了我的问题:
1)现在,FullScreen类从JFrame扩展:
public class SimpleFullScreen extends JFrame
{
...
private synchronized void init()
{
Window disp = null;
//customize my display
setFocusable(true);
setResizable(false);
setIgnoreRepaint(true);
setUndecorated(true);
setBackground(Color.CYAN);
setForeground(Color.WHITE);
addKeyListener((KeyListener)screen_list);
DisplayMode[] dms = gdev.getDisplayModes();
DisplayMode use_dm = null;
if(gdev.isFullScreenSupported())
gdev.setFullScreenWindow(this);
use_dm = getMatchMode(dms, def_dm);
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
gdev.setDisplayMode(use_dm);
createBufferStrategy(2);
}
}
catch(IllegalArgumentException ex)
{
ex.printStackTrace();
}
}
...
}
2)在run方法中添加循环,它检出计时器正在运行:
public void run(int pause, int delay)
{
Window disp = null;
screen_list = new ScreenListener();
init();
try
{
//Initialize and start timer
...
while(tm.isRunning())
{
System.out.println("Run: timer running");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if(!tm.isRunning())
{
disp = gdev.getFullScreenWindow();
disp.setVisible(false);
disp.dispose();
gdev.setFullScreenWindow(null);
System.exit(0);
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
3)init,actionPerfomed和KeyPressed成为同步方法。
所以ActionListener和KeyListener运行良好。
感谢您的回复!