Prevent FocusEvents when Component is not focused - java

I have the following sample-code:
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class SampleFocus extends JFrame {
public SampleFocus(String titel) {
setTitle(titel);
JTextField txtField1 = new JTextField("default-click");
JTextField txtField2 = new JTextField("alternative-Text");
JTextField txtField3 = new JTextField("own diaolog textfield");
JTextArea dummyLabel = new JTextArea(10, 20);
dummyLabel.setText("empty textarea, which is focusable");
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(txtField1);
add(dummyLabel);
add(txtField2);
JDialog altDialog = new JDialog(this);
altDialog.add(txtField3);
altDialog.setVisible(true);
altDialog.pack();
FocusAdapter myFocusListner = new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
if (e.getComponent() instanceof JTextField) {
System.out.println("gained for TextField: "
+ ((JTextField) e.getComponent()).getText());
} else {
System.out.println("gained for component: " + e.getComponent());
}
}
};
txtField1.addFocusListener(myFocusListner);
txtField2.addFocusListener(myFocusListner);
txtField3.addFocusListener(myFocusListner);
// dummyLabel.addFocusListener(myFocusListner);
}
public static void main(String[] args) {
JFrame frame = new SampleFocus("FocusListener - sample");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
When I switch from the Frame to the dialog I get the proper event. When I switch back to the Frame I get as well the proper FocusEvents. My problem is, that when I switch back, I get as well the FocusEvents for components which I am not interested in.
e.g.
Select 'default-click' ==> Dialog/Textfield ==> Frame/'empty textarea'
Result: I get a FocusGained-Event for 'default-click' although the component has NOT the focus.
Desired Result: Either
Component 'default-click' does not get the FocusEvent OR
distinguish if the component really received the Event properly (e.g. I could have clicked into it as well)
Workaround I found:
Attach to the JTextArea as well a FocusListener. Problem is, that this would mean, I need to attach to ALLLL of my components a Listener. Which is hardly possible. Any ideas?
Any ideas how to get the result?
Thx LeO

Its working as intended.
You select "default-click". It gains focus.
You select Dialog. Frame and "default-click" loses focus.
You select Text area. Now, things becomes interesting. Dialog loses focus. Frame gets focus. "default-click" also gains focus, because he had it when Frame was active. And then "default-click" loses focus, textarea gains focus (because you clicked on text area).
Try combine focusGained and focusLost events.
Or tell me more what are you trying to accomplish, maybe I can help.

The way I found the workaround was to check in the focusGained-method if the current component is in an own JDialog and if previous component was a JTextField in a JFrame. If so, then I memorize the gained focused component, change the focus to another component and when I receive a focusLost I request it back to the previously memorized component.
Some kind of hack, but it works.... If there are any better ideas, I am interested in ...

Related

My JCheckBox program only displays one box. Why is that?

I am attempting to add another checkbox to this program but for some reason it will not display when I run the program. Only the check box for the blue pill displays. I have attempted to add a couple things or change the way the program is structured, but nothing I have done so far has helped.
Code Below:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CMIS242WK4DonnersonAReply {
static JCheckBox red;
static JCheckBox blue;
static JButton button;
public CMIS242WK4DonnersonAReply() {
button = new JButton("submit"); // Creates submit button
widget
ButtonHandler listener = new ButtonHandler(); // Creates the handler for the button.
button.addActionListener((ActionListener) listener); // adds the handler to the button widget
JPanel content = new JPanel(); // "container"
content.setLayout(new BorderLayout());
content.add(button, BorderLayout.PAGE_END);// places submit button at the bottom of panel.
JLabel label = new JLabel("At last. Welcome, Neo. As you no doubt have guessed, I am Morpheus. This is your last chance. After this there is no turning back."); // Label in frame.
content.add(label, BorderLayout.NORTH);// places label at the top of the screen.
//Creating Check Boxes
JCheckBox red = new JCheckBox("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
red.setBounds(100,100, 50,50);
content.add(red);
JCheckBox blue = new JCheckBox("You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe. ");
blue.setBounds(100,100, 50,50);
content.add(blue);
//Adding Frame
JFrame window = new JFrame("Matrix Monologue"); // JFrame = Window
window.setContentPane(content);
window.setSize(750,200); // Length, Height
window.setLocation(200,200); // X/Y "OF THE ENTIRE FRAME" Not the contents
window.setVisible(true); // makes window visible
}
// Method handles what happens when button is pressed.
private static class ButtonHandler implements ActionListener{
public void actionPerformed1(ActionEvent e) {
// Checks if which pill was selected and responds to user depending on their action.
if (red.isSelected() == true) {
System.out.println("Follow me");
System.out.println();
}
if (blue.isSelected() == true) {
System.out.println("Very Well, You may go back to your world");
System.out.println();
}
else
System.out.println("You must make a choice for what pill you will take");
System.exit(0); //closes program
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
// Main/driver method that runs everything.
public static void main(String[] args) {
CMIS242WK4DonnersonAReply matrixMonologue= new CMIS242WK4DonnersonAReply();
}
}
Any pointers?
When you're stuck on a problem, it never hurts to go back and consult the documentation.
You'll find information like this:
A border layout lays out a container, arranging and resizing its
components to fit in five regions: north, south, east, west, and
center. Each region may contain no more than one component, and is
identified by a corresponding constant: NORTH, SOUTH, EAST, WEST, and
CENTER. When adding a component to a container with a border layout,
use one of these five constants...
When you add your button, you do this:
content.add(button, BorderLayout.PAGE_END);
But then, when it's time to add checkboxes, you do this:
content.add(red);
...
content.add(blue);
Are you seeing what's missing? My bet is that you only see the blue checkbox because you added it on top of (or simply displaced) the red checkbox. Remember, the doc says "Each region may contain no more than one component..."
Try specifying the region of your BorderLayout where you want to see each checkbox.
If you want them to appear in the same region, put them in a JPanel of their own and lay them out at NORTH and SOUTH or EAST and WEST and then add that checkbox panel to your content panel in the region you want them to appear.
I feel that you need some guidance with your Swing programming. I have rewritten your CMIS242WK4DonnersonAReply class. Code is below. But first some comments about the code in your question.
JCheckBox red = new JCheckBox("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
You have created a local variable which is hiding the class member. Hence static JCheckBox red; remains null and consequently the following if statement will throw NullPointerException.
if (red.isSelected() == true) {
By the way, the == true is not necessary. The following is sufficient.
if (red.isSelected()) {
Now another point.
red.setBounds(100,100, 50,50);
Since you are using a layout manager, namely BorderLayout, method setBounds will be ignored. The layout manager determines where to place the component on the screen.
window.setContentPane(content);
By default, the content pane of JFrame is a JPanel with BorderLayout so no need to replace the default content pane.
private static class ButtonHandler implements ActionListener
No need to create a nested class. Simply make class CMIS242WK4DonnersonAReply implement the ActionListener interface.
System.out.println("Follow me");
I don't think it's a good idea to involve the console in a GUI application. I would use JOptionPane to display a message to the user.
static JCheckBox blue;
I think that JRadioButton is more appropriate than JCheckBox in your situation.
Here is my code.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class CMIS242WK4DonnersonAReply implements Runnable, ActionListener {
private JButton button;
private JRadioButton blue;
private JRadioButton red;
private JFrame window;
#Override
public void actionPerformed(ActionEvent event) {
if (red.isSelected()) {
JOptionPane.showMessageDialog(window, "Follow me.");
}
else if (blue.isSelected()) {
JOptionPane.showMessageDialog(window, "Very Well, You may go back to your world");
}
else {
JOptionPane.showMessageDialog(window, "You must make a choice for what pill you will take");
}
}
#Override
public void run() {
createAndShowGui();
}
private void createAndShowGui() {
window = new JFrame("Matrix Monologue");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("At last. Welcome, Neo. As you no doubt have guessed, I am Morpheus. This is your last chance. After this there is no turning back."); // Label in frame.
window.add(label, BorderLayout.PAGE_START);
window.add(createCheckBoxes(), BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
button = new JButton("submit");
button.addActionListener(this);
buttonPanel.add(button);
window.add(buttonPanel, BorderLayout.PAGE_END);
window.setSize(750,200); // Length, Height
window.setLocation(200,200); // X/Y "OF THE ENTIRE FRAME" Not the contents
window.setVisible(true); // makes window visible
}
private JPanel createCheckBoxes() {
JPanel panel = new JPanel();
BoxLayout layout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
panel.setLayout(layout);
red = new JRadioButton("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
blue = new JRadioButton("You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe.");
ButtonGroup grp = new ButtonGroup();
grp.add(red);
grp.add(blue);
panel.add(red);
panel.add(blue);
return panel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new CMIS242WK4DonnersonAReply());
}
}
Here is how the app looks when I run it.

ActionListener never fires if previous listener calls revalidate()

So I've made a basic UI that shows text fields that will alert the user if the contents is outside of given bounds by causing a label to appear below it. This occurs if the user hits return or Tabs away from the field.
There is also a button that will advance the program so long as all of the fields are correct. If they are not it will cause the text fields to 'flash' (animation background red back to white).
This works fine except for one little bug - if the user enters incorrect data and immediately clicks the button, without first leaving the field, the focus listener fires and adds the label below the text field, but the click button action never fires (no flash). This appears to be due to the FocusListener event calling revalidate() on the panel and or pack() on the enclosing jframe.
Here's a working minimal example to demonstrate the problem
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* Demonstration that running revalidate() or JFrame.pack() in FocusListener
* (on a textField) causes the action listener for a JButton to never fire.
*
* This is only a problem if the contents of the frame are changed (ie. only
* happens once when label is added).
*/
public final class App {
private App() {
JFrame jFrame = new JFrame();
JPanel main = new JPanel();
MyPanel myPanel = new MyPanel();
JButton button = new JButton("Click");
button.addActionListener(event->{
/* with the code as it is this will never print if
the button is pressed while textField has focus
and label is not yet displayed */
System.out.print("\n Click has been pressed");
});
main.add(myPanel);
main.add(button);
jFrame.add(main);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new App());
}
/**
* Creates a panel containing a text box.
* when this text box looses focus it causes
* a label to be added and the frame to resize (.pack())
*/
class MyPanel extends JPanel{
JLabel label;
JTextField textField;
public MyPanel(){
label = new JLabel("hello");
textField = new JTextField(10);
this.add(textField);
textField.addFocusListener(new Handler(this));
}
private class Handler implements FocusListener{
JPanel panel;
public Handler(JPanel panel){
this.panel = panel;
}
#Override
public void focusGained(FocusEvent e) {
}
#Override
public void focusLost(FocusEvent e) {
// if this line is removed
panel.add(label);
// if the below two lines are removed
// button ActionListener will fire
panel.revalidate();
SwingUtilities.getWindowAncestor(panel).pack(); // side note if this is called is revalidate() needed?
}
}
}
}
Any advice on how to fix this would be great. One thing to note is that in the real program the MyPanel class would be in its own file, if that affects any solutions.
Cheers.
=============== EDIT ======================
I was running it in my IDE (vscode) where the problem occured. When I compiled it and ran it from the terminal it worked fine. I presume its some quirk of the IDE.

Swing: grayable multi-line JCheckBox?

I want to have a checkbox with multi-line text and I want to disable it sometimes.
Simple JCheckBox works fine and gets disabled, but it's not multiline.
Putting <html>line1<br>line2</html> provides correct size and layout, but when I disable the control, only the checkbox itself is grayed, the text remains black.
I know I can change the HTML text color to gray, but this will not work for the "Classic Windows" look-and-feel where disabled text should rendered as "sunken". Or, actually, it will work, but the appearance will differ from other disabled controls nearby, which is not good.
I can create a simple JCheckBox containing the first line of text and a JLabel with the second line and disable them simultaneously, but clicking the second line (the JLabel) doesn't activate the checkbox, and clicking the checkbox displays the keyboard focus only around the first line which confuses the user.
Is it possible to have a checkbox and its label as separate controls and have some kind of link between them, as in HTML? Probably I would be able to cook something from this.
Is it possible to subclass JButton and override something there, for example, to change the way the focus rectangle is drawn? The rectangle is drawn by com.sun.java.swing.plaf.windows.WindowsButtonUI but I'm kinda afraid of subclassing that class because it's too deep in the standard library and my application may break with a new JRE.
EDIT 04.02.2015: The above applies to Java 1.6. In Java 1.7 and higher, disabling a multi-line checkbox changes its appearance, but it still looks not the same as a disabled single-line checkbox; in particular, on Classic Windows theme the text doesn't become sunken.
(source: keep4u.ru)
I might be missing something, but I just disable the JCheckBox and the JLabel.
Using Java 1.7 and Windows Vista.
Here's the code
package com.ggl.testing;
import java.awt.BorderLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class CheckBoxTest implements Runnable {
private JCheckBox checkBox;
private JLabel multiLineLabel;
private JFrame frame;
#Override
public void run() {
frame = new JFrame("Check Box Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel checkBoxPanel = new JPanel();
checkBox = new JCheckBox();
checkBoxPanel.add(checkBox);
String s = "<html>When in the course of human events it becomes"
+ "<br>necessary for one people to dissolve the political"
+ "<br>bands which have connected them with another and to"
+ "<br>assume among the powers of the earth, the separate"
+ "<br>and equal station to which the Laws of Nature and"
+ "<br>of Nature's God entitle them, a decent respect to the"
+ "<br>opinions of mankind requires that they should declare"
+ "<br>the causes which impel them to the separation.";
multiLineLabel = new JLabel(s);
multiLineLabel.setLabelFor(checkBox);
checkBoxPanel.add(multiLineLabel);
mainPanel.add(checkBoxPanel, BorderLayout.CENTER);
JPanel toggleButtonPanel = new JPanel();
JToggleButton toggleButton = new JToggleButton("Disable Checkbox");
toggleButton.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent event) {
JToggleButton toggleButton = (JToggleButton) event.getSource();
if (toggleButton.isSelected()) {
checkBox.setEnabled(false);
multiLineLabel.setEnabled(false);
} else {
checkBox.setEnabled(true);
multiLineLabel.setEnabled(true);
}
}
});
toggleButtonPanel.add(toggleButton);
mainPanel.add(toggleButtonPanel, BorderLayout.SOUTH);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new CheckBoxTest());
}
}

How to remove minimize button and keep maximize and close button in JFrame

I want to remove only minimize button from JFrame
but want maximize and close button in JFrame title bar.
Here I am talking about removing not disabling.
I don't think removing the minimize button is a good thing. But may be you can use the setUndecorated() method to remove the title bar and window edges. And you'll have to add your own close and maximize buttons to perfom those action.
Here is an example :
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.JButton;
public class Example {
public Example() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);//<---- this will disable the frame decorations
JPanel panel = new JPanel();
panel.add(new JLabel("titlebar"));
//Add button maximize
JButton button_max=new JButton("Maximize");
button_max.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if(frame.getExtendedState() == JFrame.NORMAL) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
} else {
frame.setExtendedState(JFrame.NORMAL);
}
}
});
panel.add(button_max);
//Add button close
JButton button_close = new JButton(new AbstractAction("Close") {
private static final long serialVersionUID = -4901571960357967734L;
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
panel.add(button_close);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new Example();
}
}
Edit :
As #peeskillet states in the comment, even with this method the window still can be resized and draged by the user. The ComponentResizer class allows to do that.
Here is a an SO post which gives a good example to use this class with Jframe.
It's a very big hack, which works only with Synthetica L&F because it provides a painted title bar. Note: this L&F is not free to use. So if you use it you must by a license.
When you use this L&F you can iterate over all component starting from root pane to find an instance of SyntheticaTitlePane. On success you can try to access the field iconifyAction using Reflection Framework and use the method Action.setEnabled(false) on it.
I have no idea how to access the standard title bar because it's native. Probably it's impossible.

