[英]revalidate()/repaint() not working within ActionListener
I am trying to add an OpenGL context to a jFrame. 我试图将OpenGL上下文添加到jFrame。
It works when I do it like this: 当我这样做时它会起作用:
jframe.setVisible( true );
jframe.getContentPane().add( glcanvas, BorderLayout.CENTER );
jframe.revalidate();
jframe.repaint();
However if I try to create the context on a button click like this: 但是,如果我尝试在按钮上创建上下文,则单击,如下所示:
JButton startButton = new JButton("Start");
startButton.addActionListener(
new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
jframe.getContentPane().add( glcanvas, BorderLayout.CENTER );
jframe.revalidate();
jframe.repaint();
}
});
jframe.add(startButton);
then nothing happens. 那什么也没发生 If I try and debug it the program runs through the revalidate() and repaint() commands but nothing changes.
如果我尝试对其进行调试,则程序将通过revalidate()和repaint()命令运行,但没有任何变化。
Can someone please tell me why this is happening - why is it different when I try to call it on a button press? 有人可以告诉我为什么会发生这种情况吗?当我尝试按按钮调用它时,为什么会有所不同? Also can you suggest a way to fix this?
您还可以建议解决此问题的方法吗? I need to be able to open the context from a menu system.
我需要能够从菜单系统中打开上下文。
-- Edited: Here is the full code of my test program -编辑:这是我测试程序的完整代码
/* -- OpenGL -- */
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.awt.GLJPanel;
import javax.swing.JComponent;
/* -- Swing -- */
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
/* -- jFrame Layouts -- */
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Menu
{
public static void main(String[] args)
{
GLProfile glprofile = GLProfile.getDefault();
GLCapabilities glcapabilities = new GLCapabilities( glprofile );
final GLCanvas glcanvas = new GLCanvas( glcapabilities );
glcanvas.addGLEventListener( new GLEventListener()
{
@Override
public void init( GLAutoDrawable glautodrawable )
{
System.out.println("INIT");
}
@Override
public void reshape( GLAutoDrawable glautodrawable, int x, int y, int width, int height )
{
GL2ES2 gl = glautodrawable.getGL().getGL2ES2(); //Get OpenGL
gl.glViewport( 0, 0, width, height ); //Set the viewport
}
@Override
public void display( GLAutoDrawable glautodrawable )
{
GL2ES2 gl = glautodrawable.getGL().getGL2ES2();
gl.glClearColor(+0.0f, +0.2f, +0.9f, +0.0f); // Blue background
//Clear the screen so that we can draw the new one
gl.glClear(
GL2ES2.GL_STENCIL_BUFFER_BIT |
GL2ES2.GL_COLOR_BUFFER_BIT |
GL2ES2.GL_DEPTH_BUFFER_BIT
);
}
@Override
public void dispose( GLAutoDrawable glautodrawable )
{
}
}); /* Add GLEventListner to glCanvas */
final JFrame jframe = new JFrame( "One Triangle Swing GLCanvas" );
jframe.addWindowListener( new WindowAdapter()
{
public void windowClosing( WindowEvent windowevent )
{
jframe.dispose();
System.exit( 0 );
}
});
jframe.setSize( 800, 600 );
jframe.setVisible( true );
/* --- IF I ADD THE ContentPane HERE AND REVALIDATE/REPAINT IT WORKS --- */
//jframe.getContentPane().add( glcanvas, BorderLayout.CENTER );
//jframe.revalidate();
//jframe.repaint();
jframe.setLayout(new FlowLayout());
JButton startButton = new JButton("Start");
startButton.addActionListener(
new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
/* --- I NEED TO ADD THE ContentPane HERE, BUT IF I DO THIS THE REPAINT DOESN'T WORK --- */
jframe.getContentPane().add( glcanvas, BorderLayout.CENTER );
jframe.revalidate();
jframe.repaint();
/* -- I added this because I was told elsewhere that repainting
* in a different thread would make it work, however I haven't
* been successful in getting this to work. Included for information
*/
//repaintThread(jframe);
}
});
jframe.add(startButton);
}
private static void repaintThread(final JFrame jframe)
{
Thread thread = new Thread(new Runnable()
{
public void run()
{
for( int i = 0; i < 200; i++)
{
jframe.revalidate();
jframe.repaint();
try
{
Thread.currentThread().sleep( 50 );
}
catch( Exception ex )
{
break;
}
}
}
});
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
}
This is the line that messes everything up: 这是使一切混乱的行:
jframe.setLayout(new FlowLayout());
You're changing the layout to FlowLayout
and then adding glcanvas
next to startButton
. 您要将布局更改为
FlowLayout
,然后在startButton
旁边添加glcanvas
。 The preferred size of glcanvas
is 0 so it is not visible, although you can see a slight movement of startButton
when the button is clicked. glcanvas
的首选大小是0,因此它是不可见的,尽管单击按钮时可以看到startButton
的轻微移动。
I assume that setting FlowLayout
was not intentional because you are using BorderLayout.CENTER
constraint to add glcanvas
. 我认为设置
FlowLayout
不是故意的,因为您正在使用BorderLayout.CENTER
约束来添加glcanvas
。 So here is a simple fix: 所以这是一个简单的解决方法:
Comment out: 注释掉:
//jframe.setLayout(new FlowLayout());
Add startButton
to the NORTH
of the panel instead of a CENTER
since glcanvas
will go to the CENTER
. 因为
glcanvas
将转到CENTER
所以将startButton
添加到面板的NORTH
而不是CENTER
。 Change: 更改:
jframe.add(startButton);
to: 至:
jframe.add(startButton, BorderLayout.NORTH);
That fixed the revalidation issue, at least on Windows 7 Java 7. 这至少在Windows 7 Java 7上解决了重新验证问题。
Also, see A Visual Guide to Layout Managers for more details and examples about layouts. 另外,有关布局的更多详细信息和示例,请参见《布局管理器视觉指南》 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.