简体   繁体   English

JOptionPane.showInternalConfirmDialog() 框架图标

[英]JOptionPane.showInternalConfirmDialog() frame icon

I have an application using a JDesktopPane and I am using JOptionPane.showInternalConfirmDialog() to get confirmation from the user.我有一个使用 JDesktopPane 的应用程序,我正在使用 JOptionPane.showInternalConfirmDialog() 来获得用户的确认。 The issue I am having is that no matter what I use as the parent, I always get the coffee cup as the frame icon.我遇到的问题是,无论我使用什么作为父级,我总是将咖啡杯作为框架图标。 See example code (without try-catch):请参阅示例代码(不带 try-catch):

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(300, 300);     
frame.setIconImage(ImageIO.read(new File("icon.png")));

JDesktopPane dp = new JDesktopPane();

frame.add(dp);
frame.setVisible(true);
        
if(JOptionPane.showInternalConfirmDialog(frame.getContentPane(),
   "Are you sure?", "Confirm", JOptionPane.YES_NO_OPTION) == 0)
{
   //Do something
}

This is what I get:这就是我得到的:

截屏

If I use the frame as the parent instead of using getContentPane() I get this exception:如果我使用框架作为父级而不是使用 getContentPane() 我得到这个异常:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: JOptionPane: parentComponent does not have a valid parent

Would appreciate any insight into this issue.希望对这个问题有任何见解。

EDIT: I am aware of the workaround of creating a new internal frame as follows:编辑:我知道创建一个新的内部框架的解决方法如下:

JOptionPane jop = new JOptionPane("Are you sure?", JOptionPane.YES_NO_OPTION);
JInternalFrame inf = jop.createInternalFrame(frame, "Confirm");
inf.setFrameIcon(icon);
inf.setVisible(true);

But then the window is no longer modal, which I need it to be.但是随后窗口不再是模态的,而我需要它。

Well, in order to change the dialog's icon image, you need to obtain a reference to the dialog that is created by the JOptionPane s' static methods.好吧,为了更改对话框的图标图像,您需要获取对由JOptionPane的静态方法创建的对话框的引用。

The static methods of JOptionPane work about as follows: JOptionPane的静态方法的工作方式如下:

  1. Create a JOptionPane and prepare it with the arguments.创建一个JOptionPane并用参数准备它。
  2. Create a dialog (or internal frame) and prepare it with the arguments.创建一个对话框(或内部框架)并用参数准备它。
  3. Add the JOptionPane (created from step 1) to the dialog (or internal frame) (created from step 2) with the required listeners.JOptionPane (从步骤 1 创建)添加到具有所需侦听器的对话框(或内部框架)(从步骤 2 创建)。
  4. Show the dialog as modal (blocks for input).将对话框显示为模态(输入块)。
  5. Search the user's supplied value from the selected ones and return it.从选定的值中搜索用户提供的值并返回它。

Step 2 and 3 take place in the create* methods of JOptionPane .第 2 步和第 3 步发生在JOptionPanecreate*方法中。

So you may try the following:因此,您可以尝试以下操作:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Objects;
import javax.swing.JDesktopPane;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

public class OptionPaneCustomIconDialog {
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> {
            
            final JDesktopPane pane = new JDesktopPane();
            pane.setPreferredSize(new Dimension(500, 500));
            
            final JFrame frame = new JFrame("No coffee...");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(pane);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            
            final BufferedImage dialogImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
            final Graphics2D g2d = dialogImage.createGraphics();
            g2d.setColor(Color.RED);
            g2d.fillRect(25, 25, 50, 50);
            g2d.dispose();
            
            final JOptionPane option = new JOptionPane("Are you sure?", JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION);
            final JDialog diag = option.createDialog(pane, "Please confirm...");
            diag.setIconImage(dialogImage); //The solution.
            diag.setVisible(true); //Blocks (because it's modal).
            final Object value = option.getValue();
            if (value == null || Objects.equals(value, JOptionPane.CLOSED_OPTION))
                System.out.println("Closed");
            else if (Objects.equals(value, JOptionPane.YES_OPTION))
                System.out.println("Yes");
            else if (Objects.equals(value, JOptionPane.NO_OPTION))
                System.out.println("No");
            else
                System.err.println("Please implement all options...");
        });
    }
}