Java Swing - Problem in disabling JCheckbox

I am disabling a JCheckbox and then enabling it with the help of setEnabled(...) method.
But the problem is if I disable a unselected checkbox, then it becomes selected after I enable it.
I want all of them to have the same state after being enabled that they had before being disabled.
Are you enabling/disabling the JCheckBox using an ActionListener? If so, then that is normal because when you click on the checkbox, the isSelected() status changes.
What you can do is to add checks using isSelected() and the setSelected() methods.
The below code works as you describe:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CheckboxTest implements ActionListener{
private JCheckBox checkbox = new JCheckBox();
private JButton btn = new JButton("Enable");
public CheckboxTest(){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.getContentPane().add(panel);
checkbox.setEnabled(false);
btn.addActionListener(this);
panel.add(checkbox);
panel.add(btn);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args){
new CheckboxTest();
}
public void actionPerformed(ActionEvent e) {
checkbox.setEnabled(!checkbox.isEnabled());
btn.setText(checkbox.isEnabled()?"Disable":"Enable");
}
}
If you call setEnabled that should not affect the selected state. If it is, then I suggest you reexamine your code to see if there is anything that can account for this behaviour. As someone else suggested, maybe if you post a code sample that may be helpful.
Update:
To make it perfectly clear, there are only two ways the selected state of a checkbox can be changed.
A call to setSelected
User clicks on the checkbox
A call to setEnabled does not change the selected state.
Thus, there must be something odd in your code that is causing this.

Categories

Resources