How to use the Java Preferences Class with JRadioButton - java

I'm building a small program that's got a settings screen where the user can choose a color theme. I used a JRadioButton for every color but I can't get the program to save it for the next time I run the program. Here's my code:
private Preferences userPreferences = Preferences.userRoot();
MainWindow() {
super("Timer");
setLayout(new GridLayout(4,3,5,5));
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(650,290);
setResizable(false);
userPreferences.get("COLOR_CODE", "#ededed");
//MORE CODE HERE
#Override
public void menuSelected(MenuEvent e) {
//Open settings window
if(e.getSource().equals(settings)) {
about.setEnabled(false);
exit.setEnabled(false);
settingsFrame = new SettingsWindow();
settingsFrame.setAlwaysOnTop(true);
settingsFrame.setLocationRelativeTo(null);
settingsFrame.setVisible(true);
//WindowListener for closing the settings window
settingsFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent we) {
settings.setEnabled(true);
about.setEnabled(true);
exit.setEnabled(true);
}
});
//Adding action listeners to the radio buttons
settingsFrame.defaultColorRB.addActionListener(ee -> {
settingsFrame.setColor("#ededed");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
settingsFrame.whiteColorRB.addActionListener(ee -> {
settingsFrame.setColor("#FFFFFF");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
settingsFrame.lightGrayColorRB.addActionListener(ee -> {
settingsFrame.setColor("#D2D8DF");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
settingsFrame.darkGrayColorRB.addActionListener(ee -> {
settingsFrame.setColor("#A2A4A6");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
settingsFrame.yellowColorRB.addActionListener(ee -> {
settingsFrame.setColor("#FBFF00");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
settingsFrame.pinkColorRB.addActionListener(ee -> {
settingsFrame.setColor("#F58EB3");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
settingsFrame.cyanColorRB.addActionListener(ee -> {
settingsFrame.setColor("#32D0F7");
getContentPane().setBackground(Color.decode(settingsFrame.getColorCode()));
userPreferences.put("COLOR_CODE", settingsFrame.getColorCode());
});
}
}
Please can anyone let me know why the code above doesn't save the user's choice of color?

If saving the color code, as posted in the question, you will need to test the saved color code and select the respective button. Example, very basic, just for demonstration:
// assuming userPreferences is java.util.prefs.Preferences
String colorCode = userPreferences.get("COLOR_CODE", "#ededed");
switch (colorCode.toLowerCase()) {
case "#ededed": defaultColorRB.setSelected(true); break;
case "#ffffff": whiteColorRB.setSelected(true); break;
...
default: /* none selected - not sure what you want to do in that case */ break;
}
Hint 1: use constants for the preferences key "COLOR_CODE" and the colors (e.g. "ededed")
Hint 2: since you are using radio buttons, that is, some distinct colors, it would be easier save the selected radio button index (or some constant) instead of the color code itself (e.g. #ededed). If the user is allowed to select ANY color, not only the radio buttons ones, you sure must save the color code.
Here an example for the second hint:
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.prefs.Preferences;
import javax.swing.ButtonGroup;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
public class Radio {
private static final String PREF_BUTTON_INDEX = "color button";
private final Preferences prefs = Preferences.userNodeForPackage(getClass());
private static final String[] COLORS = { "#ededed", "#ffffff", "#a00000" };
private List<JRadioButton> buttons;
private JLabel output; // so we can see something, simulating usage of color
private Radio() {
buttons = new ArrayList<>();
SwingUtilities.invokeLater(this::initGUI);
}
private void initGUI() {
JPanel panel = new JPanel();
ButtonGroup group = new ButtonGroup();
for (int i = 0; i < COLORS.length; i++) {
JRadioButton button = new JRadioButton(COLORS[i]);
button.addActionListener(this::buttonSelected);
group.add(button);
panel.add(button);
buttons.add(button);
}
output = new JLabel("undefined");
output.setBorder(new TitledBorder("Color:"));
panel.add(output);
int colorIndex = prefs.getInt(PREF_BUTTON_INDEX, -1);
if (colorIndex != -1) {
buttons.get(colorIndex).setSelected(true);
output.setText(COLORS[colorIndex]);
}
JOptionPane.showMessageDialog(null, panel);
}
private void buttonSelected(ActionEvent ev) {
int index = buttons.indexOf(ev.getSource());
if (index != -1) {
output.setText(COLORS[index]);
prefs.putInt(PREF_BUTTON_INDEX, index);
}
}
public static void main(String[] args) {
new Radio();
}
}

One good usage first is to create a node and not to save the preferences directly in the user root node.
Try this:
// This will define a node in which the preferences can be stored
prefs = Preferences.userRoot().node(this.getClass().getName());
And see if this changing something.

Related

TextField is not following the conditions

here's a quick explanation, I make my TextField into false condition inside of .setEnabled area. So basically after the user press check on Cake's check-box, he need to choose either one of the sub-item menu, after he do that, he needs to enter the quantity of the cake. But, after choosing the sub-item menu, the TextField condition should be true(means it should be editable), but it doesn't go as were told. Thank you.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;
class testingcheckbox
{
public static void main(String[] args)
{
Frame qB = new Frame("Queen Bakery");
JCheckBox cake;
cake = new JCheckBox("Cake");
JCheckBox cakeOpt1 = new JCheckBox("Butter Cake");
JCheckBox cakeOpt2 = new JCheckBox("Cheese Cake");
TextField tfCake = new TextField();
tfCake.setPreferredSize(new Dimension(50,24));
tfCake.setEnabled(false);
ActionListener cakeListener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(cake.isSelected())
{
cakeOpt1.setEnabled(true);
cakeOpt2.setEnabled(true);
if(cakeOpt1.isSelected())
{
tfCake.setEnabled(true);
}
else
{
tfCake.setEnabled(false);
}
}
else
{
cakeOpt1.setEnabled(false);
cakeOpt2.setEnabled(false);
}
}
};
cake.addActionListener(cakeListener);
qB.add(cake);
cakeOpt1.setEnabled(false);
cakeOpt2.setEnabled(false);
qB.add(cakeOpt1);
qB.add(cakeOpt2);
qB.add(tfCake);
qB.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent windowEvent)
{
System.exit(0);
}
});
qB.setSize(780,470);
qB.setLayout(new FlowLayout(FlowLayout.LEFT));
qB.setVisible(true);
qB.setLocationRelativeTo(null);
qB.setResizable(false);
}
}
cake.addActionListener(cakeListener);
You only add the ActionListener to one check box so no code is execute when you click on the "optonal" check boxes.
You also need to add your ActionListener to your other check boxes:
cakeOpt1.addActionListener(cakeListener);
cakeOpt2.addActionListener(cakeListener);

How to use JavaFX KeyListeners?

I have an editable JavaFX ComboBox.
A user must only be able to
type alphabets ('a' to 'z'), space and round braces ('(', ')') to enter the string
press tab to exit
press enter to exit
How to filter out every other key, modifiers etc?
I have read about and used event handlers like Key_Pressed, Key_Released but I am unable to figure out a straight-forward way to achieve the above.
I am using Mac OS Yosemite, Java 8, latest version of JavaFX and
public static final EventType<KeyEvent> KEY_TYPED just does not work at all.
Below code is my attempt. The variable typedText stores the desired values.
comboBox.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
private final String[] allowedItems = new String[]{"a","b","c","d","e","f",
"g","h","i","j","k","l","m","n","o","p","q","r",
"s","t","u","v","w","x","y","z"," ","(",")"};
private final List data = Arrays.asList(allowedItems);
private String tempInput;
public boolean containsCaseInsensitive(String s, List<String> l){
for (String string : l) {
if (string.equalsIgnoreCase(s)){
return true;
}
}
return false;
}
public void handle(KeyEvent event) {
boolean b;
b = event.isShiftDown();
if (b) {
if (event.getText().equals("(")) {
tempInput = "(";
} else if (event.getText().equals(")")){
tempInput = ")";
}
} else {
tempInput = event.getCode().toString().toLowerCase();
}
System.out.println("tempInput:"+tempInput);
if (containsCaseInsensitive(tempInput, data)) {
typedText = tempInput;
System.out.println("typedText:"+typedText);
}
}
});
}
You can get the Editor, which is a TextField in your case, and add a TextFormatter to it which restricts the input.
Tab works out of the box, but the "enter" keypress is a different matter, I simply request the focus in this example. Usually you'd navigate to the next item in the focus traversal list, but there's no future-proof api for that yet in JavaFX.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class ComboBoxSample extends Application {
#Override
public void start(Stage stage) {
ComboBox<String> comboBox = new ComboBox<>();
comboBox.setEditable(true);
comboBox.getItems().addAll("A", "B", "C", "D", "E");
comboBox.setValue("A");
// restrict input
TextField textField = comboBox.getEditor();
TextFormatter<String> formatter = new TextFormatter<String>(change -> {
change.setText(change.getText().replaceAll("[^a-z ()]", ""));
return change;
});
textField.setTextFormatter(formatter);
// dummy textfield to jump to on ENTER press
TextField dummyTextField = new TextField();
comboBox.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
if( e.getCode() == KeyCode.ENTER) {
dummyTextField.requestFocus();
e.consume();
}
});
HBox root = new HBox();
root.getChildren().addAll(comboBox, dummyTextField);
Scene scene = new Scene(root, 450, 250);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Auto-Completing JTextField and Arrow Keys

I'm trying to build a javax.swing.JTextField with javax.swing.JList for auto-completing like Google.
When a write a word, Google show several matches and
when a press the ▼ I can select some match using ▲ and ▼ and
can edit my input with ◀ and ▶ .
When I press Enter key search the content in the box.
When a press Esc the box change to the original input.
My aplication is about the Bible and I want to looking for a particular word when I'm studying the Word. I have seen the Java2sAutoTextField but don't have this particular behavior with the arrow keys.
This needs a custom coded component. Definitely a class that extends JTextField and in that class you have a JPopupMenu that will contain your JList. You will have to position the JPopupMenu right under the text field so that it looks like 1 component.
Your next trick is to filter as you type. I usually do this using Java6 TableRowSorter coupled with a JTable to which I pre-fill it with data. You're gonna need some change listeners on the JTextField and intercept each key typed and fetch your data.
Key pressed
Perform query in DB (or some data storage to get similar entries)
Populate JTable with those entires
Set RowFilter with regex based on JTextField entry to filter through retrieved data
Manage your actions with key listeners
EDIT
I whipped up a sample swing app to show what I stated. This is a copy/paste example and should work right off the bat (need JDK 1.6+). I basically got what you wanted and I put comments in places where I tell you to fill in the blanks.. like for example the Escape key event is consumed and you can do whatever you want with it.
The method initTableModel() just initializes the table model with data. Normally you would want to dynamically populate the table model with data from a database or something. A lot could be tweaked, but this is for example sake ;) So this should be a good enough example for you to modify to your complete your goal. Any more than this and you have to pay me $$$ :)
package test.text.googleclone;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
public class SearchAutoFillTest {
private JFrame frame = null;
private JTextField searchField = null;
private JPopupMenu popup = null;
private JTable searchTable = null;
private TableRowSorter<DefaultTableModel> rowSorter = null;
private DefaultTableModel searchTableModel = null;
public SearchAutoFillTest() {
searchTableModel = new DefaultTableModel();
initTableModel();
rowSorter = new TableRowSorter<DefaultTableModel>(searchTableModel);
searchTable = new JTable(searchTableModel);
searchTable.setRowSorter(rowSorter);
searchTable.setFillsViewportHeight(true);
searchTable.getColumnModel().setColumnSelectionAllowed(false);
searchTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
searchTable.getTableHeader().setReorderingAllowed(false);
searchTable.setPreferredSize(new Dimension(775, 100));
searchTable.setGridColor(Color.WHITE);
searchField = new JTextField();
searchField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
showPopup(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
showPopup(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
showPopup(e);
}
});
searchField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
switch(code)
{
case KeyEvent.VK_UP:
{
cycleTableSelectionUp();
break;
}
case KeyEvent.VK_DOWN:
{
cycleTableSelectionDown();
break;
}
case KeyEvent.VK_LEFT:
{
//Do whatever you want here
break;
}
case KeyEvent.VK_RIGHT:
{
//Do whatever you want here
break;
}
}
}
#Override
public void keyPressed(KeyEvent e) {
}
});
KeyStroke keyStroke = KeyStroke.getKeyStroke("ESCAPE");
searchField.getInputMap().put(keyStroke, "ESCAPE");
searchField.getActionMap().put("ESCAPE", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//Do what you wish here with the escape key.
}
});
popup = new JPopupMenu();
popup.add(searchTable);
popup.setVisible(false);
popup.setBorder(BorderFactory.createEmptyBorder());
JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
searchPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
searchPanel.add(searchField, BorderLayout.CENTER);
frame = new JFrame();
frame.setLayout(new BorderLayout(5, 5));
frame.add(searchPanel, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 500);
center(frame);
frame.setVisible(true);
}
private final void newFilter() {
RowFilter<DefaultTableModel, Object> rf = null;
try {
rf = RowFilter.regexFilter(getFilterText(), 0);
}
catch(PatternSyntaxException e) {
return;
}
rowSorter.setRowFilter(rf);
}
private final String getFilterText() {
String orig = searchField.getText();
return "("+orig.toLowerCase()+")|("+orig.toUpperCase()+")";
}
private void showPopup(DocumentEvent e) {
if(e.getDocument().getLength() > 0) {
if(!popup.isVisible()) {
Rectangle r = searchField.getBounds();
popup.show(searchField, (r.x-4), (r.y+16));
popup.setVisible(true);
}
newFilter();
searchField.grabFocus();
}
else {
popup.setVisible(false);
}
}
private void cycleTableSelectionUp() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 > 0) {
selModel.setSelectionInterval(index0-1, index0-1);
}
}
private void cycleTableSelectionDown() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 == -1) {
selModel.setSelectionInterval(0, 0);
}
else if(index0 > -1) {
selModel.setSelectionInterval(index0+1, index0+1);
}
}
private void initTableModel() {
String[] columns = new String[] {"A"};
String[][] data = new String[][]
{
new String[] {"a"},
new String[] {"aa"},
new String[] {"aaab"},
new String[] {"aaabb"},
new String[] {"aaabbbz"},
new String[] {"b"},
new String[] {"bb"},
new String[] {"bbb"},
new String[] {"bbbbbbb"},
new String[] {"bbbbbbbeee"},
new String[] {"bbbbbbbeeexxx"},
new String[] {"ccc"},
new String[] {"cccc"},
new String[] {"ccccc"},
new String[] {"cccccaaaa"},
new String[] {"ccccccaaaa"},
};
searchTableModel.setDataVector(data, columns);
}
private void center(Window w) {
int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
int windowWidth = w.getWidth();
int windowHeight = w.getHeight();
if (windowHeight > screenHeight) {
return;
}
if (windowWidth > screenWidth) {
return;
}
int x = (screenWidth - windowWidth) / 2;
int y = (screenHeight - windowHeight) / 2;
w.setLocation(x, y);
}
public static void main(String ... args) {
new SearchAutoFillTest();
}
}
This component is called autocomplete and is included in a so called swing extensions porject.
Just have a look at: http://swingx.java.net/
There is a webstart with demos: http://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp
use AutoComplete JTextField placed into JToolBar / MenuBar, notice you must to sort ArrayList before usage,
use undecoratted JDialog instead of JPopup (still have got a few important bugs),
a) create only one JDialog with parent to the JTextField or JMenuBar or JFrame,
b) always to search for getBounds from AutoComplete JTextField before visible JDialog on the screen, this Bounds are for possitioning JDialog correctly on the screen
c) wrap JDialog#setVisible(true) to the invokeLater()
override Escape for JDialog.setVisible(false)
put there close / hide JButton to avoiding overrive rest of important methods on focusLost (this calendar have got excelent workaround on focusLost, mouseClick, etc ...., could it be very easy to replace calendar funcionality with result from Comparator, you have to download codesource)
you can put there (my view) 6 / 9 / max 12 buttons, you can remove JButton Feels by setBackground(Color.white) for example, you cann't, please don't do it something with JDialog and these JButtons, you job will be only to setText("result from Comparator")
in the case that your ArrayList for AutoComplete JTextField was sorted, then you have two choises
a) easiest override bias from AutoComplete funcionality by add fils separate array for setText() for 6 / 9 / max 12 buttons on popup JDialog, if you setBackground(Color.white), then you don't care somehow about to hide JButtons without text
b) another way could be to create own Comparator for searching (the same AutoComplete funcionality) first 6 / 9 / max 12 matches,
for capturing an events from 6 / 9 / max 12 JButtons use putClientProperty or EventHandler or Swing Actions, where you only to test if text isEmpty :-),
maybe Swing Actions could be the best of ways because its events are scallable and you can enabled/disable (if JButtons text isEmpty) output from this Action by default
It sounds like you want a JComboBox (see Swing guide) rather than a JTextField/JList.
Of course, then you have a drop-down button, but there are possible ways to deal with this - see here.
It would be something along these lines:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.*;
public class Component extends JComponent {
private final static String[] terms = {"Jesus",
"Jesus walks on water" //...
};
private static ArrayList<String> recent = new ArrayList<String>();
JTextField jtf;
JList jl;
public Component(){
// set up design
jtf = new JTextField();
jtf.setSize(this.getWidth() - 25, 25);
this.add(jtf);
//...
// add key listeners
}
class Listener implements KeyListener{
#Override
public void keyPressed(KeyEvent arg0) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
if (arg0.getKeyCode() == KeyEvent.VK_DOWN){
// set next item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_UP){
// set previous item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
// search
}
else if (arg0.getKeyCode() == KeyEvent.VK_ESCAPE){
jtf.setText("");
}
else{
// check list for matches
}
}
}
}
The default behavior is that all key events go to the component which has the focus. So what you need to do is identify keys which should really go to the other component and install a KeyListener to both.
In that listener, you can forward the events to the other component.
See this answer how to dispatch an event to a new component. In your case, source must be the other component (the list, if your text field originally received the event and vice versa).

