Cancel button never gets enabled - java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.lang.Thread;
public class Lthread extends JPanel{
private JTextField acctTF;
private JTextField pinTF;
private JButton cancelB;
private JLabel balanceL;
private JButton searchB;
public Lthread() {
buildGUI();
hookupEvents();
}
private void buildGUI() {
JLabel acctL=new JLabel("Account Number:");
JLabel pinL=new JLabel("PIN:");
acctTF=new JTextField(12);
pinTF=new JTextField(4);
JPanel dataEntryP=new JPanel();
dataEntryP.setLayout(new FlowLayout(FlowLayout.CENTER));
dataEntryP.add(acctL);
dataEntryP.add(acctTF);
dataEntryP.add(pinL);
dataEntryP.add(pinTF);
searchB=new JButton("Search");
cancelB=new JButton("Cancel Search");
cancelB.setEnabled(false);
JPanel innerButtonP=new JPanel();
innerButtonP.setLayout(new GridLayout(1,-1,5,5));
innerButtonP.add(searchB);
innerButtonP.add(cancelB);
JPanel buttonP=new JPanel();
buttonP.setLayout(new FlowLayout(FlowLayout.CENTER));
buttonP.add(innerButtonP);
JLabel balancePrefixL=new JLabel("Account Balance: ");
balanceL=new JLabel("BALANCE UNKNOWN");
JPanel balanceP=new JPanel();
balanceP.setLayout(new FlowLayout(FlowLayout.CENTER));
balanceP.add(balanceL);
JPanel northP=new JPanel();
northP.setLayout(new GridLayout(-1,1,5,5));
northP.add(dataEntryP);
northP.add(buttonP);
northP.add(balanceP);
setLayout(new BorderLayout());
add(northP,BorderLayout.NORTH);
}
private void hookupEvents() {
searchB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
search(ae);
}
});
cancelB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
cancelSearch(ae);
}
});
}
private void search(ActionEvent ae) {
searchB.setEnabled(false);
cancelB.setEnabled(true);
balanceL.setText("SEARCHING...");
String acct=acctTF.getText();
String pin=pinTF.getText();
String bal=lookupBalance(acct,pin);
setBalance(bal);
}
private String lookupBalance(String acct,String pin) {
try {
Thread.sleep(5000);
return "1,234.56";
} catch(Exception exc) {
return "search cancelled";
}
}
private void setBalance(String newBalance) {
balanceL.setText(newBalance);
cancelB.setEnabled(false);
searchB.setEnabled(true);
}
private void cancelSearch(ActionEvent ae) {
System.out.println("in cancelSearch");
}
public static void main(String args[]) {
Lthread Lt=new Lthread();
JFrame f=new JFrame("Balance Lookup-Can't cancel");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setContentPane(Lt);
f.setSize(400,150);
f.setVisible(true);
}
}
As soon as we click search,cancel should get enabled,but it does not get enabled, why?
Another thing is label balanceL should display SEARCHING. When search is clicked but that is also not displayed. Why?

You're doing all the work (well, sleeping) in the UI thread. That's stopping all the rest of the UI from updating, processing events etc.
You should offload your work (the searching/sleeping) to a background thread, using SwingWorker to marshall any UI calls back to the UI thread. (You can't touch UI components from a non-UI thread.)
A search for "swing threads" gives loads of hits for tutorials etc, if you want more information. In particular, you probably want to read the Java Tutorial trail on threading in Swing.

because the eventdispatcher thread is blocked in the search() function. it should never be blocked. use SwingUtilities.invokeLater().
for your problem change search method to
private void search(ActionEvent ae) {
searchB.setEnabled(false);
cancelB.setEnabled(true);
balanceL.setText("SEARCHING...");
final String acct=acctTF.getText();
final String pin=pinTF.getText();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
String bal=lookupBalance(acct,pin);
setBalance(bal);
}
});
}

Related

Java GUI Real Time Word Counter

I was checking out the example projects that people do when starting to learn Java and GUI, I was faced with a bunch of word/letter count programs such as:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Counter extends JFrame implements ActionListener{
JLabel lb1,lb2;
JTextArea ta;
JButton b;
JButton pad,text;
Counter(){
super("Char Word Count Tool - JTP");
lb1=new JLabel("Characters: ");
lb1.setBounds(50,50,100,20);
lb2=new JLabel("Words: ");
lb2.setBounds(50,80,100,20);
ta=new JTextArea();
ta.setBounds(50,110,300,200);
b=new JButton("Count");
b.setBounds(50,320, 80,30);//x,y,w,h
b.addActionListener(this);
add(lb1);add(lb2);add(ta);add(b);
setSize(400,400);
setLayout(null);//using no layout manager
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==b){
String text=ta.getText();
lb1.setText("Characters: "+text.length());
String words[]=text.split("\\s");
lb2.setText("Words: "+words.length);}
}
public static void main(String[] args) {
new Counter();
}}
But I don't want to count words whenever I click the button but in real-time so the values update each frame. Do I need to use multi-threading for this or it can be achieved without it?
You need to use a DocumentListener on the JTextArea instead of an ActionListener on a JButton.
void test() {
JTextArea textArea = new JTextArea();
textArea.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
recalculateWords();;
}
#Override
public void removeUpdate(DocumentEvent e) {
recalculateWords();
}
#Override
public void changedUpdate(DocumentEvent e) {
recalculateWords();
}
});
}
void recalculateWords() {
//Use your code from actionPerfomed here.
}

