Browse Source

Added Option pane ui.

pull/15/head
weisj 5 years ago
parent
commit
cf058d8fa1
  1. 313
      src/main/java/com/weis/darklaf/ui/optionpane/DarkOptionPaneUI.java
  2. 1
      src/main/java/com/weis/darklaf/ui/text/DarkFormattedTextFieldUI.java
  3. 5
      src/main/resources/com/weis/darklaf/properties/ui/optionPane.properties
  4. 192
      src/test/java/dialog/CustomDialog.java
  5. 587
      src/test/java/dialog/DialogDemo.java
  6. BIN
      src/test/java/dialog/images/green.gif
  7. BIN
      src/test/java/dialog/images/middle.gif
  8. 203
      src/test/java/formattedTextField/FormattedTextFieldDemo.java
  9. BIN
      src/test/java/formattedTextField/images/left.gif
  10. BIN
      src/test/java/formattedTextField/images/red.gif
  11. BIN
      src/test/java/formattedTextField/images/right.gif

313
src/main/java/com/weis/darklaf/ui/optionpane/DarkOptionPaneUI.java

@ -0,0 +1,313 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.ui.optionpane;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import sun.swing.DefaultLookup;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicOptionPaneUI;
import java.awt.*;
public class DarkOptionPaneUI extends BasicOptionPaneUI {
@NotNull
@Contract("_ -> new")
public static ComponentUI createUI(final JComponent x) {
return new DarkOptionPaneUI();
}
@Override
protected void installDefaults() {
super.installDefaults();
}
@Override
protected Container createButtonArea() {
JPanel bottom = new JPanel();
Border border = (Border) DefaultLookup.get(optionPane, this, "OptionPane.buttonAreaBorder");
bottom.setName("OptionPane.buttonArea");
if (border != null) {
bottom.setBorder(border);
}
bottom.setLayout(new DarkButtonAreaLayout(
DefaultLookup.getBoolean(optionPane, this, "OptionPane.sameSizeButtons", false),
DefaultLookup.getInt(optionPane, this, "OptionPane.buttonPadding", 6),
DefaultLookup.getInt(optionPane, this, "OptionPane.buttonOrientation", SwingConstants.CENTER),
DefaultLookup.getBoolean(optionPane, this, "OptionPane.isYesLast", false)));
addButtonComponents(bottom, getButtons(), getInitialValueIndex());
return bottom;
}
protected boolean getSizeButtonsToSameWidth() {
return UIManager.getBoolean("OptionPane.sameSizeButtons");
}
/**
* <code>ButtonAreaLayout</code> behaves in a similar manner to
* <code>FlowLayout</code>. It lays out all components from left to
* right. If <code>syncAllWidths</code> is true, the widths of each
* component will be set to the largest preferred size width.
* <p>
* This class should be treated as a &quot;protected&quot; inner class.
* Instantiate it only within subclasses of {@code BasicOptionPaneUI}.
*/
public static class DarkButtonAreaLayout extends ButtonAreaLayout {
protected boolean syncAllWidthOverwrite = false;
private int orientation;
private boolean reverseButtons;
/**
* Indicates whether or not centersChildren should be used vs
* the orientation. This is done for backward compatibility
* for subclassers.
*/
private boolean useOrientation;
public DarkButtonAreaLayout(final boolean syncAllSizes, final int padding, final int orientation,
final boolean reverseButtons) {
this(syncAllSizes, padding);
useOrientation = true;
this.orientation = orientation;
this.reverseButtons = reverseButtons;
}
/**
* Constructs a new instance of {@code ButtonAreaLayout}.
*
* @param syncAllWidths if the width of children should be synchronized
* @param padding the padding value
*/
public DarkButtonAreaLayout(final boolean syncAllWidths, final int padding) {
super(syncAllWidths, padding);
this.syncAllWidths = syncAllWidths;
this.padding = padding;
centersChildren = true;
useOrientation = false;
}
/**
* Sets if the width of children should be synchronized.
*
* @param newValue if the width of children should be synchronized
*/
public void setSyncAllWidths(final boolean newValue) {
syncAllWidths = newValue;
}
/**
* Returns if the width of children should be synchronized.
*
* @return if the width of children should be synchronized
*/
public boolean getSyncAllWidths() {
return syncAllWidths && !syncAllWidthOverwrite;
}
/**
* Sets the padding value.
*
* @param newPadding the new padding
*/
public void setPadding(final int newPadding) {
this.padding = newPadding;
}
/**
* Returns the padding.
*
* @return the padding
*/
public int getPadding() {
return padding;
}
/**
* Sets whether or not center children should be used.
*
* @param newValue a new value
*/
public void setCentersChildren(final boolean newValue) {
centersChildren = newValue;
useOrientation = false;
}
/**
* Returns whether or not center children should be used.
*
* @return whether or not center children should be used
*/
public boolean getCentersChildren() {
return centersChildren;
}
private int getOrientation(final Container container) {
if (!useOrientation) {
return SwingConstants.CENTER;
}
if (container.getComponentOrientation().isLeftToRight()) {
return orientation;
}
switch (orientation) {
case SwingConstants.LEFT:
return SwingConstants.RIGHT;
case SwingConstants.RIGHT:
return SwingConstants.LEFT;
case SwingConstants.CENTER:
return SwingConstants.CENTER;
}
return SwingConstants.LEFT;
}
public void addLayoutComponent(final String string, final Component comp) {
}
public void layoutContainer(final Container container) {
Component[] children = container.getComponents();
if (children != null && children.length > 0) {
int numChildren = children.length;
Insets insets = container.getInsets();
int maxWidth = 0;
int maxHeight = 0;
int totalButtonWidth = 0;
int x = 0;
int xOffset = 0;
boolean ltr = container.getComponentOrientation().isLeftToRight();
boolean reverse = (ltr) == reverseButtons;
for (Component child : children) {
Dimension pref = child.getPreferredSize();
maxWidth = Math.max(maxWidth, pref.width);
maxHeight = Math.max(maxHeight, pref.height);
totalButtonWidth += pref.width;
}
if (getSyncAllWidths()) {
int totalButtonWidthTmp = maxWidth * numChildren;
totalButtonWidthTmp += (numChildren - 1) * padding;
syncAllWidthOverwrite = totalButtonWidthTmp > container.getWidth();
if (!syncAllWidthOverwrite) {
totalButtonWidth = totalButtonWidthTmp;
}
} else {
totalButtonWidth += (numChildren - 1) * padding;
}
switch (getOrientation(container)) {
case SwingConstants.LEFT:
x = insets.left;
break;
case SwingConstants.RIGHT:
x = container.getWidth() - insets.right - totalButtonWidth;
break;
case SwingConstants.CENTER:
if (getCentersChildren() || numChildren < 2) {
x = (container.getWidth() - totalButtonWidth) / 2;
} else {
x = insets.left;
if (getSyncAllWidths()) {
xOffset = (container.getWidth() - insets.left -
insets.right - totalButtonWidth) /
(numChildren - 1) + maxWidth;
} else {
xOffset = (container.getWidth() - insets.left -
insets.right - totalButtonWidth) /
(numChildren - 1);
}
}
break;
}
for (int counter = 0; counter < numChildren; counter++) {
int index = (reverse) ? numChildren - counter - 1 :
counter;
Dimension pref = children[index].getPreferredSize();
if (getSyncAllWidths()) {
children[index].setBounds(x, insets.top, maxWidth, maxHeight);
} else {
children[index].setBounds(x, insets.top, pref.width, pref.height);
}
if (xOffset != 0) {
x += xOffset;
} else {
x += children[index].getWidth() + padding;
}
}
}
syncAllWidthOverwrite = false;
}
public Dimension minimumLayoutSize(final Container c) {
if (c != null) {
Component[] children = c.getComponents();
if (children != null && children.length > 0) {
Dimension aSize;
int numChildren = children.length;
int height = 0;
Insets cInsets = c.getInsets();
int extraHeight = cInsets.top + cInsets.bottom;
int extraWidth = cInsets.left + cInsets.right;
if (getSyncAllWidths()) {
int maxWidth = 0;
for (Component child : children) {
aSize = child.getPreferredSize();
height = Math.max(height, aSize.height);
maxWidth = Math.max(maxWidth, aSize.width);
}
return new Dimension(extraWidth + (maxWidth * numChildren) +
(numChildren - 1) * padding,
extraHeight + height);
} else {
int totalWidth = 0;
for (Component child : children) {
aSize = child.getPreferredSize();
height = Math.max(height, aSize.height);
totalWidth += aSize.width;
}
totalWidth += ((numChildren - 1) * padding);
return new Dimension(extraWidth + totalWidth, extraHeight + height);
}
}
}
return new Dimension(0, 0);
}
public Dimension preferredLayoutSize(final Container c) {
return minimumLayoutSize(c);
}
public void removeLayoutComponent(final Component c) {
}
}
}

