[英]Size JDialog so correct size when invisible components made visible
[英]JDialog invisible, components clickable
我使用的是在应用程序启动时设置为Instatiated的JDialog
,以多次显示消息。 有时,对话框及其控件是不可见的,但可以单击。
JDialog
仅实例化一次,每次应显示一条消息时将其设置为可见的“ true”,然后将其设置为可见的“ false”,直到应显示下一条消息为止。
为了排除与多线程相关的问题,当线程创建消息并显示对话框时,我始终将SwingUtilities.invokeLater(...)
用于ui调用。
因为这是一个庞大的项目,而且我的问题与任何特定的代码都不相关,所以我不发布代码,而是描述问题。 该问题似乎不是可重现的,但有时会发生,因此尽管在EDT
上运行了每个相关的调用,但它仍可能是线程问题。
我究竟做错了什么?
public class MessageHandler {
private volatile static MessageHandler messageHandler = null;
private List<Message>messages = null;
private volatile WeakReference<MessagesPanelControl> view = null;
private final Object viewSynchronizationObject = new Object();
private MessageHandler() {
messages = new ArrayList<Message>();
}
public static MessageHandler getInstance() {
MessageHandler result = messageHandler;
if (result == null) {
synchronized (MessageHandler.class) {
result = messageHandler;
if (result == null)
messageHandler = result = new MessageHandler();
}
}
return result;
}
public void registerView(MessagesPanelControl view) {
this.view = new WeakReference<MessagesPanelControl>(view);
}
public void addMessage(final Message message) {
synchronized (viewSynchronizationObject) {
messages.add(message);
Collections.sort(messages);
updateView();
}
}
private void updateView() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
synchronized (viewSynchronizationObject) {
if (view == null) {
return;
}
MessagesPanelControl mpc = view.get();
if (mpc != null) {
mpc.updateView();
}
}
}
});
}
}
在MainFrame类中,我在启动时进行了一次初始化:
MessagesPanelControl mp = new MessagesPanelControl();
MessageHandler.getInstance().registerView(mp);
LockPane messageBasicPane = new LockPane(this, mp);
然后在不同的线程中调用它,以通过MessageHandler
Singleton显示消息:
MessageHandler.getInstance().addMessage(Message.getSimpleMessage("Error", "Fatal error occured", Message.MessageIcon.ERROR));
我没有发布所有详细信息,但是发布了所有必要的部分以理解整个问题,希望它使它更易于理解。
MessagePanelControl
(mpc)是扩展JPanel
的类。 它的updateView()
方法基于MessageHandler's
消息列表(如按钮,标签和图标updateView()
创建消息控件。 最后,该方法向主框架发送类似于Delegate
命令,以显示包含MessagePanelControl
的JDialog
。 总结一下:
MessageHandler
中的列表中的每个消息创建消息面板 MessagePanelControl
JDialog messageList.size()<= 0:使用MessagePanelControl
隐藏JDialog
公共无效的updateView(){已同步(viewMPCSynchronizationObject){Utils.throwExceptionWhenNotOnEDT();
JPanel messagesListPanel = new JPanel(); scrollPane.setViewportView(messagesListPanel); scrollPane.setBorder(null); messagesListPanel.setLayout(new BoxLayout(messagesListPanel, BoxLayout.Y_AXIS)); if (MessageHandler.getInstance().getMessages() != null && MessageHandler.getInstance().getMessages().size() > 0) { [...] //Create buttons, text icons... for each message [...] SwingUtilities.invokeLater(new Runnable() { public void run() { MainFrame().showMessageBoard(); } }); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { MainFrame().closeMessageBoard(); } }); } repaint(); }
}
大型机:
//Show Messageboard
public void showMessageBoard() {
if (messageBasicPane != null) {
messageBasicPane.setVisible(true);
messageBasicPane.repaint();
}
}
[...]
//Close Messageboard
public void closeMessageBoard() {
if (messageBasicPane != null) {
messageBasicPane.setVisible(false);
}
}
此行将详细创建JDialog
:
[...]
public LockPane(JFrame parentFrame, JComponent componentToShow, Dimension paneSize, float opacity, ModalityType modality) {
super(parentFrame, true);
Utils.throwExceptionWhenNotOnEDT();
createDialog(paneSize, opacity, modality);
if (componentToShow != null) {
add(componentToShow);
}
pack();
}
private void createDialog(Dimension paneSize, float opacity, ModalityType modality) {
Utils.throwExceptionWhenNotOnEDT();
setUndecorated(true);
setModalityType(modality);
if (opacity < 1 && opacity >= 0)
com.sun.awt.AWTUtilities.setWindowOpacity(this, opacity);
setSize(paneSize);
setPreferredSize(paneSize);
setMaximumSize(paneSize);
setBounds(0, 0, paneSize.width, paneSize.height);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
}
[...]
Java VisualVM
一项新发现是,AWT-EventQueue没有被阻塞,只是在某个时间段内有很小的“等待”时间,而没有阻塞。 另一个奇怪的事情是,有时我的JDialog
是完全透明的(不可见的),有时是白色的并且具有所需的不透明度。
在此函数中,您实际上是在等待传递给SwingUtilities.invokeLater
的Runnable
,后者将invokeLater
提交给EDT以便执行。 如果您在viewSynchronizationObject
上持有的锁被其他应用程序线程锁定,则它将阻止EDT,这实际上在您的代码中很明显,因为您在其他几个地方使用了此变量。
private void updateView() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
synchronized (viewSynchronizationObject) {
if (view == null) {
return;
}
MessagesPanelControl mpc = view.get();
if (mpc != null) {
mpc.updateView();
}
}
}
},false);
}
切勿以其他方式阻止EDT执行任务,否则应用程序将冻结。 请阅读我发布的答案,以了解有关EDT和EventQueue如何执行Swing事件和渲染任务的详细信息 。
虽然我们不知道您的应用程序逻辑,但是您可以从invokeLater
删除已synchronized (viewSynchronizationObject) {}
,而是可以将SwingUtilities.invokeLater(new Runnable() {}
放入此同步块中:
synchronized (viewSynchronizationObject)
{
SwingUtilities.invokeLater(new Runnable() { /* your code */ } );
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.