How do you hide a Swing Popup when you click somewhere else

I have a Popup that is shown when a user clicks on a button. I would like to hide the popup when any of the following events occur:
The user clicks somewhere else in the application. (The background panel for example)
The user minimizes the application.
The JPopupMenu has this behavior, but I need more than just JMenuItems. The following code block is a simplified illustration to demonstrate the current usage.
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class PopupTester extends JFrame {
public static void main(String[] args) {
final PopupTester popupTester = new PopupTester();
popupTester.setLayout(new FlowLayout());
popupTester.setSize(300, 100);
popupTester.add(new JButton("Click Me") {
#Override
protected void fireActionPerformed(ActionEvent event) {
Point location = getLocationOnScreen();
int y = (int) (location.getY() + getHeight());
int x = (int) location.getX();
JLabel myComponent = new JLabel("Howdy");
Popup popup = PopupFactory.getSharedInstance().getPopup(popupTester, myComponent, x, y);
popup.show();
}
});
popupTester.add(new JButton("No Click Me"));
popupTester.setVisible(true);
popupTester.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Use a JPopupMenu. You can add any component to it, not just menu items.
As pajton noted in a previous comment, Popup is not a JComponent to which listeners can be readily bound. But, as its documentation states, "implementations of Popup are responsible for creating and maintaining their own Components to render [its subject] to the user."
So in using it as your presentation mechanism, your Popup is going to have to present itself as an actual Swing component anyway. Have it register itself to that component. Have it hide itself when the component loses focus.
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.Popup;
public class PopupTester extends JFrame {
private static class MessagePopup extends Popup
implements WindowFocusListener
{
private final JDialog dialog;
public MessagePopup(Frame base, String message) {
super();
dialog = new JOptionPane().createDialog( base, "Message" );
dialog.setModal( false );
dialog.setContentPane( new JLabel( message ) );
}
#Override public void show() {
dialog.addWindowFocusListener( this );
dialog.setVisible( true );
}
#Override public void hide() {
dialog.setVisible( false );
dialog.removeWindowFocusListener( this );
}
public void windowGainedFocus( WindowEvent e ) {
// NO-OP
}
public void windowLostFocus( WindowEvent e ) {
hide();
}
}
public static void main(String[] args) {
final PopupTester popupTester = new PopupTester();
popupTester.setLayout(new FlowLayout());
popupTester.setSize(300, 100);
popupTester.add(new JButton("Click Me") {
#Override
protected void fireActionPerformed(ActionEvent event) {
Point location = getLocationOnScreen();
MessagePopup popup = new MessagePopup( popupTester, "Howdy" );
popup.show();
}
});
popupTester.add(new JButton("No Click Me"));
popupTester.setVisible(true);
popupTester.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
You can add MouseListener to your background panel and hide the popup when somebody clicks on the panel.
To react on application minimization, use WindowListener attached to a JFrame.
Etc, etc. May seem tedious, but surely will work.
Thanks pajton and Noel Ang for getting me pointed in the right direction! Here is the solution that I ended up with. I'm just including it here so that others may benefit from it.
I ended up going with a JWindow since it doesn't get the window decorations but does get focus events.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PopupTester extends JFrame {
private static class MessagePopup extends Popup implements WindowFocusListener {
private final JWindow dialog;
public MessagePopup(Frame base, JLabel component, int x, int y) {
super();
dialog = new JWindow(base);
dialog.setFocusable(true);
dialog.setLocation(x, y);
dialog.setContentPane(component);
component.setBorder(new JPopupMenu().getBorder());
dialog.setSize(component.getPreferredSize());
dialog.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dialog.setVisible(false);
}
}
});
}
#Override
public void show() {
dialog.addWindowFocusListener(this);
dialog.setVisible(true);
}
#Override
public void hide() {
dialog.setVisible(false);
dialog.removeWindowFocusListener(this);
}
public void windowGainedFocus(WindowEvent e) {
// NO-OP
}
public void windowLostFocus(WindowEvent e) {
hide();
}
}
public static void main(String[] args) {
final PopupTester popupTester = new PopupTester();
popupTester.setLayout(new FlowLayout());
popupTester.setSize(300, 100);
popupTester.add(new JButton("Click Me") {
#Override
protected void fireActionPerformed(ActionEvent event) {
Point location = getLocationOnScreen();
int x = (int) location.getX();
int y = (int) (location.getY() + getHeight());
JLabel myComponent = new JLabel("Howdy");
MessagePopup popup = new MessagePopup(popupTester, myComponent, x, y);
popup.show();
}
});
popupTester.add(new JButton("No Click Me"));
popupTester.setVisible(true);
popupTester.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
You could add a FocusListener to your popup-window, and dispose it when it loses focus. However, that will cause you some troubles when the focus loss is due to some other application (new windows comes to the foreground, you switch virtual desktops, etc.)
But perhaps you (a) know that that cannot happen in your case or (b) would want to close the popup in such cases anyway, a focus-based approach may still be interesting to you.
I know this is an old question but I really needed the Popup to work in my case. So I tried a few things and the following is my solution.
Add a FocusListener to the component you add to the popup and program the focusLost event on that component to hide the popup when focus is lost. Call the requestFocus method on your component just after showing the popup.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.*;
public class PopupTester extends JFrame {
JButton myButton = new JButton("Click Me");
JLabel myComponent = new JLabel("Howdy");
Popup popup = null;
public PopupTester() {
setLayout(new FlowLayout());
setSize(300, 100);
add(myButton);
add(new JButton("No Click Me"));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myComponent.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent e) {
if (popup != null) {
popup.hide();
}
}
});
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if (popup != null) {
popup.hide();
popup = null;
}
Point location = myButton.getLocationOnScreen();
int y = (int) (location.getY() + myButton.getHeight());
int x = (int) location.getX();
popup = PopupFactory.getSharedInstance().getPopup(PopupTester.this, myComponent, x, y);
popup.show();
myComponent.requestFocus();
}
});
}
public static void main(String[] args) {
PopupTester popupTester = new PopupTester();
popupTester.setVisible(true);
}
}

