我有一个JScrollPane,其中包含JPanel,其中包含一些自定义组件,这些组件是JPanel的扩展(它们都是相同的类型)。在显示包含JFrame之前,此JScrollPane设置为不可见。
当用户选择JCheckBox时,我使用setVisible()
来显示滚动窗格。第一次显示窗格时,在调用setVisible()
和绘制窗格之间存在显着延迟。如果用户取消选中并重新选中复选框,则会立即绘制窗格。
我的自定义组件已经构建并添加到面板中。它们是ComponentListener但除了componentResized()
之外有空实现。它们也有一个自定义paintComponent()
方法,但该方法中的断点显示延迟发生在调用它之前,因此它不是慢速绘制的情况。
JScrollPane或JPanel都没有任何其他侦听器。 setVisible()
和paintComponent()
之间还会发生什么?我还能在哪里确定延迟的来源?
修改 我试图根据MCVE的建议创建和Kevin Workman,我发现我的问题与我的想法略有不同。似乎没有其他任何事情发生滚动窗格将永远不会被绘制。
在我的最小例子中(见下文),在我调整框架大小之前,该项目不会显示。在初始显示后,setVisible()
会立即应用,如同完整程序一样。以下是演示此问题的示例代码:
public class VisibilityDelayExample extends JFrame {
private JPanel contentPane;
private JCheckBox chckbxAdvancedView;
private JScrollPane scrollPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
VisibilityDelayExample frame = new VisibilityDelayExample();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public VisibilityDelayExample() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
chckbxAdvancedView = new JCheckBox("Advanced View");
chckbxAdvancedView.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent arg0) {
System.err.println("Property Changed");
if(chckbxAdvancedView.isSelected() != scrollPane.isVisible()){
scrollPane.setVisible(chckbxAdvancedView.isSelected());
scrollPane.invalidate();
scrollPane.repaint();
VisibilityDelayExample.this.invalidate();
VisibilityDelayExample.this.repaint();
}
}
});
contentPane.add(chckbxAdvancedView, BorderLayout.NORTH);
scrollPane = new JScrollPane();
scrollPane.setVisible(false);
contentPane.add(scrollPane, BorderLayout.CENTER);
JPanel panel = new JPanel();
scrollPane.setViewportView(panel);
for(int j = 0; j < 100;j++){
panel.add(new JLabel("Label " + j));
}
}
}
现在的问题是,调整大小期间发生了什么导致setVisible()
生效?如何让它立即发生?
答案 0 :(得分:4)
现在问题是,在调整大小期间发生了什么
调整框架大小时,将调用布局管理器,以使滚动窗格的大小从(0,0)更改为适当的值。
我怎样才能让它立即发生?
在可见GUI中添加/删除组件时,需要使用revalidate()和repaint()父容器。我知道你没有添加组件,但效果是一样的,因为它没有有效的大小。
// scrollPane.revalidate();
// scrollPane.repaint();
// VisibilityDelayExample.this.invalidate();
// VisibilityDelayExample.this.repaint();
contentPane.revalidate();
contentPane.repaint();
答案 1 :(得分:2)
Conversely,您的示例的此变体会覆盖滚动窗格的getPreferredSize()
方法以提供任意大小。该复选框使用ItemListener
来切换可见性。请注意使用pack()
,其中&#34;使Window
的大小适合其子组件的首选大小和布局。&#34;
附录:此更新使滚动窗格最初不可见,并调整框架的大小以适应。
public class VisibilityDelayExample extends JFrame {
private JCheckBox chckbxAdvancedView;
private JScrollPane scrollPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
VisibilityDelayExample frame = new VisibilityDelayExample();
frame.setVisible(true);
}
});
}
public VisibilityDelayExample() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout(0, 0));
chckbxAdvancedView = new JCheckBox("Advanced View");
chckbxAdvancedView.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
System.out.println(e);
scrollPane.setVisible(chckbxAdvancedView.isSelected());
}
});
add(chckbxAdvancedView, BorderLayout.NORTH);
JPanel panel = new JPanel(new GridLayout(0, 1));
for (int j = 0; j < 100; j++) {
panel.add(new JLabel("Label " + j));
}
scrollPane = new JScrollPane(panel) {
@Override
public Dimension getPreferredSize() {
return new Dimension(450, 300);
}
};
add(scrollPane, BorderLayout.CENTER);
pack();
scrollPane.setVisible(false);
setSize(scrollPane.getPreferredSize());
}
}