-1

For purposes that involve fancy looking components, I wrote a function that creates and shows a JOptionPane in a JDialog. Now, I need to get input from that JDialog but I can't. Is there a way that will let me get input from that JDialog without extending either JDialog or JOptionPane? (I also can't use UIManager to alter the appearance of JDialog that's why I'm having the problem in the first place)

public static final Color WHITE = Color.WHITE;
public static final Color RED = Color.RED;
public static final Color LIGHTER_RED = new Color(255, 0, 0, 100);
public static final Color LIGHT_RED = new Color(255, 0, 0, 160);
public static final Color DARK_BLUE = new Color(22, 44, 66);

public static final Font GEORGIA_BOLD_12 = new Font("Georgia", Font.BOLD, 12);

public static final BasicStroke STROKE_0 = new BasicStroke(0);

private static void recursivePaint(Container ct) {
    for (Component c : ct.getComponents()) {
        if (c instanceof Container) {
            c.setBackground(DARK_BLUE);
            c.setForeground(WHITE);
            recursivePaint((Container) c);
        }
    }
}

public static int showInputDialog(final Container parent) {
    int portNumber = 0;

    final JLabel label = new JLabel("Enter an Open Port: ", SwingConstants.LEFT);
    label.setOpaque(true);
    label.setBackground(DARK_BLUE);
    label.setForeground(WHITE);

    final JButton button = new JButton("OK") {

        private static final long serialVersionUID = -4808194362293478299L;

        @Override
        public int getWidth() {
            return 51;
        }

        @Override
        public int getHeight() {
            return 26;
        }

        @Override
        public void paintComponent(final Graphics g) {
            final Graphics2D g2d = (Graphics2D) g;
            g2d.clearRect(0, 0, getWidth(), getHeight());
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.setStroke(STROKE_0);
            g2d.setColor(LIGHTER_RED);
            if (this.getModel().isRollover()) {
                g2d.setColor(LIGHT_RED);
            }
            if (this.getModel().isPressed()) {
                g2d.setColor(RED);
            }
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.setColor(RED);
            g2d.drawRect(0, 0, getWidth(), getHeight());
            g2d.setColor(WHITE);
            g2d.setFont(GEORGIA_BOLD_12);
            g2d.drawString("CONFIRM", 10, 18);
        }
    };
    button.addActionListener(e -> {
        //GET THE INPUT OF JOPTIONPANE TEXTFIELD
        //portNumber = getTextOfJOptionPane();
        SwingUtilities.getWindowAncestor((Component) e.getSource()).setVisible(false);
        SwingUtilities.getWindowAncestor((Component) e.getSource()).dispose();
    });

    final JOptionPane optionPane = new JOptionPane(label, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_OPTION, null, new JButton[] {button}, button);
    optionPane.setWantsInput(true);
    optionPane.setOpaque(true);
    optionPane.setBackground(DARK_BLUE);
    optionPane.getInputValue();
    recursivePaint(optionPane);
    final JDialog d = optionPane.createDialog(parent, "Open port required!");
    d.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    d.setContentPane(optionPane);
    d.pack();
    d.setLocationRelativeTo(parent);
    d.setVisible(true);
    return portNumber;
}

Thanks in advance.

JOptionPane on Windows

Community
  • 1
  • 1
