[英]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
的静态方法的工作方式如下:
JOptionPane
and prepare it with the arguments.JOptionPane
并用参数准备它。JOptionPane
(created from step 1) to the dialog (or internal frame) (created from step 2) with the required listeners.JOptionPane
(从步骤 1 创建)添加到具有所需侦听器的对话框(或内部框架)(从步骤 2 创建)。 Step 2 and 3 take place in the create*
methods of JOptionPane
.第 2 步和第 3 步发生在
JOptionPane
的create*
方法中。
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...");
});
}
}
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.