As per the docs , you can pass an Icon as a parameter to the showInternalConfirmDialog method.根据文档,您可以将Icon作为参数传递给showInternalConfirmDialog方法。 Just remember to also then add all the rest of the parameters in the correct order.请记住,然后以正确的顺序添加所有其余参数。

Okay, this is the solution I came up with.好的,这是我想出的解决方案。 I had a look at JOptionPane and it uses a private method called startModal() to make the internal frame modal.我看了一下 JOptionPane,它使用一个名为 startModal() 的私有方法来使内部框架模态化。

I copied that method and the static showInternalConfirmDialog() to a new class, added an ImageIcon as an argument and used setFrameIcon() to change the icon.我将该方法和静态 showInternalConfirmDialog() 复制到一个新类,添加一个 ImageIcon 作为参数并使用 setFrameIcon() 更改图标。

Note : I also had to use setVisible() and requestFocus() on the internal frame to make it work.注意:我还必须在内部框架上使用 setVisible() 和 requestFocus() 才能使其工作。

import java.awt.AWTEvent;
import java.awt.ActiveEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.MenuComponent;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import javax.swing.ImageIcon;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class InternalDialog {
    
    public static int showInternalConfirmDialog(Component parentComponent,
                                               Object message, String title,
                                               int optionType, int messageType,
                                               ImageIcon icon)
   {
     JOptionPane pane = new JOptionPane(message, messageType, optionType);
     JInternalFrame frame = pane.createInternalFrame(parentComponent, title);
     
     //WHAT I ADDED
     frame.setFrameIcon(icon);
     frame.setVisible(true);
     frame.requestFocus();
 
     startModal(frame);
 
     if (pane.getValue() instanceof Integer)
       return ((Integer) pane.getValue()).intValue();
     return -1;
   }
    
    private static void startModal(JInternalFrame f){
      // We need to add an additional glasspane-like component directly
      // below the frame, which intercepts all mouse events that are not
      // directed at the frame itself.
      JPanel modalInterceptor = new JPanel();
      modalInterceptor.setOpaque(false);
      JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f);
      lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue());
      modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight());
      modalInterceptor.addMouseListener(new MouseAdapter(){});
      modalInterceptor.addMouseMotionListener(new MouseMotionAdapter(){});
      lp.add(modalInterceptor);
      f.toFront();

      // We need to explicitly dispatch events when we are blocking the event
      // dispatch thread.
      EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
      try
        {
          while (! f.isClosed())
            {
              if (EventQueue.isDispatchThread())
                {
                  // The getNextEventMethod() issues wait() when no
                  // event is available, so we don't need do explicitly wait().
                  AWTEvent ev = queue.getNextEvent();
                  // This mimics EventQueue.dispatchEvent(). We can't use
                  // EventQueue.dispatchEvent() directly, because it is
                  // protected, unfortunately.
                  if (ev instanceof ActiveEvent)
                    ((ActiveEvent) ev).dispatch();
                  else if (ev.getSource() instanceof Component)
                    ((Component) ev.getSource()).dispatchEvent(ev);
                  else if (ev.getSource() instanceof MenuComponent)
                    ((MenuComponent) ev.getSource()).dispatchEvent(ev);
                  // Other events are ignored as per spec in
                  // EventQueue.dispatchEvent
                }
              else
                {
                  // Give other threads a chance to become active.
                  Thread.yield();
                }
            }
        }
      catch (InterruptedException ex)
        {
          // If we get interrupted, then leave the modal state.
        }
      finally
        {
          // Clean up the modal interceptor.
          lp.remove(modalInterceptor);

          // Remove the internal frame from its parent, so it is no longer
          // lurking around and clogging memory.
          Container parent = f.getParent();
          if (parent != null)
            parent.remove(f);
        }
    }
}

Usage:用法:

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(300, 300);

ImageIcon icon = ImageIO.read(new File("icon.png"));     
frame.setIconImage(icon);

JDesktopPane dp = new JDesktopPane();
frame.add(dp);
frame.setVisible(true);
        
if(InternalDialog.showInternalConfirmDialog(frame.getContentPane(),
  "Are you sure?", "Confirm", JOptionPane.YES_NO_OPTION, 
  JOptionPane.QUESTION_MESSAGE, icon) == 0)
{
   //Do something
}

The startModal() method might be useful in general for anyone trying to make a modal internal frame. startModal() 方法对于任何试图制作模态内部框架的人来说可能很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM