I try to make a custom jcombobox for my menu sidebar
my jcombobox has JButton as items because I found it easy to insert and align icon and text.
But my problem is when I choose a item in dropdown, the color of the header changes unexpectedly to the default color of component.
public class MyComboBoxRenderer extends JLabel implements ListCellRenderer<Object> {
private String _title;
private JButton header;
public MyComboBoxRenderer(String title) {
_title = title;
}
#Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean hasFocus) {
JButton item = new JButton();
item.setOpaque(true);
item.setBorderPainted(false);
item.setFocusPainted(false);
item.setBackground(isSelected ? Frame.LIGHTER_COLOR : Frame.LIGHT_COLOR );
ImageIcon dot = new ImageIcon("image/icon/orange_dot.png");
if (index == -1){
item.setText(_title);
header=item;
return item;
}
else{
item.setIcon(dot);
item.setIconTextGap(30);
item.setText(value.toString());
return item;
}
}
public JButton getHeader(){
return header;
}
}
public static class MyComboBoxUI extends BasicComboBoxUI {
final JButton button= new JButton(EXPAND_ARROW);
protected void installDefaults() {
super.installDefaults();
}
#Override
protected JButton createArrowButton() {
button.setContentAreaFilled(false);
button.setBorder(null);
return button;
}
#Override
public void configureArrowButton() {
super.configureArrowButton();
}
public JButton getArrowButton(){
return button;
}
}
public class ComboBox extends JComboBox{
public boolean isExpanded = false;
private MyComboBoxRenderer renderer;
public ComboBox(){
super();
this.setUI(new MyComboBoxUI());
}
public ComboBox(String[] list){
super(list);
renderer = new MyComboBoxRenderer("Lists Of Vocab");
this.setUI(new MyComboBoxUI());
this.setFont(Frame.I_FONT);
this.setForeground(Frame.FONT_COLOR);
this.setBackground(Frame.LIGHT_COLOR);
this.setRenderer(renderer);
MyComboBoxUI ui = (MyComboBoxUI) this.getUI();
JButton arrowButton = ui.getArrowButton();
arrowButton.addActionListener((ActionEvent e)->{
isExpanded = !isExpanded;
if(isExpanded == true){
arrowButton.setIcon(COLLAPSE_ARROW);
}
else{
arrowButton.setIcon(EXPAND_ARROW);
}
});
}
public MyComboBoxRenderer getRenderer(){
return renderer;
}
I add this combobox to the sideBar
private void addCheckBoxToSideBar(){
ComboBox lists = new ComboBox(listNames);
lists.setAlignmentX(Component.LEFT_ALIGNMENT); // have to have
lists.addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
CardLayout cl = (CardLayout)(mainPane.getLayout());
cl.show(mainPane, (String)e.getItem());[enter image description here][1]
}
}
});
sideBar.add(lists);
}
This is first:
https://i.stack.imgur.com/ctVnT.png
But when I click to choose an item, it changes to default color:
https://i.stack.imgur.com/KkhhO.png
Those are what I tried but they didn't work:
to set the background of the header in the itemStateChanged
get the JTextfield of BasicComboBoxEditor of it
I wonder whether updating UI causes this problem but I don't understand much about it.
In your MyComboBoxUI, try overriding this method :
#Override
public void paintCurrentValueBackground(Graphics g,Rectangle bounds,boolean hasFocus)
{
Color t = g.getColor();
g.setColor(your_color);
g.fillRect(bounds.x,bounds.y,bounds.width,bounds.height);
g.setColor(t);
}
i have a program with a frame that contains a main panel with the cardlayout layout, and i want it to display different cards/panel.
In my case i'm really struggling to call a new card from a button action listener.
I want a new card to appear after i click on a button but none of the codes i put in my action listener displayed the card i wanted.
I know my actionListener work because i did a println inside.
here's my code. i got rid of anything that was unnecessary so it's easier to read. Thanks for the help!
i'll take all advices about code structuration
the mainFrame :
public class MainFrame extends JFrame{
final static String CONNEXION_VIEW = "connexionView";
final static String CONNEXION_FAILED_VIEW = "connexionRefusee";
public MainFrame()
{
super();
initialize();
}
private void initialize()
{
getMainPanel();
add(getMainPanel());
}
CardLayout cardLayout;
public CardLayout getCardLayout()
{
if (cardLayout == null)
{
cardLayout = new CardLayout();
}
return cardLayout;
}
JPanel mainPanel;
public JPanel getMainPanel()
{
if (mainPanel == null)
{
mainPanel = new JPanel();
mainPanel.setLayout(getCardLayout());
mainPanel.add(CONNEXION_VIEW, getConnexionView());
mainPanel.add(CONNEXION_FAILED_VIEW, getConnexionFailedView());
}
return mainPanel;
}
ConnexionView connexionView;
protected ConnexionView getConnexionView()
{
if (connexionView == null)
{
connexionView = new ConnexionView();
}
return connexionView;
}
ConnexionFailedView connexionFailedView;
protected ConnexionFailedView getConnexionFailedView()
{
if (connexionFailedView == null)
{
connexionFailedView = new ConnexionFailedView();
}
return connexionFailedView;
}
the connexion view, the one with the button to click with the action listener where i want to put my code
public class ConnexionView extends JPanel{
GridBagLayout gbl = new GridBagLayout();
private JButton btnConnexion;
Dimension dimensionBouton = new Dimension(170, 30);
public ConnexionView()
{
super();
initialise();
}
private void initialise()
{
setLayout(gbl);
GridBagConstraints gbcbtnConnexion = new GridBagConstraints();
gbcbtnConnexion.gridwidth = GridBagConstraints.REMAINDER;
gbcbtnConnexion.gridheight = GridBagConstraints.REMAINDER;
gbcbtnConnexion.gridx = 1;
gbcbtnConnexion.gridy = 2;
add(getBtnConnexion(), gbcbtnConnexion);
}
private JButton getBtnConnexion()
{
if (btnConnexion == null)
{
btnConnexion = new JButton("Connexion");
btnConnexion.setPreferredSize(dimensionBouton);
btnConnexion.setMinimumSize(dimensionBouton);
btnConnexion.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
/////code to display the connexion_Failed_View
System.out.println("test");
}
});
}
return btnConnexion;
}
}
and the connexion failed view, the one i want to display after the button is clicked
public class ConnexionFailedView extends JPanel{
public ConnexionFailedView()
{
super();
initialise();
}
private void initialise()
{
setBackground(Color.YELLOW);
}
thanks in advance
You will need to keep the component in your Button somehow, so you can access it.
class ConnexionView {
private JComponent mainPanel;
public ConnexionView(JComponent mp) { mainPanel = mp; }
}
Obviously, that means the MainFrame needs to pass it then.
Now, the listener can do
// it would be cleaner if you passed the layout in the constructor as well
CardLayout cl = (CardLayout) mainPanel.getLayoutManager();
cl.show(mainPanel, MainFrame.CONNEXION_FAILED_VIEW);
I have some problems with my application. I'm trying to create a JButton just with AWT components. The main problem is that I have an exception : at QButton.QButton.addActionListener(QButton.java:83).
If i comment the line //this.addActionListener everything is ok. My object is extends Panel
public class QButton extends Panel implements MouseListener,ActionListener{
public Label text;
ImagePanel image;
ActionListener listener;
public QButton(String text){
Label l = new Label(text);
this.add(l);
this.text=l;
this.setLayout(new GridBagLayout());
this.setBackground(Color.gray);
TextButtonActions ac1=new TextButtonActions(this);
this.addMouseListener(ac1);
this.text.addMouseListener(ac1);
}
public QButton(ImagePanel img){
this.setLayout(new GridLayout());
this.image=img;
this.add(image);
PictureButtonActions ac2=new PictureButtonActions(this);
this.image.addMouseListener(ac2);
}
public QButton(String text, ImagePanel img){
this.setBackground(Color.gray);
this.setLayout(new GridLayout());
Label l = new Label(text);
this.add(l);
this.text=l;
this.image=img;
this.add(image);
TAndPButtonActions ac3=new TAndPButtonActions(this);
this.image.addMouseListener(ac3);
this.text.addMouseListener(ac3);
}
public void setText(String txt)
{
this.text.setText(txt);
}
public String getText()
{
return(text.getText());
}
public void setImage(ImagePanel i)
{
this.remove(image);
this.image=i;
this.add(i);
//System.out.println("setImage");
this.validate();
}
public ImagePanel getImage()
{
return(image);
}
void addActionListener(ActionListener listener)
{
this.listener=listener;
this.addActionListener(listener);
}
}
I'm not familiar with UI things, but the reason you get a StackOverflowException, is because your program trying to invoke the method which will call itself.
void addActionListener(ActionListener listener)
// ^^^^^^^^^^^^^^^^^
{
this.listener=listener;
this.addActionListener(listener); // <-- will keep calling itself.
//^^^^^^^^^^^^^^^^^
}
Perhaps you meant to say super.addActionListener(listener);?
I am trying to change JList rows dynamically. I need change nth row colour, highlight it(n is unknown during compilation). I saw a lot of examples with custom ListCellRenderer, but all were "static".
In other words I have JList with x rows. During runtime my "business logic" detects nth row is important. So I want make its background green, wait one second, and then make it white again. One more thing, don't wan change row selection.
What is the best way to do so?
Simple, set a custom ListCellRenderer to your JList using:
list.setCellRenderer(myListCellrenderer);
Now inside the overridden method getListCellRendererComponent() do something like this:
public Component getListCellRendererComponent(.....) {
Component c = super.getListCellRendererComponent();
c.setBackGround(Color.blue)
return c;
}
The above example assumed that your custom renderer overrid DefaultListCellRenderer
Based on ListDemo sample from SUN.
If you enter some text in the textfield which isn't in the list and you hit highlight it gets added.
If the text is in the list and you hit highlight the entry in the list gets temporarily highlighted blue.
Note the solution here with the match field is just for demo. For more correct implementation consider the other ideas proposed and consider using javax.swing.Timer
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ListDemo extends JPanel {
private JList list;
private DefaultListModel listModel;
public String match = null;
private static final String hireString = "Highlight";
private JTextField employeeName;
public ListDemo() {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("Test1");
listModel.addElement("Test2");
listModel.addElement("Test3");
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.setVisibleRowCount(5);
list.setCellRenderer(new MyListCellRenderer());
JScrollPane listScrollPane = new JScrollPane(list);
JButton hireButton = new JButton(hireString);
HireListener hireListener = new HireListener(hireButton);
hireButton.setActionCommand(hireString);
hireButton.addActionListener(hireListener);
hireButton.setEnabled(false);
employeeName = new JTextField(10);
employeeName.addActionListener(hireListener);
employeeName.getDocument().addDocumentListener(hireListener);
listModel.getElementAt(list.getSelectedIndex()).toString();
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane,
BoxLayout.LINE_AXIS));
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(employeeName);
buttonPane.add(hireButton);
buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
add(listScrollPane, BorderLayout.CENTER);
add(buttonPane, BorderLayout.PAGE_END);
}
class MyListCellRenderer extends JLabel implements ListCellRenderer {
public MyListCellRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(JList paramlist, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setText(value.toString());
if (value.toString().equals(match)) {
setBackground(Color.BLUE);
SwingWorker worker = new SwingWorker() {
#Override
public Object doInBackground() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) { /*Who cares*/ }
return null;
}
#Override
public void done() {
match = null;
list.repaint();
}
};
worker.execute();
} else
setBackground(Color.RED);
return this;
}
}
class HireListener implements ActionListener, DocumentListener {
private boolean alreadyEnabled = false;
private JButton button;
public HireListener(JButton button) {
this.button = button;
}
public void actionPerformed(ActionEvent e) {
String name = employeeName.getText();
if (listModel.contains(name)) {
match = name;
list.repaint();
employeeName.requestFocusInWindow();
employeeName.selectAll();
return;
}
if (name.equals("")) {
Toolkit.getDefaultToolkit().beep();
employeeName.requestFocusInWindow();
employeeName.selectAll();
return;
}
int index = list.getSelectedIndex();
if (index == -1)
index = 0;
else
index++;
listModel.insertElementAt(employeeName.getText(), index);
employeeName.requestFocusInWindow();
employeeName.setText("");
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
public void insertUpdate(DocumentEvent e) {
enableButton();
}
public void removeUpdate(DocumentEvent e) {
handleEmptyTextField(e);
}
public void changedUpdate(DocumentEvent e) {
if (!handleEmptyTextField(e))
enableButton();
}
private void enableButton() {
if (!alreadyEnabled)
button.setEnabled(true);
}
private boolean handleEmptyTextField(DocumentEvent e) {
if (e.getDocument().getLength() <= 0) {
button.setEnabled(false);
alreadyEnabled = false;
return true;
}
return false;
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("ListDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new ListDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() { createAndShowGUI(); }
});
}
}
Your custom ListCellRenderer, which implements the method getListCellRendererComponent, will have access to both the JList and the value that it is redering. This gives you a couple options for how to determine when to paint the nth row green:
You could subclass JList and have the renderer ask it which color to use for the bg. The JList subclass could trigger a repaint when the business logic determines that it is time for the nth row to be green, and then start an Swing Timer to trigger a repaint returning the bg back to normal
When the business logic determines when you should show the row as green, you also have the option of setting state on the backing object of the row, and test it for that state within getListCellRendererComponent, setting the bg green if the state is correct. Again, you have the option of setting an Swing Timer to revert the state on the backing object.
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());
}