Doga Oruc
  • 783
  • 3
  • 16
  • Take a closer look at [the JavaDocs for `JOptionPane`](https://docs.oracle.com/javase/8/docs/api/javax/swing/JOptionPane.html), in particular look at the ***"Direct Use:"*** example. Basically, AFTER the dialog has been closed, you will, as you normally would have to, get the value from the `JOptionPane`, but you will need to do this "manually" instead – MadProgrammer Jun 17 '18 at 23:24
  • Thank!. I just did and got an idea, but there is one line that I don't understand there, what does "pane.set.Xxxx(...); // Configure" mean? There are no such methods for JOptionPane. Can you describe how to "configure" a JOptionPane – Doga Oruc Jun 17 '18 at 23:28
  • Wait, does that simply mean the set methods? I'm confused :( – Doga Oruc Jun 17 '18 at 23:29
  • Yes, it means you will need to configure the dialog your self. In particular `setWantsUnput`, `setSelectionValues`, `setInitialSelectionValue` and you can get the input value via `getInputValue`. Take a look at the source code for `JOptionPane.showInputDialog`, it will demonstrate how the dialog is actually build by the class itself – MadProgrammer Jun 17 '18 at 23:32
  • You could just do something more like [this](https://stackoverflow.com/questions/14591089/joptionpane-passing-custom-buttons/14591165#14591165) which might be simpler – MadProgrammer Jun 17 '18 at 23:33
  • Looked at the link you provided, but I don't think that's what I need. I need to get input from the textField/textArea the JDialog has not from the buttons. – Doga Oruc Jun 17 '18 at 23:37
  • JOptionPane is already configured in the posted code. – Doga Oruc Jun 17 '18 at 23:38
  • The linked documentation is EXACTLY what you should be looking at, take the time to dive into the available methods, because that's all `JOptionPane` uses - a quick glance reveals that `getInputValue` is probably what you're after, but you will need to check which "option" the use selected, because they could have just closed the dialog without doing anything, which is generally treated as a "cancel" – MadProgrammer Jun 17 '18 at 23:40
  • Tried it, but failed. I'm doing something wrong... The method "getInputValue" always returns JOptionPane.UNINITIALIZED_VALUE for some reason. My code is almost the same as the source code. Cannot figure out the problem. Any idea why? – Doga Oruc Jun 17 '18 at 23:53
  • 1
    Long story short - you're going to have to set this up manually, including providing the `JTextField`, when the "confirm" button is pressed, you will need to take the value from the `JTextField` and call `setInputValue` - why, because the `JOptionPane` doesn't expose the `JTextField` use for input in the base class, this seems to be applied by the look and feel delegate – MadProgrammer Jun 18 '18 at 00:08
  • Understood, just realized calling setInputValue(9999) in the method solved the issue. I need to create a JTextField and add it to a panel alongside with my already created JLabel right? After that I should be adding a KeyListener to the JTextField and call setInputValue everytime a number is pressed. Such a burden. Thanks for your help :) – Doga Oruc Jun 18 '18 at 00:13
  • Or better, just found another answer of yours, I'll look at your way and adapt it accordingly. [link](https://stackoverflow.com/questions/28163962/joptionpane-with-a-jtextarea-instead-of-a-text-field) – Doga Oruc Jun 18 '18 at 00:15

1 Answers1

1

Since JOptionPane doesn't expose ALL the functionality you would need to replicate this, you're going to have to take more control.

The "appropriate" path would be to supply your own custom look and feel delegate, but that seems like a lot of extra work just so you can control the JTextField.

Instead, you could pass both the JLabel and JTextField to the OptionPane via the message parameter, contained in a single JPanel, for example...

public static final Color WHITE = Color.WHITE;
public static final Color RED = Color.RED;
public static final Color LIGHTER_RED = new Color(255, 0, 0, 100);
public static final Color LIGHT_RED = new Color(255, 0, 0, 160);
public static final Color DARK_BLUE = new Color(22, 44, 66);

public static final Font GEORGIA_BOLD_12 = new Font("Georgia", Font.BOLD, 12);

public static final BasicStroke STROKE_0 = new BasicStroke(0);

public static int showInputDialog(final Container parent) {
    int portNumber = 0;

    final JLabel label = new JLabel("Enter an Open Port: ", SwingConstants.LEFT);
    label.setForeground(WHITE);

    JPanel panel = new JPanel(new GridLayout(2, 1));
    panel.setOpaque(true);
    panel.setBackground(DARK_BLUE);
    JTextField inputField = new JTextField(10);
    panel.add(label);
    panel.add(inputField);

    final JButton button = new JButton("OK") {

        private static final long serialVersionUID = -4808194362293478299L;

        @Override
        public int getWidth() {
            return 51;
        }

        @Override
        public int getHeight() {
            return 26;
        }

        @Override
        public void paintComponent(final Graphics g) {
            final Graphics2D g2d = (Graphics2D) g;
            g2d.clearRect(0, 0, getWidth(), getHeight());
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.setStroke(STROKE_0);
            g2d.setColor(LIGHTER_RED);
            if (this.getModel().isRollover()) {
                g2d.setColor(LIGHT_RED);
            }
            if (this.getModel().isPressed()) {
                g2d.setColor(RED);
            }
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.setColor(RED);
            g2d.drawRect(0, 0, getWidth(), getHeight());
            g2d.setColor(WHITE);
            g2d.setFont(GEORGIA_BOLD_12);
            g2d.drawString("CONFIRM", 10, 18);
        }
    };
    final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_OPTION, null, new JButton[]{button}, button);
    button.addActionListener(e -> {
        //GET THE INPUT OF JOPTIONPANE TEXTFIELD
        optionPane.setInputValue(inputField.getText());
        optionPane.setValue(JOptionPane.OK_OPTION);
    });

    optionPane.setOpaque(true);
    optionPane.setBackground(DARK_BLUE);
    final JDialog d = optionPane.createDialog(parent, "Open port required!");
    d.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    d.setContentPane(optionPane);
    d.pack();
    d.setLocationRelativeTo(parent);
    d.setVisible(true);
    System.out.println(optionPane.getValue());
    System.out.println(optionPane.getInputValue());
    return portNumber;
}

So. In addition, I've made some additional changes. In the ActionListener, I've set the "value" of the operation to OK_OPTION and called setInputValue. It's important that you call setValue, otherwise the inputValue is not applied, because it thinks you've "cancelled" the dialog.

I don't what you're dialog looks like on your system, but this is what it looks like on mine....

This is why it's ill-advised to override things like getHeight and getWidth

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Damn, it looks fine on Windows OS. Never thought it would look that distorted on other OS'. Any advice on how to properly create a custom looking button without overriding getHeight and getWidth? I can really use some advice at the moment. – Doga Oruc Jun 18 '18 at 00:27
  • Yeah, either the API as intended or write your own :P – MadProgrammer Jun 18 '18 at 00:33
  • I've added an imgur link to my answer. That is the JOptionPane's image. When the recursivePaint function is used(which you didn't because I forgot to add it but now it is added) it looks OK. But I'm sure there are better ways yo create custom buttons. So, if you have any alternatives apart from this way, I'm definitely positive about hearing them. Again, thanks for helping. The program is finally complete. :) – Doga Oruc Jun 18 '18 at 00:36