What am I doing wrong with this Java JPanel/JFrame/JButton?

What am I doing wrong with this Java JPanel/JFrame/JButton? This is my program and right now I've been trying to be able to repaint it, but it won't work. Please help! I am a beginner with JPanel and JFrame. I'm only adding this sentence to allow it to post.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Clicks implements MouseListener
{
private static int clicks, clickersInt, clickersCost;
private static JButton clickersB, click;
private static JLabel clickersL, clicksL;
private static JPanel panel;
public static void main(String[] args)
{
JFrame clicksFrame=new JFrame ("Clicks");
clicksFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
clicks=0;
panel=new JPanel(new GridBagLayout());
click=new JButton("Click Me!");
clickersB=new JButton("Cost: 10");
clickersL=new JLabel("Clickers: "+Integer.toString(clickersInt));
clicksL=new JLabel("Clicks: "+Integer.toString(clicks));
click.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
clicks++;
clicksFrame.remove(panel);
clicksFrame.add(panel);
panel.validate();
panel.repaint();
}
});
clickersB.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(clicks>=clickersCost)
{
clickersInt++;
clicks-=clickersCost;
clickersCost*=2;
}
}
});
panel.add(click);
panel.add(clicksL);
panel.add(clickersL);
panel.add(clickersB);
clicksFrame.add(panel);
clicksFrame.setBackground(Color.CYAN);
clicksFrame.setVisible(true);
}
}
So, based on this little snippet...
click=new JButton("Click Me!");
clickersB=new JButton("Cost: 10");
clickersL=new JLabel("Clickers: "+Integer.toString(clickersInt));
clicksL=new JLabel("Clicks: "+Integer.toString(clicks));
click.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
clicks++;
clicksFrame.remove(panel);
clicksFrame.add(panel);
panel.validate();
panel.repaint();
}
});
I would suggest that what you really want to do is...
click.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
clicks++;
clicksL.setText("Clicks: "+Integer.toString(clicks));
}
});
You seem to be of the illusion that changing a variable will some how change another variable which is just a string of characters. As you've discovered, that's not how this works

Java 8 - Losing all keyboard input or focus after switching windows

I'm running an application with similar behaviour to that in the test case below.
The problem is that when you switch focus to a different window by clicking on it and keeping the below application frame in view and then click directly into the text field with the focusGained listener, close the dialog and then all key input will be lost to the all of the text fields in the application.
If you click anywhere in the application first or the icon in the task bar to gain focus back then this does not occur.
This is Java 8 specific - in Java 7 it will not lose focus, not sure about java 9 but that is not an option anyway
The test case below demonstrates this behaviour.
public class FocusTest extends JFrame
{
JTextField noFocus;
public static void main(String[] args)
{
FocusTest ft = new FocusTest();
ft.setVisible(true);
}
public FocusTest()
{
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBounds(100,100,300,150);
setLayout(new GridLayout(3,1, 2, 2));
setTitle("Losing keyboard...");
noFocus = new JTextField();
add(noFocus);
JTextField jft = new JTextField();
jft.addFocusListener(new FocusAdapter()
{
#Override
public void focusGained(FocusEvent e)
{
createDialog().setVisible(true);
noFocus.requestFocusInWindow();
}
});
add(jft);
JButton jb = new JButton("OPEN");
jb.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("OPEN"))
createDialog().setVisible(true);
}
});
add(jb);
}
private JDialog createDialog()
{
final JDialog jd = new JDialog(this, true);
jd.setLocationRelativeTo(this);
jd.setLayout(new BorderLayout());
jd.getContentPane().add(new JTextField(), BorderLayout.CENTER);
JButton jb = new JButton("Close");
jb.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("Close"))
jd.dispose();
}
});
jd.getContentPane().add(jb, BorderLayout.SOUTH);
jd.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
jd.pack();
return jd;
}
}
Not exactly sure what's happening, but one solution is to use a SwingUtilities.invokeLater():
#Override
public void focusGained(FocusEvent e)
{
noFocus.requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createDialog().setVisible(true);
}
});
}
This will allow the text field to get focus properly before the dialog is made visible.

Swing : Exit application actionListener

