JComboBox loses keyboard events after setting custom UI - java

I have the following problem :
I need to set a custom UI for a JComboBoxComponent (to modify colors, arrow button etc.) Currently, I'm doing it in a constructor, like this :
public MyComboBox() {
setUI(new MyComboBoxUI);
}
Problem is, after setting UI in such way, I somehow loose all InputMap and ActionMap contents for list in combo box popup, i.e. it doesn't scroll list up or down with arrow keys.
What am I doing wrong here?
Here's the code :
public class CurrencyPairComboBox extends JComboBox {
public CurrencyPairComboBox() {
setUI(new CurrencyPairComboBoxUI());
}
}
class CurrencyPairComboBoxUI extends BasicComboBoxUI {
#Override
public void installUI(JComponent c) {
super.installUI(c);
listBox.setSelectionBackground(Color.BLACK);
listBox.setSelectionForeground(Color.WHITE);
}
#Override
protected JButton createArrowButton() {
arrowButton = new JButton();
arrowButton.setIcon(OrderWidgetUIConstants.DROPDOWN_ARROW_ICON);
arrowButton.setRolloverIcon(OrderWidgetUIConstants.DROPDOWN_ARROW_HOVER_ICON);
return arrowButton;
}
}

I tried code that you posted here, I didn't see any Keyboard issue(s), all works as I expected
import java.awt.*;
import javax.swing.*;
class ComboBoxTest extends JFrame {
private static final long serialVersionUID = 1L;
private JComboBox comboBox;
private ImageIcon infoIcon = (ImageIcon) UIManager.getIcon("OptionPane.informationIcon");
private ImageIcon warnIcon = (ImageIcon) UIManager.getIcon("OptionPane.warningIcon");
ComboBoxTest() {
String[] items = {"Item1", "Item2"};
comboBox = new JComboBox(items);
Container c = getContentPane();
c.setLayout(new FlowLayout());
c.add(comboBox);
comboBox.setUI(new MyUI());
}
public JFrame getCurrentInstance() {
return this;
}
public static void main(String[] args) {
ComboBoxTest frame = new ComboBoxTest();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
class MyUI extends javax.swing.plaf.basic.BasicComboBoxUI {
#Override
protected JButton createArrowButton() {
JButton btn = new JButton();
btn.setIcon(infoIcon);
btn.setRolloverIcon(warnIcon);
return btn;
}
}
}

Related

Accessing variables from a JPanel when using EventListenter [duplicate]

I have a class whitch extends JPanel:
public class ButtonPanel extends JPanel {
private label;
public ButtonPanel() {
label=new JLabel("waiting for click");
add(label);
}
public void setButtonText() {
label.setText("just clicked");
}
}
I have several instances of that class which is added to JFrame. I want to create one instanse of MouseAdapter class and then add them as a mouse listener to all of the ButtonPanel components on my JFrame. I meen:
ButtonPanel butt1 = new ButtonPanel();
ButtonPanel butt2 = new ButtonPanel();
ButtonPanel butt3 = new ButtonPanel();
//... here goes code which add ButtonPanels to JFrame
MouseAdapterMod mam = new MouseAdapterMod();
butt1.addMouseListener(mam);
butt2.addMouseListener(mam);
butt3.addMouseListener(mam);
The MouseAdapterMod class I want to be separate from the other and locate in it's own package. It should looks like this:
public class MouseAdapterMod extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
//here goes the code of calling setButtonText method of ButtonPanel component on which the event had occurred
}
}
So the problem is that I don't know how to implement mouseClicked method to make it determine which of ButtonPanel generate the event and call the corresponding to that component setButtonText() method. Is anyone know how to do that?
I know that I can achieve this by including event handling functionality in the ButtonPanel class, but thats not appropriate way for me, cuz I want to keep the class structure as I described above and have only one instance of MouseAdapterMod class for handling all of the ButtonPanels.
The MouseEvent#getSource method will return which object has been clicked:
public class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
As the comments note, you're often better off listening for mousePressed or mouseReleased rather than mouseClicked because for mouseClicked to work, the press and release must be from the same point, and if the mouse shifts even a slight amount, the click won't register.
My test program:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class MainForButtonPanel extends JPanel {
public MainForButtonPanel() {
setLayout(new GridLayout(4, 4));
MouseAdapter myMA = new MouseAdapterMod();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
ButtonPanel btnPanel = new ButtonPanel();
btnPanel.addMouseListener(myMA);
add(btnPanel);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MainForButtonPanel");
frame.getContentPane().add(new MainForButtonPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ButtonPanel extends JPanel {
private static final int TIMER_DELAY = 2000;
private static final String JUST_CLICKED = "just clicked";
private static final String WAITING_FOR_CLICK = "waiting for click";
private static final Color CLICKED_COLOR = Color.pink;
private JLabel label;
public ButtonPanel() {
label = new JLabel(WAITING_FOR_CLICK);
add(label);
}
public void setButtonText() {
label.setText(JUST_CLICKED);
setBackground(CLICKED_COLOR);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
label.setText(WAITING_FOR_CLICK);
setBackground(null);
((Timer)ae.getSource()).stop();
}
}).start();
}
}
class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}

