How to make sure Swing UI is actually displayed on screen? - java

When I click on button another JFrame class is getting opened. The JFrame will be visible on the screen after 2 seconds but the isVisible returns true before that. I want to start timer when the JFrame actually getting displayed on the screen. How can I achieve this ? I tried to used isShowing() and isDisplayable() but it's not giving expected result.

You could use something like this:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class MainApp {
JFrame frame = new JFrame("Main");
JButton button = new JButton("Toggle auxiliary");
JFrame auxFrame = new JFrame("Auxiliary");
public MainApp() {
button.addActionListener(evt -> {
// Delay displaying for 2 seconds
Timer timer = new Timer(2000, event -> {
auxFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
auxFrame.setSize(320, 240);
auxFrame.setVisible(true);
});
timer.start();
auxFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
// Stop timer after the auxiliary frame is displayed
timer.stop();
}
});
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(320, 240);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(MainApp::new);
}
}

Related

Make a JLabel disappear after a few seconds in java

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();
}
}
}
}

Weird Issue with JComponent Visibility

I am working on a GUI project with Swing in Java and the program is generally working fine. However, under each screen, I have a back button that calls the method of the screen before it and goes through the ArrayList containing all of the elements on the current screen and calls setVisible(false) on them. Upon running the program, the back button works correctly if you click it once but if you go back on the screen, and click it again, it takes two clicks for it to correctly work and then four clicks and then eight clicks and so on. I have no idea what is going on or why it is behaving this way as nothing in my code seems to do it. Also, sometimes, the button correctly returns to the previous screen but then keeps the components on the current screen active as if setVisible(false) was never called. The following code represents the general structure of my project. Is there anything that it is doing that is generating this problem?
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MAIN {
static JFrame frame;
static JPanel panel;
public static void main(String [] args) {
mainScreen();
}
public static void mainScreen() {
JButton newScreen = new JButton("Next Screen");
frame = new JFrame();
panel = new JPanel();
panel.setBounds(0,0,1920,1080);
panel.setBackground(Color.cyan);
newScreen.setBounds(50, 500, 100, 500);
newScreen.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
newScreen.setVisible(false);
JButton returnButton = new JButton("return");
returnButton.setBounds(50, 50, 100, 100);
panel.add(returnButton);
returnButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
returnButton.setVisible(false);
mainScreen();
}
});
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(newScreen);
frame.add(panel);
frame.setSize(1920,1080);
frame.setLayout(null);
frame.setVisible(true);
}
}

How to hide a JPopupMenu by pressing a button?

I'm making a program that has a popup menu with two buttons, one of which should close the popup menu, but I have no idea how to do that and googling hasn't gone too well.
I've tried using popup.hide() but then the menu wouldn't come back, despite doing so when I tried just moving the popup. It also required me to put a SuppressWarning in that case and it took a few seconds for it to close at all. Is there any better way of doing it?
I'm not sure what kind of code is relevant, but here's the relevant buttons and their roles in this(I skipped all the creating the GUI parts that didn't seem relevant, everything looks good and I know that the buttons are working):
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
interface CustomButton {
JButton create();
void react(JPopupMenu popup, JFrame frame);
}
class ErrandsButton implements CustomButton {
private JButton errands = new JButton("Errands");
public JButton create() {
return errands;
}
public void react(JPopupMenu popup, JFrame frame) {
errands.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
popup.show(frame, 120, 65);
}
});
}
}
class Test {
static JFrame frame = new JFrame("List");
static CustomButton errands = new ErrandsButton();
static JButton cancelTask = new JButton("Cancel");
static JPopupMenu popup = new JPopupMenu();
static void cancelTask() {
cancelTask.addActionListener(new ActionListener() {
#SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e) {
popup.hide();
}
});
}
public static void main(String args[]) {
createInterface();
cancelTask();
errands.react(popup, frame);
}
static void createInterface() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JPanel popup1 = new JPanel();
JPanel button = new JPanel();
popup1.add(cancelTask);
popup.add(popup1);
frame.add(popup);
button.add(errands.create());
frame.getContentPane().add(BorderLayout.CENTER, button);
frame.setVisible(true);
}
}
Use popup.setVisible(true) and popup.setVisible(false).
frame.add(popup); is the problem. Do not add a JPopupMenu to a Container. Instead, use setComponentPopupMenu.
Alternatively, you could do the work yourself by adding a MouseListener whose mousePressed, mouseReleased and mouseClicked methods call isPopupTrigger and show. (It is vital that you do this in all three of those methods—different platforms have different conditions for showing popup menus.)
But really, using setComponentPopupMenu is easier.

How would I refresh this panel

