So I want to make some kind of a JLabel that will appear and disappear after a few seconds once certain components are clicked. I used Swing Timer.
Here is my method which is handling this JLabel
`
public void Clicked(String dialog) {
if(isStarted == true) { //Checking if any other component is clicked
dialogue.setText(dialog);// setting text to the label which is the method argument
}
isStarted = false;
t = new Timer(2500,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialogue.setText("");// disappearing the label after 2.5 seconds
}
});
t.start();
t.setRepeats(false);
isStarted = true;
}
`
It actually works fine but when I click 2 components at once, it kinda starts acting weirdly.
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Concurrency in Swing section.
We don't make a JLabel disappear. We change the text of the JLabel to blank.
I created a simple GUI to demonstrate how to use Swing Timers.
After you press the "Display" JButton, the following text is displayed.
After 2.5 seconds, the following text is displayed.
After 2.5 seconds, the text is cleared.
The "trick" is setting a boolean in the original ButtonListener that causes the actionPerformed method to ignore repeated JButton presses. The entire process runs from start to finish no matter how many times you press the JButton while the process is running.
Here's the complete runnable code. I made the additional class an inner class so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class DisappearingJLabelGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DisappearingJLabelGUI());
}
private JLabel textLabel;
#Override
public void run() {
JFrame frame = new JFrame("Disappearing JLabel GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
textLabel = new JLabel(" ");
panel.add(textLabel);
JButton button = new JButton("Display");
button.addActionListener(new ButtonListener());
panel.add(button);
return panel;
}
public class ButtonListener implements ActionListener {
private boolean isRunning;
public ButtonListener() {
this.isRunning = false;
}
#Override
public void actionPerformed(ActionEvent event) {
if (!isRunning) {
isRunning = true;
textLabel.setText("Now, you see it.");
Timer timer = new Timer(2500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
Timer timer = (Timer) event.getSource();
timer.stop();
textLabel.setText("Now, you don't.");
timer = new Timer(2500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
Timer timer = (Timer) event.getSource();
timer.stop();
textLabel.setText(" ");
isRunning = false;
}
});
timer.start();
}
});
timer.start();
}
}
}
}
Related
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();
}
});
}
}
I want to use the text property in the button property field. this is the code i have tried but it does not work.
private void btnOneActionPerformed(java.awt.event.ActionEvent evt) {
String btnOneText = btnOne.getText( );
txtDisplay.setText(btnOneText);
}
I suggest you to read the oracle official tutorials that have good examples. How to use Buttons.
I made you an example of what you have to do.
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.JTextField;
public class TextFieldTest {
private JPanel panel;
public TextFieldTest(){
panel = new JPanel();
final JTextField textfield = new JTextField(10);
final JButton button = new JButton("Press me");
//here i add the action listener, that will listen the input event
button.addActionListener(new ActionListener(){
//this is anonymous class
#Override
public void actionPerformed(ActionEvent evt){
String text = button.getText();
textfield.setText(text);
}
});
panel.add(textfield);
panel.add(button);
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Textfield example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(Boolean.TRUE);
frame.add(new TextFieldTest().panel);
//Display the window.
frame.pack();
frame.setVisible(Boolean.TRUE);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
See it's more simpler than using a gui-editor, then you understand what you do. It's better to do this first and later when you understand what you are doing use the netbeans gui-editor.
I have a JFrame, and whenever I switch from one JFrame using a JButton it starts out normally, but whenever I create a new instance of the first JFrame, the JButton is in an incorrect location and is the wrong size.
Example on startup
and when another one is created
Code:
public class Menu extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
public static int Number_of_Participants = 0;
protected JPanel window = new JPanel();
double p;
private JButton Participants;
private Rectangle rParticipants;
protected int Button_width = 240;
protected int Button_height = 48;
boolean running = false;
Thread thread;
JFrame frame = new JFrame();
public Menu() {
window.setBackground(Color.BLUE);
frame.setSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().add(window);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Image image = null;
try {
image = ImageIO.read(new File("res/BG.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
generateFiles();
drawButtons();
startMenu();
frame.repaint();
}
public void drawButtons() {
rParticipants = new Rectangle(520, 12, Button_width, Button_height);
Participants = new JButton("A");
Participants.setBounds(rParticipants);
window.add(Participants);
Participants.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.dispose();
new Participant(Number_of_Participants);
}
});
}
}
Participant.java extends Menu.java
int Participant_ID;
public Participant(int Participant_ID) {
super();
this.Participant_ID = Participant_ID;
}
makes a JButton that goes back to Menu.java
As mentioned in the comment, your problem is most likely related to the call to setVisible(true). This should always be the LAST call in the constructor. Particularly, it should only be called AFTER all components have been added to the frame.
Apart from that, from the code that you posted, it seems like you want to switch through a seqence of frames, starting with a "main" menu, and then going through one frame for each "Participant". This intention could already be considered as questionable, because closing and disposing a JFrame just in order to create a new one does not seem to be very elegant. Most likely, a more elegant solution would be possible with a CardLayout : http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html
However, some general hints:
Create the GUI on the Event Dispatch Thread
Don't extend JFrame. Instead, create a JFrame and fill it as needed
Don't implement Runnable with your top level class
Obey the standardJavaNamingConventions!
Don't try to do manual layouts with setBounds
This code is still not "beautiful", but at least shows how the goal of switching through several frames might be achieved, taking into account these points
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Window;
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.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MenuExample
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JPanel mainMenuPanel = new MainMenuPanel();
createAndShowFrame(mainMenuPanel);
}
});
}
static void createAndShowFrame(JPanel panel)
{
JFrame frame = new JFrame();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(800, 600));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static JButton createNextParticipantButton(
final JComponent container, final int nextID)
{
JButton nextParticipantButton = new JButton("New Participant");
nextParticipantButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
Window window =
SwingUtilities.getWindowAncestor(container);
window.dispose();
ParticipantPanel participantPanel =
new ParticipantPanel(nextID);
createAndShowFrame(participantPanel);
}
});
return nextParticipantButton;
}
}
class MainMenuPanel extends JPanel
{
public MainMenuPanel()
{
setBackground(Color.BLUE);
add(MenuExample.createNextParticipantButton(this, 0));
}
}
class ParticipantPanel extends JPanel
{
private final int participantID;
public ParticipantPanel(int participantID)
{
this.participantID = participantID;
add(new JLabel("Add the contents for participant "+participantID));
add(MenuExample.createNextParticipantButton(this, participantID+1));
}
}
So I have a JPanel with a CardLayout.
this CardLayout, as expected, manages the switching of panels in the frame.
The switching is done by two buttons: "Back" and "Next".
I want to know if there is a way to close the whole application (i.e. call System.exit(0)) when it is on the last card and "Next" is pressed again.
I have looked for a solution everywhere, but I can't find anything.
The problem is: I don't know how to check which is the last one.
Here is the listener excerpt of my code:
public void actionPerformed(ActionEvent arg0) {
CardLayout l = (CardLayout) holder.getLayout();
if(arg0.getSource() == opt[1]){ //opt[1] is the "Next" button
//Insert if statement here to check if
//the CardLayout is on the last card
{
System.exit(0);
} else {
l.next(holder); //holder is the JPanel with the CardLayout
}
}
}
What about dispose() which is inherited from Window? Make sure you set:
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JFrame frame = ...
// ...
frame.setVisible(false); // hide the GUI
frame.dispose(); // destroy and release the GUI resources
For example:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CardLayoutGUI
{
private JFrame frame;
private JButton btnBack;
private JButton btnNext;
private CardLayout cLayout;
private JPanel panUp;
private JPanel panDown;
private static final String[] cards =
{"card1", "card2", "card3", "card4", "card5"};
private int currentCard = 0;
public void init()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
((JPanel)frame.getContentPane()).setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
btnBack = new JButton("Back");
btnNext = new JButton("Next");
btnBack.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
btnNext.setText("Next");
currentCard--;
cLayout.show(panUp, cards[currentCard]);
if(currentCard == 0) btnBack.setVisible(false);
}
});
btnNext.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
btnBack.setVisible(true);
currentCard++;
if(currentCard == cards.length - 1) // last card
{
btnNext.setText("Exit");
cLayout.show(panUp, cards[currentCard]);
}
else if(currentCard >= cards.length)
{
frame.setVisible(false);
frame.dispose();
}
else
{
cLayout.show(panUp, cards[currentCard]);
}
}
});
cLayout = new CardLayout();
panUp = new JPanel(cLayout);
panDown = new JPanel();
frame.add(panUp, BorderLayout.CENTER);
frame.add(panDown, BorderLayout.SOUTH);
panDown.add(btnBack);
panDown.add(btnNext);
for(int i = 0; i < cards.length; i++) createPanels(panUp, cards[i]);
frame.pack();
frame.setLocationRelativeTo(null);
btnBack.setVisible(false);
}
public void showGUI()
{
frame.setVisible(true);
}
private void createPanels(JPanel container, String label)
{
JPanel pan = new JPanel();
pan.add(new JLabel(label));
container.add(pan, label);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
CardLayoutGUI clg = new CardLayoutGUI();
clg.init();
clg.showGUI();
}
});
}
}
I extended CardLayout to add a few features. One of the features is an isNextCardAvailable() method. See Card Layout Focus for all the features.
The issue is determining which card is the last one. You could use a card String array index to manage the current position of the and use the show method to display the next "card". When you exceed the card array index you can then dispose your JFrame.
If you run the System.exit(0), that close all aplication, but if you only close the JFrame you can use JFrameObject.dispose().
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.