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.
Related
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();
}
}
I am creating a simple java program with a GUI built with the help of window builder. The GUI consists of just a button.
On button click,start a thread that will print to the random number infinitely until it is stopped by clicking the same button again.
Here is my code
LoopTest.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class LoopTest extends JFrame implements ActionListener {//******
private JButton startB, stopB;
private JTextArea oa;
Start sta;
public LoopTest(){
super("Final Exam: Question ");
Container c = getContentPane();
c.setLayout(new FlowLayout());
startB = new JButton("START"); c.add(startB);
stopB = new JButton("STOP"); c.add(stopB);
oa = new JTextArea(5,20); c.add(oa);
c.add(new JScrollPane(oa));
registerEvents();
sta = new Start("Loop", oa);
}
public void registerEvents(){
startB.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
if(startB.isEnabled() == true )
sta.setLoopFlag(true);
if(!sta.isAlive())
sta.start();
startB.setEnabled(false);
}
}
);
stopB.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae){
if(stopB.isEnabled()==true){
sta.setLoopFlag(false);
}
}
}
);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
public static void main(String[] args){
LoopTest app = new LoopTest();
app.setSize(300,300);
app.setLocationRelativeTo(null);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
app.setVisible(true);
}
}
Start.java
public class Start extends Thread {
private JTextArea ta;
private boolean loopFlag;
public Start(String name, JTextArea ta){
super(name);
this.ta = ta;
ta.setText("");
loopFlag = true;
}
public void run(){
int num=0;
while(true)
while(loopFlag){
num = 1+ (int)(Math.random()*100);
ta.append(num + "\n");
}
}
public void setLoopFlag(boolean value){
loopFlag = value;
}
}
Stop.java
public class Stop extends Thread {
public Stop( String name ){
super(name);
}
public void run(){
}
}
Thanks in advance.
Your code breaks Swing threading rules as you're making mutational changes to Swing components off of the Swing event thread.
Suggestions:
Never extend Thread. It's almost always better to implement Runnable and use the Runnable in a Thread.
Avoid making Swing calls, other than repaint() off of the Swing event thread.
Your while (true) is a "tight" loop -- it has no Thread.sleep within it, and that means that it risks typing up the CPU in its tight loop, something that can hamper your program and your computer.
Best to avoid using direct background threading altogether here as your code issue can be solved much more easily and cleanly by using a Swing Timer. Please check the Swing Timer Tutorial
You can easily start and stop this Timer by calling its start() and stop() methods.
I would also use a JList preferentially over a JTextArea since it can more easily handle large amounts of data.
I also like using AbstractActions rather than ActionListeners for my JButton, and this problem lends itself nicely to their use. You can create an Action for start and one for stop and simply swap out the button's actions.
For example:
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class StartStop extends JPanel {
private static final int TIMER_DELAY = 300;
private StartAction startAction = new StartAction();
private StopAction stopAction = new StopAction();
private JButton button = new JButton(startAction);
private DefaultListModel<Integer> model = new DefaultListModel<>();
private JList<Integer> jList = new JList<>(model);
private Timer timer = new Timer(TIMER_DELAY, new TimerListener());
public StartStop() {
JPanel btnPanel = new JPanel();
btnPanel.add(button);
jList.setFocusable(false);
jList.setVisibleRowCount(10);
jList.setPrototypeCellValue(100000);
JScrollPane scrollPane = new JScrollPane(jList);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int num = 1 + (int) (Math.random() * 100);
model.addElement(num);
}
}
private class StartAction extends AbstractAction {
public StartAction() {
super("Start");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
button.setAction(stopAction);
}
}
private class StopAction extends AbstractAction {
public StopAction() {
super("Stop");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
timer.stop();
button.setAction(startAction);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Start Stop");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new StartStop());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
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;
}
}
}
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();
}
}
I try to attach action Events on the JCombobox arrow JButton.
So I make a custom ComboBoxUI:
public class CustomBasicComboBoxUI extends BasicComboBoxUI {
public static CustomBasicComboBoxUI createUI(JComponent c) {
return new CustomBasicComboBoxUI ();
}
#Override
protected JButton createArrowButton() {
JButton button=super.createArrowButton();
if(button!=null) {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// arrow button clicked
}
});
}
return button;
}
}
The problem with this is that the look of combobox is different, seem to be an old look.
Why? I only add a listener to the same arrow button...
Thank.
Perhaps the problem is due to your expecting a JComboBox isn't a BasicComboBoxUI but one of another look and feel, perhaps a MetalComboBoxUI.
Rather than create a new CustomBasicComboBoxUI object, could you extract the JButton component from an existing JComboBox object? i.e.,
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ComboBoxArrowListener {
private static void createAndShowUI() {
String[] data = {"One", "Two", "Three"};
JComboBox combo = new JComboBox(data);
JPanel panel = new JPanel();
panel.add(combo);
JButton arrowBtn = getButtonSubComponent(combo);
if (arrowBtn != null) {
arrowBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("arrow button pressed");
}
});
}
JFrame frame = new JFrame("ComboBoxArrowListener");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static JButton getButtonSubComponent(Container container) {
if (container instanceof JButton) {
return (JButton) container;
} else {
Component[] components = container.getComponents();
for (Component component : components) {
if (component instanceof Container) {
return getButtonSubComponent((Container)component);
}
}
}
return null;
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}