1
src/main/java/com/weis/darklaf/ui/text/DarkFormattedTextFieldUI.java

@ -97,7 +97,6 @@ public class DarkFormattedTextFieldUI extends DarkTextFieldUI implements Propert
@Override
public void changedUpdate(final DocumentEvent e) {
update();
}
protected void update() {

5
src/main/resources/com/weis/darklaf/properties/ui/optionPane.properties

@ -21,7 +21,12 @@
#SOFTWARE.
#
# suppress inspection "UnusedProperty" for whole file
OptionPaneUI = com.weis.darklaf.ui.optionpane.DarkOptionPaneUI
OptionPane.messageForeground = %textForeground
OptionPane.buttonPadding = 5
#SwingConstants.CENTER
OptionPane.buttonOrientation = 0
OptionPane.sameSizeButtons = false
#Icons
OptionPane.informationIcon = dialog/informationDialog.svg[aware](32,32)

192
src/test/java/dialog/CustomDialog.java

@ -0,0 +1,192 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package dialog;
import javax.swing.*;
import javax.swing.text.DefaultFormatterFactory;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
/* 1.4 example used by DialogDemo.java. */
class CustomDialog extends JDialog implements ActionListener, PropertyChangeListener {
private String typedText = null;
private JFormattedTextField textField;
private DialogDemo dd;
private String magicWord;
private JOptionPane optionPane;
private String btnString1 = "Enter";
private String btnString2 = "Cancel";
/**
* Creates the reusable dialog.
*/
public CustomDialog(final Frame aFrame, final String aWord, final DialogDemo parent) {
super(aFrame, true);
dd = parent;
magicWord = aWord.toUpperCase();
setTitle("Quiz");
textField = new JFormattedTextField("");
textField.setColumns(10);
textField.setFormatterFactory(new DefaultFormatterFactory(new JFormattedTextField.AbstractFormatter() {
@Override
public Object stringToValue(final String text) throws ParseException {
if (!magicWord.equals(text)) {
throw new ParseException("Invalid magic word", 0);
}
return text;
}
@Override
public String valueToString(final Object value) {
return value == null ? "" : value.toString();
}
}));
textField.setFocusLostBehavior(JFormattedTextField.COMMIT);
//Create an array of the text and components to be displayed.
String msgString1 = "What was Dr. SEUSS's real last name?";
String msgString2 = "(The answer is \"" + magicWord + "\".)";
Object[] array = {msgString1, msgString2, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
//Create the JOptionPane.
optionPane = new JOptionPane(array, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION,
null, options, options[0]);
//Make this dialog display it.
setContentPane(optionPane);
//Handle window closing correctly.
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(final WindowEvent we) {
/*
* Instead of directly closing the window,
* we're going to change the JOptionPane's
* value property.
*/
optionPane.setValue(JOptionPane.CLOSED_OPTION);
}
});
//Ensure the text field always gets the first focus.
addComponentListener(new ComponentAdapter() {
public void componentShown(final ComponentEvent ce) {
textField.requestFocusInWindow();
}
});
//Register an event handler that puts the text into the option pane.
textField.addActionListener(this);
//Register an event handler that reacts to option pane state changes.
optionPane.addPropertyChangeListener(this);
}
/**
* Returns null if the typed string was invalid;
* otherwise, returns the string as the user entered it.
*/
public String getValidatedText() {
return typedText;
}
/**
* This method handles events for the text field.
*/
public void actionPerformed(final ActionEvent e) {
optionPane.setValue(btnString1);
}
/**
* This method reacts to state changes in the option pane.
*/
public void propertyChange(final PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (isVisible()
&& (e.getSource() == optionPane)
&& (JOptionPane.VALUE_PROPERTY.equals(prop) ||
JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
Object value = optionPane.getValue();
if (value == JOptionPane.UNINITIALIZED_VALUE) {
//ignore reset
return;
}
//Reset the JOptionPane's value.
//If you don't do this, then if the user
//presses the same button next time, no
//property change event will be fired.
optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
if (btnString1.equals(value)) {
typedText = textField.getText();
String ucText = typedText.toUpperCase();
if (magicWord.equals(ucText)) {
//we're done; clear and dismiss the dialog
clearAndHide();
} else {
//text was invalid
textField.selectAll();
JOptionPane.showMessageDialog(CustomDialog.this,
"Sorry, \"" + typedText + "\" " + "isn't a valid response.\n"
+ "Please enter " + magicWord + ".",
"Try again", JOptionPane.ERROR_MESSAGE);
typedText = null;
textField.requestFocusInWindow();
}
} else { //user closed dialog or clicked cancel
dd.setLabel("It's OK. We won't force you to type " + magicWord + ".");
typedText = null;
clearAndHide();
}
}
}
/**
* This method clears the dialog and hides it.
*/
public void clearAndHide() {
textField.setText(null);
setVisible(false);
}
}

587
src/test/java/dialog/DialogDemo.java

@ -0,0 +1,587 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package dialog;
import com.weis.darklaf.LafManager;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Objects;
/*
* DialogDemo.java requires these files:
* CustomDialog.java
* images/middle.gif
*/
public class DialogDemo extends JPanel {
private JLabel label;
private ImageIcon icon = createImageIcon("images/middle.gif");
private JFrame frame;
private String simpleDialogDesc = "Some simple message dialogs";
private String iconDesc = "A JOptionPane has its choice of icons";
private String moreDialogDesc = "Some more dialogs";
private CustomDialog customDialog;
/**
* Creates the GUI shown inside the frame's content pane.
*/
public DialogDemo(final JFrame frame) {
super(new BorderLayout());
this.frame = frame;
customDialog = new CustomDialog(frame, "geisel", this);
customDialog.pack();
//Create the components.
JPanel frequentPanel = createSimpleDialogBox();
JPanel featurePanel = createFeatureDialogBox();
JPanel iconPanel = createIconDialogBox();
label = new JLabel("Click the \"Show it!\" button"
+ " to bring up the selected dialog.",
JLabel.CENTER);
//Lay them out.
Border padding = BorderFactory.createEmptyBorder(20, 20, 5, 20);
frequentPanel.setBorder(padding);
featurePanel.setBorder(padding);
iconPanel.setBorder(padding);
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Simple Modal Dialogs", null,
frequentPanel,
simpleDialogDesc); //tooltip text
tabbedPane.addTab("More Dialogs", null,
featurePanel,
moreDialogDesc); //tooltip text
tabbedPane.addTab("Dialog Icons", null,
iconPanel,
iconDesc); //tooltip text
add(tabbedPane, BorderLayout.CENTER);
add(label, BorderLayout.PAGE_END);
label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
/**
* Creates the panel shown by the first tab.
*/
private JPanel createSimpleDialogBox() {
final int numButtons = 4;
JRadioButton[] radioButtons = new JRadioButton[numButtons];
final ButtonGroup group = new ButtonGroup();
JButton showItButton = null;
final String defaultMessageCommand = "default";
final String yesNoCommand = "yesno";
final String yeahNahCommand = "yeahnah";
final String yncCommand = "ync";
radioButtons[0] = new JRadioButton("OK (in the L&F's words)");
radioButtons[0].setActionCommand(defaultMessageCommand);
radioButtons[1] = new JRadioButton("Yes/No (in the L&F's words)");
radioButtons[1].setActionCommand(yesNoCommand);
radioButtons[2] = new JRadioButton("Yes/No "
+ "(in the programmer's words)");
radioButtons[2].setActionCommand(yeahNahCommand);
radioButtons[3] = new JRadioButton("Yes/No/Cancel "
+ "(in the programmer's words)");
radioButtons[3].setActionCommand(yncCommand);
for (int i = 0; i < numButtons; i++) {
group.add(radioButtons[i]);
}
radioButtons[0].setSelected(true);
showItButton = new JButton("Show it!");
showItButton.addActionListener(e -> {
String command = group.getSelection().getActionCommand();
//ok dialog
if (Objects.equals(command, defaultMessageCommand)) {
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.");
//yes/no dialog
} else if (Objects.equals(command, yesNoCommand)) {
int n = JOptionPane.showConfirmDialog(
frame, "Would you like green eggs and ham?",
"An Inane Question",
JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.YES_OPTION) {
setLabel("Ewww!");
} else if (n == JOptionPane.NO_OPTION) {
setLabel("Me neither!");
} else {
setLabel("Come on -- tell me!");
}
//yes/no (not in those words)
} else if (Objects.equals(command, yeahNahCommand)) {
Object[] options = {"Yes, please", "No way!"};
int n = JOptionPane.showOptionDialog(frame,
"Would you like green eggs and ham?",
"A Silly Question",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (n == JOptionPane.YES_OPTION) {
setLabel("You're kidding!");
} else if (n == JOptionPane.NO_OPTION) {
setLabel("I don't like them, either.");
} else {
setLabel("Come on -- 'fess up!");
}
//yes/no/cancel (not in those words)
} else if (Objects.equals(command, yncCommand)) {
Object[] options = {"Yes, please",
"No, thanks",
"No eggs, no ham!"};
int n = JOptionPane.showOptionDialog(frame,
"Would you like some green eggs to go "
+ "with that ham?",
"A Silly Question",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[2]);
if (n == JOptionPane.YES_OPTION) {
setLabel("Here you go: green eggs and ham!");
} else if (n == JOptionPane.NO_OPTION) {
setLabel("OK, just the ham, then.");
} else if (n == JOptionPane.CANCEL_OPTION) {
setLabel("Well, I'm certainly not going to eat them!");
} else {
setLabel("Please tell me what you want!");
}
}
});
return createPane(simpleDialogDesc + ":",
radioButtons,
showItButton);
}
/**
* Creates the panel shown by the second tab.
*/
private JPanel createFeatureDialogBox() {
final int numButtons = 5;
JRadioButton[] radioButtons = new JRadioButton[numButtons];
final ButtonGroup group = new ButtonGroup();
JButton showItButton;
final String pickOneCommand = "pickone";
final String textEnteredCommand = "textfield";
final String nonAutoCommand = "nonautooption";
final String customOptionCommand = "customoption";
final String nonModalCommand = "nonmodal";
radioButtons[0] = new JRadioButton("Pick one of several choices");
radioButtons[0].setActionCommand(pickOneCommand);
radioButtons[1] = new JRadioButton("Enter some text");
radioButtons[1].setActionCommand(textEnteredCommand);
radioButtons[2] = new JRadioButton("Non-auto-closing dialog");
radioButtons[2].setActionCommand(nonAutoCommand);
radioButtons[3] = new JRadioButton("Input-validating dialog "
+ "(with custom message area)");
radioButtons[3].setActionCommand(customOptionCommand);
radioButtons[4] = new JRadioButton("Non-modal dialog");
radioButtons[4].setActionCommand(nonModalCommand);
for (int i = 0; i < numButtons; i++) {
group.add(radioButtons[i]);
}
radioButtons[0].setSelected(true);
showItButton = new JButton("Show it!");
showItButton.addActionListener(e -> {
String command = group.getSelection().getActionCommand();
//pick one of many
if (Objects.equals(command, pickOneCommand)) {
Object[] possibilities = {"ham", "spam", "yam"};
String s = (String) JOptionPane.showInputDialog(
frame,
"Complete the sentence:\n"
+ "\"Green eggs and...\"",
"Customized Dialog",
JOptionPane.PLAIN_MESSAGE,
icon,
possibilities,
"ham");
//If a string was returned, say so.
if ((s != null) && (s.length() > 0)) {
setLabel("Green eggs and... " + s + "!");
return;
}
//If you're here, the return value was null/empty.
setLabel("Come on, finish the sentence!");
//text input
} else if (Objects.equals(command, textEnteredCommand)) {
String s = (String) JOptionPane.showInputDialog(
frame,
"Complete the sentence:\n"
+ "\"Green eggs and...\"",
"Customized Dialog",
JOptionPane.PLAIN_MESSAGE,
icon,
null,
"ham");
//If a string was returned, say so.
if ((s != null) && (s.length() > 0)) {
setLabel("Green eggs and... " + s + "!");
return;
}
//If you're here, the return value was null/empty.
setLabel("Come on, finish the sentence!");
//non-auto-closing dialog
} else if (Objects.equals(command, nonAutoCommand)) {
final JOptionPane optionPane = new JOptionPane(
"The only way to close this dialog is by\n"
+ "pressing one of the following buttons.\n"
+ "Do you understand?",
JOptionPane.QUESTION_MESSAGE,
JOptionPane.YES_NO_OPTION);
//You can't use pane.createDialog() because that
//method sets up the JDialog with a property change
//listener that automatically closes the window
//when a button is clicked.
final JDialog dialog = new JDialog(frame,
"Click a button",
true);
dialog.setContentPane(optionPane);
dialog.setDefaultCloseOperation(
JDialog.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(final WindowEvent we) {
setLabel("Thwarted user attempt to close window.");
}
});
optionPane.addPropertyChangeListener(
e12 -> {
String prop = e12.getPropertyName();
if (dialog.isVisible()
&& (e12.getSource() == optionPane)
&& (JOptionPane.VALUE_PROPERTY.equals(prop))) {
//If you were going to check something
//before closing the window, you'd do
//it here.
dialog.setVisible(false);
}
});
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
int value = (Integer) optionPane.getValue();
if (value == JOptionPane.YES_OPTION) {
setLabel("Good.");
} else if (value == JOptionPane.NO_OPTION) {
setLabel("Try using the window decorations "
+ "to close the non-auto-closing dialog. "
+ "You can't!");
} else {
setLabel("Window unavoidably closed (ESC?).");
}
//non-auto-closing dialog with custom message area
//NOTE: if you don't intend to check the input,
//then just use showInputDialog instead.
} else if (Objects.equals(command, customOptionCommand)) {
customDialog.setLocationRelativeTo(frame);
customDialog.setVisible(true);
String s = customDialog.getValidatedText();
if (s != null) {
//The text is valid.
setLabel("Congratulations! " + "You entered \"" + s + "\".");
}
//non-modal dialog
} else if (Objects.equals(command, nonModalCommand)) {
//Create the dialog.
final JDialog dialog = new JDialog(frame, "A Non-Modal Dialog");
//Add contents to it. It must have a close button,
//since some L&Fs (notably Java/Metal) don't provide one
//in the window decorations for dialogs.
JLabel label = new JLabel("<html><p align=center>"
+ "This is a non-modal dialog.<br>"
+ "You can have one or more of these up<br>"
+ "and still use the main window.");
label.setHorizontalAlignment(JLabel.CENTER);
label.setFont(label.getFont().deriveFont(Font.PLAIN, 14.0f));
JButton closeButton = new JButton("Close");
closeButton.addActionListener(e1 -> {
dialog.setVisible(false);
dialog.dispose();
});
JPanel closePanel = new JPanel();
closePanel.setLayout(new BoxLayout(closePanel, BoxLayout.LINE_AXIS));
closePanel.add(Box.createHorizontalGlue());
closePanel.add(closeButton);
closePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 5));
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(label, BorderLayout.CENTER);
contentPane.add(closePanel, BorderLayout.PAGE_END);
contentPane.setOpaque(true);
dialog.setContentPane(contentPane);
//Show it.
dialog.setSize(new Dimension(300, 150));
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
});
return createPane(moreDialogDesc + ":", radioButtons, showItButton);
}
/*
* Creates the panel shown by the 3rd tab.
* These dialogs are implemented using showMessageDialog, but
* you can specify the icon (using similar code) for any other
* kind of dialog, as well.
*/
private JPanel createIconDialogBox() {
JButton showItButton = null;
final int numButtons = 6;
JRadioButton[] radioButtons = new JRadioButton[numButtons];
final ButtonGroup group = new ButtonGroup();
final String plainCommand = "plain";
final String infoCommand = "info";
final String questionCommand = "question";
final String errorCommand = "error";
final String warningCommand = "warning";
final String customCommand = "custom";
radioButtons[0] = new JRadioButton("Plain (no icon)");
radioButtons[0].setActionCommand(plainCommand);
radioButtons[1] = new JRadioButton("Information icon");
radioButtons[1].setActionCommand(infoCommand);
radioButtons[2] = new JRadioButton("Question icon");
radioButtons[2].setActionCommand(questionCommand);
radioButtons[3] = new JRadioButton("Error icon");
radioButtons[3].setActionCommand(errorCommand);
radioButtons[4] = new JRadioButton("Warning icon");
radioButtons[4].setActionCommand(warningCommand);
radioButtons[5] = new JRadioButton("Custom icon");
radioButtons[5].setActionCommand(customCommand);
for (int i = 0; i < numButtons; i++) {
group.add(radioButtons[i]);
}
radioButtons[0].setSelected(true);
showItButton = new JButton("Show it!");
showItButton.addActionListener(e -> {
String command = group.getSelection().getActionCommand();
//no icon
if (Objects.equals(command, plainCommand)) {
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.",
"A plain message",
JOptionPane.PLAIN_MESSAGE);
//information icon
} else if (Objects.equals(command, infoCommand)) {
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.",
"Inane informational dialog",
JOptionPane.INFORMATION_MESSAGE);
//XXX: It doesn't make sense to make a question with
//XXX: only one button.
//XXX: See "Yes/No (but not in those words)" for a better solution.
//question icon
} else if (Objects.equals(command, questionCommand)) {
JOptionPane.showMessageDialog(frame,
"You shouldn't use a message dialog "
+ "(like this)\n"
+ "for a question, OK?",
"Inane question",
JOptionPane.QUESTION_MESSAGE);
//error icon
} else if (Objects.equals(command, errorCommand)) {
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.",
"Inane error",
JOptionPane.ERROR_MESSAGE);
//warning icon
} else if (Objects.equals(command, warningCommand)) {
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.",
"Inane warning",
JOptionPane.WARNING_MESSAGE);
//custom icon
} else if (Objects.equals(command, customCommand)) {
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.",
"Inane custom dialog",
JOptionPane.INFORMATION_MESSAGE,
icon);
}
});
return create2ColPane(iconDesc + ":",
radioButtons,
showItButton);
}
/**
* Sets the text displayed at the bottom of the frame.
*/
void setLabel(final String newText) {
label.setText(newText);
}
/**
* Used by createSimpleDialogBox and createFeatureDialogBox
* to create a pane containing a description, a single column
* of radio buttons, and the Show it! button.
*/
private JPanel createPane(final String description,
final JRadioButton[] radioButtons,
final JButton showButton) {
JPanel box = new JPanel();
JLabel label = new JLabel(description);
box.setLayout(new BoxLayout(box, BoxLayout.PAGE_AXIS));
box.add(label);
for (JRadioButton radioButton : radioButtons) {
box.add(radioButton);
}
JPanel pane = new JPanel(new BorderLayout());
pane.add(box, BorderLayout.PAGE_START);
pane.add(showButton, BorderLayout.PAGE_END);
return pane;
}
/**
* Like createPane, but creates a pane with 2 columns of radio
* buttons. The number of buttons passed in *must* be even.
*/
private JPanel create2ColPane(final String description,
final JRadioButton[] radioButtons,
final JButton showButton) {
JLabel label = new JLabel(description);
int numPerColumn = radioButtons.length / 2;
JPanel grid = new JPanel(new GridLayout(0, 2));
for (int i = 0; i < numPerColumn; i++) {
grid.add(radioButtons[i]);
grid.add(radioButtons[i + numPerColumn]);
}
JPanel box = new JPanel();
box.setLayout(new BoxLayout(box, BoxLayout.PAGE_AXIS));
box.add(label);
grid.setAlignmentX(0.0f);
box.add(grid);
JPanel pane = new JPanel(new BorderLayout());
pane.add(box, BorderLayout.PAGE_START);
pane.add(showButton, BorderLayout.PAGE_END);
return pane;
}
/**
* Returns an ImageIcon, or null if the path was invalid.
*/
private static ImageIcon createImageIcon(final String path) {
java.net.URL imgURL = DialogDemo.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void main(final String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
LafManager.install();
javax.swing.SwingUtilities.invokeLater(DialogDemo::createAndShowGUI);
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("DialogDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
DialogDemo newContentPane = new DialogDemo(frame);
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

BIN
src/test/java/dialog/images/green.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/test/java/dialog/images/middle.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

203
src/test/java/formattedTextField/FormattedTextFieldDemo.java

@ -0,0 +1,203 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package formattedTextField;
import com.weis.darklaf.LafManager;
import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
/**
* FormattedTextFieldDemo.java requires no other files.
* <p>
* It implements a mortgage calculator that uses four
* JFormattedTextFields.
*/
public class FormattedTextFieldDemo extends JPanel
implements PropertyChangeListener {
//Strings for the labels
private static String amountString = "Loan Amount: ";
private static String rateString = "APR (%): ";
private static String numPeriodsString = "Years: ";
private static String paymentString = "Monthly Payment: ";
//Values for the fields
private double amount = 100000;
private double rate = 7.5; //7.5%
private int numPeriods = 30;
//Labels to identify the fields
private JLabel amountLabel;
private JLabel rateLabel;
private JLabel numPeriodsLabel;
private JLabel paymentLabel;
//Fields for data entry
private JFormattedTextField amountField;
private JFormattedTextField rateField;
private JFormattedTextField numPeriodsField;
private JFormattedTextField paymentField;
//Formats to format and parse numbers
private NumberFormat amountFormat;
private NumberFormat percentFormat;
private NumberFormat paymentFormat;
public FormattedTextFieldDemo() {
super(new BorderLayout());
setUpFormats();
double payment = computePayment(amount,
rate,
numPeriods);
//Create the labels.
amountLabel = new JLabel(amountString);
rateLabel = new JLabel(rateString);
numPeriodsLabel = new JLabel(numPeriodsString);
paymentLabel = new JLabel(paymentString);
//Create the text fields and set them up.
amountField = new JFormattedTextField(amountFormat);
amountField.setValue(new Double(amount));
amountField.setColumns(10);
amountField.addPropertyChangeListener("value", this);
rateField = new JFormattedTextField(percentFormat);
rateField.setValue(new Double(rate));
rateField.setColumns(10);
rateField.addPropertyChangeListener("value", this);
numPeriodsField = new JFormattedTextField();
numPeriodsField.setValue(new Integer(numPeriods));
numPeriodsField.setColumns(10);
numPeriodsField.addPropertyChangeListener("value", this);
paymentField = new JFormattedTextField(paymentFormat);
paymentField.setValue(new Double(payment));
paymentField.setColumns(10);
paymentField.setEditable(false);
paymentField.setForeground(Color.red);
//Tell accessibility tools about label/textfield pairs.
amountLabel.setLabelFor(amountField);
rateLabel.setLabelFor(rateField);
numPeriodsLabel.setLabelFor(numPeriodsField);
paymentLabel.setLabelFor(paymentField);
//Lay out the labels in a panel.
JPanel labelPane = new JPanel(new GridLayout(0, 1));
labelPane.add(amountLabel);
labelPane.add(rateLabel);
labelPane.add(numPeriodsLabel);
labelPane.add(paymentLabel);
//Layout the text fields in a panel.
JPanel fieldPane = new JPanel(new GridLayout(0, 1));
fieldPane.add(amountField);
fieldPane.add(rateField);
fieldPane.add(numPeriodsField);
fieldPane.add(paymentField);
//Put the panels in this panel, labels on left,
//text fields on right.
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
add(labelPane, BorderLayout.CENTER);
add(fieldPane, BorderLayout.LINE_END);
}
//Create and set up number formats. These objects also
//parse numbers input by user.
private void setUpFormats() {
amountFormat = NumberFormat.getNumberInstance();
percentFormat = NumberFormat.getNumberInstance();
percentFormat.setMinimumFractionDigits(3);
paymentFormat = NumberFormat.getCurrencyInstance();
}
//Compute the monthly payment based on the loan amount,
//APR, and length of loan.
private double computePayment(final double loanAmt, final double rate, int numPeriods) {
double I, partial1, denominator, answer;
numPeriods *= 12; //get number of months
if (rate > 0.01) {
I = rate / 100.0 / 12.0; //get monthly rate from annual
partial1 = Math.pow((1 + I), (0.0 - numPeriods));
denominator = (1 - partial1) / I;
} else { //rate ~= 0
denominator = numPeriods;
}
answer = (-1 * loanAmt) / denominator;
return answer;
}
public static void main(final String[] args) {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(() -> {
//Turn off metal's use of bold fonts
LafManager.install();
createAndShowGUI();
});
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("FormattedTextFieldDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add contents to the window.
frame.add(new FormattedTextFieldDemo());
//Display the window.
frame.pack();
frame.setVisible(true);
}
/**
* Called when a field's "value" property changes.
*/
public void propertyChange(final PropertyChangeEvent e) {
Object source = e.getSource();
if (source == amountField) {
amount = ((Number) amountField.getValue()).doubleValue();
} else if (source == rateField) {
rate = ((Number) rateField.getValue()).doubleValue();
} else if (source == numPeriodsField) {
numPeriods = ((Number) numPeriodsField.getValue()).intValue();
}
double payment = computePayment(amount, rate, numPeriods);
paymentField.setValue(new Double(payment));
}
}

BIN
src/test/java/formattedTextField/images/left.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

BIN
src/test/java/formattedTextField/images/red.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/test/java/formattedTextField/images/right.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Loading…
Cancel
Save