How do I get which JRadioButton is selected from a ButtonGroup

I have a swing application that includes radio buttons on a form. I have the ButtonGroup, however, looking at the available methods, I can't seem to get the name of the selected JRadioButton. Here's what I can tell so far:
From ButtonGroup, I can perform a getSelection() to return the ButtonModel. From there, I can perform a getActionCommand, but that doesn't seem to always work. I tried different tests and got unpredictable results.
Also from ButtonGroup, I can get an Enumeration from getElements(). However, then I would have to loop through each button just to check and see if it is the one selected.
Is there an easier way to find out which button has been selected? I'm programing this in Java 1.3.1 and Swing.
I got similar problem and solved with this:
import java.util.Enumeration;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
public class GroupButtonUtils {
public String getSelectedButtonText(ButtonGroup buttonGroup) {
for (Enumeration<AbstractButton> buttons = buttonGroup.getElements(); buttons.hasMoreElements();) {
AbstractButton button = buttons.nextElement();
if (button.isSelected()) {
return button.getText();
}
}
return null;
}
}
It returns the text of the selected button.
I would just loop through your JRadioButtons and call isSelected(). If you really want to go from the ButtonGroup you can only get to the models. You could match the models to the buttons, but then if you have access to the buttons, why not use them directly?
You must add setActionCommand to the JRadioButton then just do:
String entree = entreeGroup.getSelection().getActionCommand();
Example:
java = new JRadioButton("Java");
java.setActionCommand("Java");
c = new JRadioButton("C/C++");
c.setActionCommand("c");
System.out.println("Selected Radio Button: " +
buttonGroup.getSelection().getActionCommand());
I suggest going straight for the model approach in Swing. After you've put the component in the panel and layout manager, don't even bother keeping a specific reference to it.
If you really want the widget, then you can test each with isSelected, or maintain a Map<ButtonModel,JRadioButton>.
You can put and actionCommand to each radio button (string).
this.jButton1.setActionCommand("dog");
this.jButton2.setActionCommand("cat");
this.jButton3.setActionCommand("bird");
Assuming they're already in a ButtonGroup (state_group in this case) you can get the selected radio button like this:
String selection = this.state_group.getSelection().getActionCommand();
Hope this helps
The following code displays which JRadiobutton is selected from Buttongroup on click of a button.
It is done by looping through all JRadioButtons in a particular buttonGroup.
JRadioButton firstRadioButton=new JRadioButton("Female",true);
JRadioButton secondRadioButton=new JRadioButton("Male");
//Create a radio button group using ButtonGroup
ButtonGroup btngroup=new ButtonGroup();
btngroup.add(firstRadioButton);
btngroup.add(secondRadioButton);
//Create a button with text ( What i select )
JButton button=new JButton("What i select");
//Add action listener to created button
button.addActionListener(this);
//Get selected JRadioButton from ButtonGroup
public void actionPerformed(ActionEvent event)
{
if(event.getSource()==button)
{
Enumeration<AbstractButton> allRadioButton=btngroup.getElements();
while(allRadioButton.hasMoreElements())
{
JRadioButton temp=(JRadioButton)allRadioButton.nextElement();
if(temp.isSelected())
{
JOptionPane.showMessageDialog(null,"You select : "+temp.getText());
}
}
}
}
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JRadioButton;
import javax.swing.JToggleButton;
public class RadioButton extends JRadioButton {
public class RadioButtonModel extends JToggleButton.ToggleButtonModel {
public Object[] getSelectedObjects() {
if ( isSelected() ) {
return new Object[] { RadioButton.this };
} else {
return new Object[0];
}
}
public RadioButton getButton() { return RadioButton.this; }
}
public RadioButton() { super(); setModel(new RadioButtonModel()); }
public RadioButton(Action action) { super(action); setModel(new RadioButtonModel()); }
public RadioButton(Icon icon) { super(icon); setModel(new RadioButtonModel()); }
public RadioButton(String text) { super(text); setModel(new RadioButtonModel()); }
public RadioButton(Icon icon, boolean selected) { super(icon, selected); setModel(new RadioButtonModel()); }
public RadioButton(String text, boolean selected) { super(text, selected); setModel(new RadioButtonModel()); }
public RadioButton(String text, Icon icon) { super(text, icon); setModel(new RadioButtonModel()); }
public RadioButton(String text, Icon icon, boolean selected) { super(text, icon, selected); setModel(new RadioButtonModel()); }
public static void main(String[] args) {
RadioButton b1 = new RadioButton("A");
RadioButton b2 = new RadioButton("B");
ButtonGroup group = new ButtonGroup();
group.add(b1);
group.add(b2);
b2.setSelected(true);
RadioButtonModel model = (RadioButtonModel)group.getSelection();
System.out.println(model.getButton().getText());
}
}
Typically, some object associated with the selected radio button is required. It is not necessarily a String representing the button's label. It could be an Integer containing the button's index or an object of more complicated type T. You could fill and use a Map<ButtonModel, T> as Tom Hawtin suggested, but I propose to extend the model and place the objects there. Here's an improved ButtonGroup that uses this approach.
import javax.swing.*;
#SuppressWarnings("serial")
public class SmartButtonGroup<T> extends ButtonGroup {
#Override
public void add(AbstractButton b) {
throw new UnsupportedOperationException("No object supplied");
}
public void add(JRadioButton button, T attachedObject) {
ExtendedModel<T> model = new ExtendedModel<>(attachedObject);
model.setSelected(button.isSelected());
button.setModel(model);
super.add(button);
}
#SuppressWarnings("unchecked")
public T getSelectedObject() {
ButtonModel selModel = getSelection();
return selModel != null ? ((ExtendedModel<T>)selModel).obj : null;
}
public static class ExtendedModel<T> extends javax.swing.JToggleButton.ToggleButtonModel {
public T obj;
private ExtendedModel(T object) {
obj = object;
}
}
}
You can use this utility class instead of ButtonGroup. Create an object of this class and add buttons along with associated objects to it. For example,
SmartButtonGroup<Integer> group = new SmartButtonGroup<>();
JPanel panel = new JPanel();
for (int i = 1; i <= 5; i++) {
JRadioButton button = new JRadioButton("Button #" + i, i == 3); // select the 3rd button
group.add(button, i);
panel.add(button);
}
After this, you can get the object associated with the currently selected button anytime you need by simply calling getSelectedObject(), like this:
int selectedButtonIndex = group.getSelectedObject();
In case you need just the buttons themselves, you can use the next non-generic class instead.
import javax.swing.JRadioButton;
#SuppressWarnings("serial")
public class RadioButtonGroup extends SmartButtonGroup<JRadioButton> {
public void add(JRadioButton button) {
super.add(button, button);
}
#Override
public void add(JRadioButton button, JRadioButton attachedObject) {
throw new UnsupportedOperationException("Use the short form of addition instead");
}
public JRadioButton getSelectedButton() {
return getSelectedObject();
}
}
You could use getSelectedObjects() of ItemSelectable (superinterface of ButtonModel) which returns the list of selected items. In case of a radio button group it can only be one or none at all.
Add the radiobuttons to a button group then:
buttonGroup.getSelection().getActionCommand
Use the isSelected() method. It will tell you the state of your radioButton. Using it in combination with a loop(say for loop) you can find which one has been selected.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyJRadioButton extends JFrame implements ActionListener
{
JRadioButton rb1,rb2; //components
ButtonGroup bg;
MyJRadioButton()
{
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
rb1=new JRadioButton("male");
rb2=new JRadioButton("female");
//add radio button to button group
bg=new ButtonGroup();
bg.add(rb1);
bg.add(rb2);
//add radio buttons to frame,not button group
add(rb1);
add(rb2);
//add action listener to JRadioButton, not ButtonGroup
rb1.addActionListener(this);
rb2.addActionListener(this);
pack();
setVisible(true);
}
public static void main(String[] args)
{
new MyJRadioButton(); //calling constructor
}
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println(((JRadioButton) e.getSource()).getActionCommand());
}
}
Ale Rojas's answer works fine:
As alternative you can also use the My_JRadiobutton11.addActionListener(this); on your JButton and then make your actions in the actionPerformed function like this (It just uses an extra variable which you have to instantiate (e.g Private String selection;) but it's not a big deal):
public void actionPerformed(ActionEvent arg0) {
if(arg0.getSource() == My_JRadiobutton11){
//my selection
selection = "Become a dolphin";
}else if(arg0.getSource() == My_JRadiobutton12){
//my selection
selection = "Become a Unicorn";
} ..etc
}
jRadioOne = new javax.swing.JRadioButton();
jRadioTwo = new javax.swing.JRadioButton();
jRadioThree = new javax.swing.JRadioButton();
... then for every button:
buttonGroup1.add(jRadioOne);
jRadioOne.setText("One");
jRadioOne.setActionCommand(ONE);
jRadioOne.addActionListener(radioButtonActionListener);
...listener
ActionListener radioButtonActionListener = new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
radioButtonActionPerformed(evt);
}
};
...do whatever you need as response to event
protected void radioButtonActionPerformed(ActionEvent evt) {
System.out.println(evt.getActionCommand());
}

Categories