jDialog not showing

I have tried to add my jPanel to a jDialog and when I trigger the button nothing happens. Why? I have the code below:
public class fontFormat{
public void fontPanel(){
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.getPreferredSize();
Dimension size = new Dimension();
size.width = 400;
size.height = 600;
panel.setPreferredSize(size);
panel.add(new JLabel("label"));
panel.add(new JButton("button"));
JDialog fontDialog = new JDialog();
fontDialog.add(fontDialog);
}
}
Here:
JDialog fontDialog = new JDialog();
fontDialog.add(fontDialog);
You appear to be trying to add your JDialog to itself, which should cause your code to not function. While this code may compile, running this method should cause the JVM to throw an IllegalArgumentException on the fontDialog.add(fontDialog); line.
Please note that you show a JDialog similar to how you show a JFrame:
When you call your JDialog constructor, you will want to pass in the parent window into it, especially if your desire is to display a modal dialog.
You will also want to pass into the constructor the correct ModalityType enum.
You give your JDialog content, often a JPanel with your components on it.
You pack it
then you call setVisible(true) on it, and it should display
For example,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DialogEg {
private static void createAndShowGUI() {
MainPanelGen mainPanelGen = new MainPanelGen();
JFrame frame = new JFrame("DialogEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanelGen.getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
class MainPanelGen {
private JPanel mainPanel = new JPanel();
private JTextField field = new JTextField(10);
private JButton btn = new JButton(new BtnActn());
private JDialog dialog;
private DialogPanel dialogPanel = new DialogPanel();
public MainPanelGen() {
mainPanel.add(field);
mainPanel.add(btn);
field.setEditable(false);
field.setFocusable(false);
}
public JPanel getMainPanel() {
return mainPanel;
}
private class BtnActn extends AbstractAction {
BtnActn() {
super("Button");
}
#Override
public void actionPerformed(ActionEvent arg0) {
if (dialog == null) {
Window win = SwingUtilities.getWindowAncestor(mainPanel);
if (win != null) {
dialog = new JDialog(win, "My Dialog",
Dialog.ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(dialogPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
}
dialog.setVisible(true); // here the modal dialog takes over
System.out.println (dialogPanel.getFieldText());
field.setText(dialogPanel.getFieldText());
}
}
}
class DialogPanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton exitBtn = new JButton(new ExitBtnAxn("Exit"));
public DialogPanel() {
add(field);
add(exitBtn);
}
public String getFieldText() {
return field.getText();
}
private class ExitBtnAxn extends AbstractAction {
public ExitBtnAxn(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent arg0) {
Window win = SwingUtilities.getWindowAncestor(DialogPanel.this);
if (win != null) {
win.dispose();
}
}
}
}

How to add ArrayList of JButton on a JFrame?

I am coding a little game in which,in one class(named Brick) which extends JPannel,i have a JButton working as a "Brick" and in another class which extends JFrame i have an ArrayList of Brick named Grid which holds the Bricks.But i don't know how to represent the Bricks of ArrayList of Bricks in the serial form,i.e,one after the anoher,on the JFrame of Grid class.Please give me some suggestions.
EDIT : I also want no space between the two buttons.How can i stick two buttons,sharing boundaries?
You may use the following code snippet to add and array of customized classes of JButton.
You may edit it as per your needs.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* A JList of JButtons.
*/
public class JButtonListDemo implements Runnable
{
private JList jlist;
public static void main(String args[])
{
SwingUtilities.invokeLater(new JButtonListDemo());
}
public void run()
{
Object[] items = new ButtonItem[] {
new ButtonItem("Apple"),
new ButtonItem("Banana"),
new ButtonItem("Carrot"),
new ButtonItem("Date"),
new ButtonItem("Eggplant"),
new ButtonItem("Fig"),
new ButtonItem("Guava"),
};
jlist = new JList(items);
jlist.setCellRenderer(new ButtonListRenderer());
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jlist.setVisibleRowCount(5);
jlist.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent event)
{
clickButtonAt(event.getPoint());
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(jlist));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void clickButtonAt(Point point)
{
int index = jlist.locationToIndex(point);
ButtonItem item = (ButtonItem) jlist.getModel().getElementAt(index);
item.getButton().doClick();
// jlist.repaint(jlist.getCellBounds(index, index));
}
public class ButtonItem
{
private JButton button;
public ButtonItem(String name)
{
this.button = new JButton(name);
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println(button.getText() + " was clicked.");
}
});
}
public JButton getButton()
{
return button;
}
#Override
public String toString()
{
return button.getText();
}
}
class ButtonListRenderer extends JButton implements ListCellRenderer
{
public Component getListCellRendererComponent(JList comp, Object value, int index,
boolean isSelected, boolean hasFocus)
{
setEnabled(comp.isEnabled());
setFont(comp.getFont());
setText(value.toString());
if (isSelected)
{
setBackground(comp.getSelectionBackground());
setForeground(comp.getSelectionForeground());
}
else
{
setBackground(comp.getBackground());
setForeground(comp.getForeground());
}
return this;
}
}
}
Alternatively, you could always layout your JButtons vertically on a JPanel (using a new GridLayout(0,1) perhaps) and then put your JPanel in a JScrollPane, thus mocking a JList of JButtons.

Composition vs inheritence in JButton

I'd like to create a simple table game by Swing. I have a JFrame and a JPanel variable.
I want to add JButtons to this JPanel, but I'd like to create an own class.
I made a class that extends JButton (inheritence):
public class GameField extends JButton {...}
So I could add GameFields to the JPanel.
But I'd like to create GameFields by composition:
public class GameField{
private JButton button;
}
But in this clase how I can add GameField to JPanel?
Can I solve this problem by compisition?
But in this clase how I can add GameField to JPanel? Can I solve this
problem by compisition?
You do this by adding a simple getter like this:
public class GameField{
private JButton button;
public GameField(String text) {
button = new JButton(text);
// do your stuff here
}
public JButton getButton() {
return button;
}
}
Then in your GUI:
public void createAndShowGUI() {
JPanel panel = new JPanel(new GridLayout(5,5));
panel.add(new GameField("Button # 1").getButton());
panel.add(new GameField("Button # 2").getButton());
...
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
Edit
You've stated in a comment:
Thanks, but in this case if I'd like to access this field (i.e.
panel.getComponent(i)), I can get only a JButton, and not a GameField.
You can keep a list with your GameField objects or you can use putClientProperty() method to keep a reference to the GameField object as shown in the example below:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Demo {
private void createAndShowGUI() {
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton)e.getSource();
GameField gameField = (GameField)button.getClientProperty("GameField");
if(gameField != null) {
System.out.println(gameField.getText());
}
}
};
GameField gameField1 = new GameField("Button # 1");
gameField1.getButton().addActionListener(actionListener);
GameField gameField2 = new GameField("Button # 2");
gameField2.getButton().addActionListener(actionListener);
JPanel content = new JPanel(new GridLayout());
content.add(gameField1.getButton());
content.add(gameField2.getButton());
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class GameField {
private String text;
private JButton button;
public GameField(String text) {
this.text = text;
button = new JButton(text);
button.putClientProperty("GameField", GameField.this);
}
public JButton getButton() {
return button;
}
public String getText() {
return text;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
If you wish your GameField objects to have JComponents and still be able to add them to other JComponents, have them extend JPanel instead of JButton.
You can then have your GameField objects as JPanels with other JComponents and add them to your JFrame.

Determine clicked JPanel component in the MouseListener. Event handling

I have a class whitch extends JPanel:
public class ButtonPanel extends JPanel {
private label;
public ButtonPanel() {
label=new JLabel("waiting for click");
add(label);
}
public void setButtonText() {
label.setText("just clicked");
}
}
I have several instances of that class which is added to JFrame. I want to create one instanse of MouseAdapter class and then add them as a mouse listener to all of the ButtonPanel components on my JFrame. I meen:
ButtonPanel butt1 = new ButtonPanel();
ButtonPanel butt2 = new ButtonPanel();
ButtonPanel butt3 = new ButtonPanel();
//... here goes code which add ButtonPanels to JFrame
MouseAdapterMod mam = new MouseAdapterMod();
butt1.addMouseListener(mam);
butt2.addMouseListener(mam);
butt3.addMouseListener(mam);
The MouseAdapterMod class I want to be separate from the other and locate in it's own package. It should looks like this:
public class MouseAdapterMod extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
//here goes the code of calling setButtonText method of ButtonPanel component on which the event had occurred
}
}
So the problem is that I don't know how to implement mouseClicked method to make it determine which of ButtonPanel generate the event and call the corresponding to that component setButtonText() method. Is anyone know how to do that?
I know that I can achieve this by including event handling functionality in the ButtonPanel class, but thats not appropriate way for me, cuz I want to keep the class structure as I described above and have only one instance of MouseAdapterMod class for handling all of the ButtonPanels.
The MouseEvent#getSource method will return which object has been clicked:
public class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
As the comments note, you're often better off listening for mousePressed or mouseReleased rather than mouseClicked because for mouseClicked to work, the press and release must be from the same point, and if the mouse shifts even a slight amount, the click won't register.
My test program:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class MainForButtonPanel extends JPanel {
public MainForButtonPanel() {
setLayout(new GridLayout(4, 4));
MouseAdapter myMA = new MouseAdapterMod();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
ButtonPanel btnPanel = new ButtonPanel();
btnPanel.addMouseListener(myMA);
add(btnPanel);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MainForButtonPanel");
frame.getContentPane().add(new MainForButtonPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ButtonPanel extends JPanel {
private static final int TIMER_DELAY = 2000;
private static final String JUST_CLICKED = "just clicked";
private static final String WAITING_FOR_CLICK = "waiting for click";
private static final Color CLICKED_COLOR = Color.pink;
private JLabel label;
public ButtonPanel() {
label = new JLabel(WAITING_FOR_CLICK);
add(label);
}
public void setButtonText() {
label.setText(JUST_CLICKED);
setBackground(CLICKED_COLOR);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
label.setText(WAITING_FOR_CLICK);
setBackground(null);
((Timer)ae.getSource()).stop();
}
}).start();
}
}
class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}

Categories