I am trying to figure out how can we exit the application with button click.
The problem i faced which makes me unable to exit the application is because i am using "extend JFRame" from the main class.
For an example,
app.class
public class app{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame frame = new MainFrame("Exercise one");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
.. .. ..
frame.setVisible(true);
})
}
}
MainFrame.java
public class MainFrame extends JFrame(){
public MainFrame(String title){
super(title)
//set layout manager
setLayout(new BorderLayout());
//swing components
JButton exit = new JButton("Exit");
//add container
Container container = getContentPane();
container.add(exit);
//create actionlist logic
exit.addActionListener(new ActionListener()){
#Override
public void actionPerformed(ActionEvent arg0){
// on click , this logic will end the application
}
}
}
}
I fully understand how i can cancel the application from app class.But in scenarios where i want to cancel the application from MainFrame.Can it be done ?
Thank you in advance.
The defaultCloseOperation is only processed by the frame when it encounters a WINDOW_CLOSING event, neither setVisible or dispose trigger this event, which means the the defaultCloseOperation won't be processed
The only way to ensure that this operation is triggered is to manually dispatch a WINDOW_CLOSING event
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
One of the main reasons for wanting to follow this path is that it ensures the application is following the configured defaultCloseOperation and making up it's own mind (like calling System.exit manually)
The following demonstrates hiding, disposing and dispatching approaches. Only the dispatch approach will close the window and terminate the JVM
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.NAME;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
frame.add(new JButton(new HideAction(frame)), gbc);
frame.add(new JButton(new DisposeAction(frame)), gbc);
frame.add(new JButton(new DispatchAction(frame)), gbc);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.out.println("Closing");
}
#Override
public void windowClosed(WindowEvent e) {
System.out.println("Closed");
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HideAction extends AbstractAction {
private JFrame frame;
public HideAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Hide");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
}
}
public class DisposeAction extends AbstractAction {
private JFrame frame;
public DisposeAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Dispose");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
}
}
public class DispatchAction extends AbstractAction {
private JFrame frame;
public DispatchAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Dispatch");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
}
}
}
If I run this in my IDE, unless I use the dispatch option, the JVM is left running and I have to terminate the session to close it fully.
I also noted that calling dispose only triggers the WINDOW_CLOSED event, while the dispatch method will trigger the WINDOW_CLOSING event
Problem solved.
Credits to #XtremeBaumer.
Basically, when using "classname" extend JFRame.
We can input dispose() which will kill the application completely. This will causes the JFrame window to be destroyed and cleaned up by the operating system. :)
Indeed, dispose() is the right solution. I also suggest to add a pack() call so the UI shows up properly:
public class MainFrame extends JFrame {
public MainFrame(String title) {
super(title);
...
// create actionlist logic
exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("--> closing app programmatically");
MainFrame.this.dispose();
}
});
this.pack();
}
}
You can test the events with a WindowListener on the MainFrame. They are invoked as if the user pressed the close button:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new MainFrame("Exercise one");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
// .. .. ..
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.out.println("--> closing...");
}
public void windowClosed(WindowEvent e) {
System.out.println("--> closed...");
}
});
}
});
}

Swing JButton event

I have JButton and want on event call this class method show() when this button in pressed. I know how to this, if I want use method from another class, but I need call method from same class as button.
JButton search = new JButton(new ButtonAction("Search", KeyEvent.VK_A));
I try add
JButton search = new JButton(show());
But it works only 1 time when object creating, but not when button is pressed.
Not sure what you want here... but if you want to attach an actionListener() to a JButton, you can do the following. Why do you need to listen to A?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionListenerExample1 extends JFrame
implements ActionListener, KeyListener {
private static final long serialVersionUID = 1L;
private JTextField searchText;
private JButton searchButton1;
private JButton searchButton2;
public ActionListenerExample1() {
initialize();
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
protected void initialize() {
searchText = new JTextField(30);
searchButton1 = new JButton("Search 1");
searchButton2 = new JButton("Search 2");
searchText.addKeyListener(this);
searchButton1.addActionListener(this);
searchButton2.addActionListener(new ButtonAction());
this.setLayout(new FlowLayout());
this.add(searchText);
this.add(searchButton1);
this.add(searchButton2);
}
public static void main(String[] args) {
new ActionListenerExample1();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == searchButton1) {
buttonAction("GLOBAL LISTENER");
}
}
private class ButtonAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
buttonAction("LOCAL LISTENER");
}
}
private void buttonAction(String label) {
JOptionPane.showMessageDialog(this,
String.format("%s: %s", label, searchText.getText()));
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_A) {
buttonAction("KEYBOARD");
}
}
#Override
public void keyReleased(KeyEvent e) { }
#Override
public void keyTyped(KeyEvent e) { }
}
If I understand you correctly, you want to call a method from the class that you created the button in rather than a method from another class.
First off, notice that while you are technically calling a method here
JButton search = new JButton(new ButtonAction("Search", KeyEvent.VK_A));
what is really going on is that you are passing a ButtonAction object to the JButton constructor. The closest thing that I can think of that will get what you want is having the class you are using extend ButtonAction.

Categories

Resources