gpt4 book ai didi

java - JDialog不可见,组件可点击

转载 作者:太空宇宙 更新时间:2023-11-04 15:20:15 24 4
gpt4 key购买 nike

我使用在应用程序启动时启动的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 的 消息列表(如按钮、标签和图标)创建消息控件。最后,该方法向主框架发送类似 Delegate 的命令,以显示包含 MessagePanelControlJDialog总结一下:

  • messageList.size()>0:为MessageHandler中列表中的每条消息创建消息面板
  • messageList.size()>0:使用 MessagePanelControl 显示 JDialog
  • messageList.size()<=0:使用 MessagePanelControl 隐藏 JDialog

    公共(public)无效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.invokeLaterRunnableinvokeLater 会提交给 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 执行它的任务,否则我们的应用程序会卡住。请阅读我的posted answer here for details关于 EDT 和 EventQueue 如何执行 Swing 事件和渲染任务。

虽然我们不知道您的应用程序逻辑,但您可以从 invokeLater 中删除 synchronized (viewSynchronizationObject) {},而是将 SwingUtilities.此同步块(synchronized block)内的 invokeLater(new Runnable() {}:

synchronized (viewSynchronizationObject) 
{
SwingUtilities.invokeLater(new Runnable() { /* your code */ } );
}

关于java - JDialog不可见,组件可点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20465456/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com