I want to make a kind of digital clock which you can activate by using enter to kind of refresh the clock display, for that I use this method:
private static void GUI(String time, int action){
JLabel textLabel = new JLabel(time);
JPanel panel = new JPanel();
JFrame enterMessage = new JFrame("Tester");
if (action == 1){
enterMessage.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
enterMessage.setSize(190, 80);
enterMessage.setVisible(true);
panel.setBackground(Color.WHITE);
panel.add(textLabel);
enterMessage.add(panel);
}else {
System.out.printf("Refresh");
panel.revalidate();
enterMessage.revalidate();
panel.repaint();
enterMessage.repaint();
}
}
}
This method gets called twice in the program code: one time to make the GUI upon opening the program and everytime an enterpress is detected to refresh it. I searched on internet how to refresh a JPanel and I found that you needed to use revalidate(); and then repaint(); but it does not refresh the time displayed by the panel. How would I refresh it?
ps:the time is passed from the main as a string and everytime an enterpress is detected gets overwritten and passed
Follow Java naming conventions. Variable names should NOT start with an upper case character.
Don't keep adding the label to the panel. Just use the setText(...) method of JLabel to change the text being displayed.
Edit:
An example of a SSCCE that shows you how to use the setText(...) method:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class TimerTime extends JPanel implements ActionListener
{
private JLabel timeLabel;
public TimerTime()
{
timeLabel = new JLabel( new Date().toString() );
add( timeLabel );
Timer timer = new Timer(1000, this);
timer.setInitialDelay(1);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e)
{
//System.out.println(e.getSource());
timeLabel.setText( new Date().toString() );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("TimerTime");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TimerTime() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

JFrame and visibility: issue with fading out and getting a screenshot

In an action (i.e. a method) executed by pressing a button deployed into a JFrame, I want to hide the java app and then to get a screenshot. Finally, once the screenshot is taken, I need to make the JFrame visible.
The method is the following:
public void myButtonPressedAction(){
//Hiding the JFrame
this.setVisible(false);
//Now I use Robot to get a screenshot using another method
//not reported for simplicity
myMethodToGetScreenshot();
//Making the JFrame visible
this.setVisible(true);
}
What happens is that, once visibility is set to false, the app starts to become invisible and immediately I get the screenshot: unfortunately, the screenshot also capture the JFrame while fading out (i.e., it is going to become invisible, the isVisible method returns true, but the JFrame is not completely invisible).
One possible solution is to insert a timer to put a delay between the call to setVisible(false) and the one to myMethodToGetScreenshot(). However, suppose that the system is busy, the delay could be undervalued; on the contrary, a larger delay will make my application slow!
How can I get the exact time instant such that the JFrame has been completely fade out, i.e. it is really invisible?
EDIT
This are initialized in the constructor:
String myPath= ...;//here I have a String that represent a path to a folder.
JPEGImageWriteParam JPEG_PARAMS_BEST_QUALITY = new JPEGImageWriteParam(null);
JPEG_PARAMS_BEST_QUALITY.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
JPEG_PARAMS_BEST_QUALITY.setCompressionQuality(1f);
This is the code for myMethodToGetScreenshot():
public void myMethodToGetScreenshot(){
BufferedImage capture = new Robot().createScreenCapture(screenArea);
ImageWriter writer = writerService.getWriter();
writer.setOutput(new FileImageOutputStream(new File(myPath+"screenshot.jpg")));
writer.write(null, new IIOImage(capture, null, null), JPEG_PARAMS_BEST_QUALITY);
}
This is the screenshot I get. You can see the JFrame fading out...
Then put some delay time. You can use Swing timer.
Here is a small demo:
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ScreenshotDemo {
JFrame frame = new JFrame();
JButton button = new JButton("Catch the screenshot");
Timer timer;
Robot robot;
JLabel label = new JLabel();
public ScreenshotDemo() {
try {
robot = new Robot();
} catch (AWTException e1) {
e1.printStackTrace();
}
// Keeps frame disposed for 3 seconds
timer = new Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle size = new Rectangle(Toolkit.getDefaultToolkit()
.getScreenSize());
Image image = robot.createScreenCapture(size);
label.setIcon(new ImageIcon(image));
frame.setVisible(true);
}
});
timer.setRepeats(false);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
frame.setVisible(false);
timer.start();
}
});
frame.add(button, BorderLayout.NORTH);
frame.add(label, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// frame.pack();
frame.setSize(1024, 768);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ScreenshotDemo();
}
});
}
}
Basically, you will hide your frame for some time (3 seconds in this demo). While frame is hidden you will take a snapshot.
Instead of setvisible you can use setExtendedState
//Minimize the JFrame
this.setExtendedState(JFrame.ICONIFIED);
//Now I use Robot to get a screenshot using another method
//not reported for simplicity
myMethodToGetScreenshot();
//Restore the JFrame
this.setExtendedState(JFrame.NORMAL);
You have to add a reasonable delay after hiding the frame and before taking the screenshot. Easiest way is to insert a call to robot.delay() before robot.createScreenCapture().
I'd give the ComponentListener a try (assuming this code goes to a member of a JFrame-extending class):
final Container contentPane = getContentPane();
ComponentAdapter componentAdapter = new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent arg0) {
myMethodToGetScreenshot();
contentPane.removeComponentListener(this);
}
};
contentPane.addComponentListener(componentAdapter);

Categories

Resources