I was making a simple text editor where you can set font style,font size, clear all etc. To set font size I added JComboBox and implemented ItemListener. Here is my MainWindow class:
import javax.swing.*;
public class MainWindow extends JFrame{
Editor e = new Editor();
public MainWindow(){
super(".:My Text Editor:.");
getContentPane().add(e);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new MainWindow();
}
});
}
}
Here is my Editor class:
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class Editor extends JPanel{
JPanel optionPanel = new JPanel();
JTextArea editArea = new JTextArea();
JButton boldBtn = new JButton("Bold");
JButton italicBtn = new JButton("Italic");
JButton plainBtn = new JButton("Plain");
JButton clearBtn = new JButton("Clear all");
String [] fontSizes = {"10","11","12","13","14","15","16","17","18","19","20"};
int fontSize;
JComboBox combo = new JComboBox(fontSizes);
public Editor(){
createUI();
addEvents();
}
public void createUI(){
optionPanel.add(boldBtn);
optionPanel.add(italicBtn);
optionPanel.add(plainBtn);
optionPanel.add(combo);
optionPanel.add(clearBtn);
setLayout(new BorderLayout());
add(optionPanel,BorderLayout.NORTH);
add(new JScrollPane(editArea),BorderLayout.CENTER);
setPreferredSize(new Dimension(640,480));
}
public void addEvents(){
boldBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
editArea.setFont(new Font("Sans Serif",Font.BOLD,fontSize));
}
});
italicBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
editArea.setFont(new Font("Sans Serif",Font.ITALIC,fontSize));
}
});
plainBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
editArea.setFont(new Font("Sans Serif",Font.PLAIN,fontSize));
}
});
combo.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e){
int ind = combo.getSelectedIndex();
System.out.println(ind);
fontSize = Integer.parseInt(fontSizes[ind]);
editArea.setFont(new Font("Sans Serif",Font.PLAIN,fontSize));
}
});
clearBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
editArea.setText("");
}
});
}
}
Now, weird thing what happened is when I put System.out.println(ind); line just to see what index the getSelectedIndex() method returns me. Depending on which item I click, it returns me this:
1
1
0
0
2
2
3
3
Why is this happening? Shouldn't return me just 1 0 2 3? Thanks in advance.
JCombobox fire itemStateChanged twice for SELECTED and DESELECTED that you differentiate with ItemEvent.getStateChanged(). So wrap your code in an if like this:
public void itemStateChanged( ItemEvent event ) {
if( event.getStateChanged() == ItemEvent.SELECTED ) {
// code here
}
}
Whenever you change the selection in a JComboBox, the itemStateChanged event is triggered twice, once for DESELECT of the old selected item and once for SELECT for the new selected item.
If you only want your code to be executed once, just do:
if (e.getStateChange() == ItemEvent.SELECTED) {
...
}
Seems that itemStateChanged is triggered twice. I think that the ItemEvent parameter is not the same each time. Perhaps you should check the event type before doing something.
Sorry I can't check now, but I will do it later if you still need help.
Related
I have a jframe that includes JButton.I have six buttons in this frame, but I don't know how to define action listener for this buttons.please help to solve this problem.
First you have to import the package java.awt.event.* to enable events. After the class name you have to add implements ActionListener so that the class can handle events. When you have created the buttons you have to add an actionlistener to each button. Since you haven't showed which code you use I make an example with a simple program that counts votes, if the user clicks the yesButton the votes are increased with 1 and if the user clicks the noButton the votes are decreased with 1.
Here is the code to add an ActionListener to each button:
yesButton.addActionListener(this);
noButton.addActionListener(this);
Then write the following code to handle the events:
public void actionPerformed(ActionEvent e) {
JButton src = (JButton) e.getSource();
if(src.getActionCommand().equals("Yes")) {
yesCount++;
} else {
noCount++;
}
label.setText("Difference: " + (yesCount - noCount));
}
If you have 6 buttons you need to have an if statement and then 5 "else if" statements instead of only an if and an else statement.
Have a look at the Java tutorials on how to use ActionListeners:
https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
Here's a simple example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Hello extends JPanel implements ActionListener {
JButton button;
public Hello() {
super(new BorderLayout());
button = new JButton("Say Hello");
button.setPreferredSize(new Dimension(180, 80));
add(button, BorderLayout.CENTER);
button.addActionListener(this); // This is how you add the listener
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e) {
System.out.println("Hello world!");
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Hello");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new Hello();
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();
}
});
}
}
buttons have a method called addActionListener, use that for adding the action listener that you can implement for the click...
Example:
dummyButton = new JButton("Click Me!"); // construct a JButton
add(dummyButton); // add the button to the JFrame
dummyButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(" TODO Auto-generated method stub");
}
});
It's really simple.
I suppose you have an instance of your button, right? Let's say that instance is called myButton.
You can just add an action listener by calling addActionListener:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Do whatever you like here
}
});
Protip: next time you don't know what method to call, just type the instance name and .. Then, your IDE will show you all the methods you can call, unless you are not using an IDE. If that is the case, download one.
Like I said the JButton GR is set to the default size (size of window) when I click JButton MN.
When the program is started the JButton GR has the right size (200 by 20), when clicked the menu button appears also at the right size (200 by 20), but when the menu button is clicked the GR JButton is at its default size. When the full size GR JButton is clicked the Menu button reappears with the right size.
I'm using BlueJ (school dose not allow other IDEs).
import java.util.Scanner;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JButton;
public class MAIN
{
public static void main(String args[])
{
ActionClass actionEvent = new ActionClass();
//Main window
JFrame Program1 = new JFrame("Program1");
Program1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Program1.setPreferredSize(new Dimension(800, 600));
Program1.pack();
Program1.setVisible(true);
//menu button (returns to home Menu)
JButton MN = new JButton("MENU");
MN.setBounds(300, 10, 200, 20);
MN.setVisible(false);
Program1.add (MN);
//MN.setActionCommand("1");
// Enter GRC
JButton GR = new JButton("GRC");
GR.setBounds(300, 40, 200, 20);
GR.setVisible(true);
Program1.add (GR);
//GR.setActionCommand("2");
GR.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent GRH)
{
MN.setVisible(true);
GR.setVisible(false);
}
}
);
MN.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent MNH)
{
MN.setVisible(false);
GR.setVisible(true);
}
}
);
}
}
Like you said the Jbutton GR is ...
JFrame has BorderLayout as default LayoutManager in API,
use Java naming conventions
use LayoutManager instead of NullLayout and wrong way
setVisible(true); should be last code line, because your are in risk that all JComponents are added to already visible container (e.g. mouse over repainting those JComponents)
use Initial Thread
simplest as is possible
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.JButton;
public class Main {
private JFrame myProgram1 = new JFrame("myProgram1");
private JButton myMN = new JButton("MENU");
private JButton myGR = new JButton("myGRC");
public Main() {
myGR.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent myGRH) {
myMN.setVisible(true);
myGR.setVisible(false);
}
});
myProgram1.add(myMN, BorderLayout.SOUTH);
myMN.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent myMNH) {
myMN.setVisible(false);
myGR.setVisible(true);
}
});
myProgram1.add(myGR, BorderLayout.NORTH);
myProgram1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myProgram1.pack();
myProgram1.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
}
Well what i'm trying to do is change the text of the JRadioButton's when they're selected, i got them to change the color. I know I can do it by putting the code to change the text inside the dedicated event handling method specific to each button, but how do I do it so that I use A DIFFERENT event handling method that just changes the buttons? I already created one but it doesn't work, here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LessonTwenty extends JFrame implements ActionListener{
JRadioButton b1,b2;
JTextArea t1;
JScrollPane s1;
JPanel jp = new JPanel();
public LessonTwenty()
{
b1= new JRadioButton("green");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jp.setBackground(Color.GREEN);
}
});
b2= new JRadioButton("red");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jp.setBackground(Color.RED);
}
});
//Method to change the text of the JRadion Buttons, what i'm trying to make work
new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(b1.isSelected()){
b1.setText("Welcome");
}
else if(b2.isSelected()){
b2.setText("Hello");
}
}
};
jp.add(b1);
jp.add(b2);
this.add(jp);
setTitle("Card");
setSize(700,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String [ ] args){
new LessonTwenty();
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
if i understand you right, you want do do something like this:
//Method to change the text of the JRadion Buttons, what i'm trying to make work
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(b1.isSelected()){
b1.setText("Welcome");
}
else if(b2.isSelected()){
b2.setText("Hello");
}
}
};
b1= new JRadioButton("green");
b1.addActionListener(al);
b2= new JRadioButton("red");
b2.addActionListener(al);
ie. you define one ActionListener which you use in all your objects.
The anonymous object you define in your original code does absolutely nothing, it just creates an ActionListener which nobody can ever access, since it is not assigned to any Button.
Maybe this could help
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(e.getSource() == b1){
b1.setText("Welcome");
} else if(e.getSource() == b2){
b2.setText("Hello");
}
}
};
I am trying to toggle visibility of a JTextField with a checkbox. If the checkbox is selected I want the JTextField to be displayed and vice-versa. My program works fine until I add the line that initializes the JTextField to be invisible at the start. If I remove this the segment works fine! Can you help me?
final JCheckBox chckbxNewCheckBox_1 = new JCheckBox("New Folder");
panel_3.add(chckbxNewCheckBox_1);
final JTextField textField_3 = new JTextField();
panel_3.add(textField_3);
textField_3.setColumns(20);
//textField_3.setVisible(false); if a comment it in.. it never becomes visible
chckbxNewCheckBox_1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if(chckbxNewCheckBox_1.isSelected()){
textField_3.setVisible(true);
}
else
textField_3.setVisible(false);
}
});
Try with ActionListener instead of MouseListener
checkBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
textField_3.setVisible(checkBox.isSelected());
}
});
--EDIT--
call panel_3.revalidate(); after changing its visibility.
When an element is invisible during container initialization, it never gets its dimensions initialized. You can check it by calling getWidth() and getHeight() on the text area after you set it to visible. They're both zero. So follow #Braj edit and call panel.revalidate() after you change element visibility to let layout manager know that it's time to reposition/recalculate some elements and give them proper size.
You will do better with ItemListener
chckbxNewCheckBox_1.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED))
textField_3.setVisible(false);
else if (e.getStateChange() == ItemEvent.SELECTED))
textField_3.setVisible(true);
textField_3.revalidate();
}
});
Note: pelase follow naming conventions and use underscores only for constants.
Consider calling pack() method
Below is the complete code I experimented with:
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Test {
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
final JCheckBox chckbxNewCheckBox_1 = new JCheckBox("New Folder");
final JPanel panel_3 = new JPanel();
frame.add(panel_3);
panel_3.add(chckbxNewCheckBox_1);
final JTextField textField_3 = new JTextField();
panel_3.add(textField_3);
textField_3.setColumns(20);
textField_3.setVisible(false); //if a comment it in.. it never becomes visible
chckbxNewCheckBox_1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if (chckbxNewCheckBox_1.isSelected()) {
textField_3.setVisible(true);
} else
textField_3.setVisible(false);
frame.pack();
}
});
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I need to display a swing popup with my custom component. The popup should stay visible, until I hide it myself, but shouldn't get focus.
I have a code written by some other developer that does it in the following way:
popupMenu = new JPopupMenu();
popupMenu.add(myCustomComponent, BorderLayout.CENTER);
popupMenu.setFocusable(false);
popupMenu.setVisible(true);
popupMenu.show(parentComponent, x, y);
This seems to work, but has a bug - when the popup is visible, first mouse click outside the component is consumed by the popup. So I need to click twice to set focus to another component.
How can I fix it? Or what is correct way to make the popup?
UPDATE
At last I've managed to reproduce my problem in short code fragment. Thanks to Guillaume Polet for giving me a starting point.
Here's the code:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class TestJPopup {
protected void initUI() {
JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField textField = new JTextField("Some text field");
frame.add(textField, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(200, 100);
frame.setVisible(true);
final JPopupMenu popup = new JPopupMenu();
popup.add(new JLabel("<html>Hey!<br>I'm the popup window!</html>"),
BorderLayout.NORTH);
popup.setFocusable(false);
popup.setVisible(true);
popup.show(textField, 60, 60);
// I want to activate popup when user clicks in the text field
textField.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (popup != null) {
popup.show(textField, 60, 60);
}
}
});
}
public static void main(String[] args) throws Exception {
Class lnfClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsLookAndFeel", true,
Thread.currentThread().getContextClassLoader());
LookAndFeel feel = (LookAndFeel) lnfClass.newInstance();
UIManager.setLookAndFeel(feel);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestJPopup().initUI();
}
});
}
}
Two critical moments:
Windows look and feel used (with default not reproducible)
Mouse listener attached to text field in main frame
Not an answer, but just an example SSCCE in which I can't currently reproduce the behaviour you described. Maybe start from this code, try to reproduce the error and the edit your post with modified non-working code.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TestJPopup {
protected void initUI() {
JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel leftLabel = new JLabel("Left");
frame.add(leftLabel, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(500, 400);
frame.setVisible(true);
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(new JLabel("<html>A Custom<br>component<br>made to<br> simulate <br>your custom component</html>"),
BorderLayout.NORTH);
JTextField textfield = new JTextField(30);
popupMenu.add(textfield);
popupMenu.setFocusable(false);
popupMenu.setVisible(true);
popupMenu.show(leftLabel, 20, 20);
// Let's force the focus to be in a component in the popupMenu
textfield.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestJPopup().initUI();
}
});
}
}
Not a solution, but:
Looks like a bug to me, even a plain componentPopup exhibits the same mis-behaviour (in winLAF and Nimbus, not in Metal):
JTextField field = new JTextField("some popup owner");
JPopupMenu menu = new JPopupMenu();
menu.add("dummy");
field.setComponentPopupMenu(menu);
Action action = new AbstractAction("hit me!") {
#Override
public void actionPerformed(ActionEvent e) {
LOG.info("got hit!");
}
};
JComponent content = new JPanel();
content.add(new JButton(action));
content.add(field);
for quick research and/or for future readers,
this issue is reproducible and presented for,
a) JPopup
b) JMenu
tested on jdk1.6.0_25 and jdk1.7.0_04,
same issue on WinXp and Win7,
for Look and Feel to SystemLookAndFeel / WindowsLookAndFeel,
Here's a possible workaround with JWindow instead of JPopupMenu, that was proposed by mKorbel in comments:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestJPopup {
protected void initUI() {
final JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField textField = new JTextField("Some text field");
frame.add(textField, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(200, 70);
frame.setVisible(true);
final JWindow popup = new JWindow();
popup.getContentPane().add(new JLabel("<html>Hey!<br>I'm the popup window!</html>"),
BorderLayout.NORTH);
popup.setLocation(frame.getLocation().x + 60, frame.getLocation().y + 60);
popup.pack();
popup.setFocusable(false);
popup.setVisible(true);
// I want to activate popup when user clicks in the text field
textField.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if (popup != null) {
popup.setVisible(true);
popup.setLocation(frame.getLocation().x + 60, frame.getLocation().y + 60);
popup.toFront();
}
}
});
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
if (popup != null) {
popup.setVisible(false);
}
}
});
}
public static void main(String[] args) throws Exception {
Class lnfClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsLookAndFeel", true,
Thread.currentThread().getContextClassLoader());
LookAndFeel feel = (LookAndFeel) lnfClass.newInstance();
UIManager.setLookAndFeel(feel);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestJPopup().initUI();
}
});
}
}
Here is the magic line that fixes the problem:
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
I found this after looking into the source code for the BasicPopupMenuUI class. Apparently this behaviour is a deliberate design choice according to the following comments in the code, but it sure feels like a bug to me.
// Ask UIManager about should we consume event that closes
// popup. This made to match native apps behaviour.
By the way, it happens in Java 5 and 6 too.