I want to know how to display loading dialog at center of app screen. An indefinite progress bar.
If you're talking about a JDialog, after calling pack() on it, call setLocationRelativeTo(null) to center it.
Here's how I typically show a "loading..." progress bar. The loading itself must happen on a background thread to make sure the progress bar keeps updating. The frame with the progress bar will be shown in the center of the screen.
public static void main(String[] args) throws Throwable {
final JFrame frame = new JFrame("Loading...");
final JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
final JPanel contentPane = new JPanel();
contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
contentPane.setLayout(new BorderLayout());
contentPane.add(new JLabel("Loading..."), BorderLayout.NORTH);
contentPane.add(progressBar, BorderLayout.CENTER);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Runnable runnable = new Runnable() {
public void run() {
// do loading stuff in here
// for now, simulate loading task with Thread.sleep(...)
try {
System.out.println("Doing loading in background step 1");
Thread.sleep(1000);
System.out.println("Doing loading in background step 2");
Thread.sleep(1000);
System.out.println("Doing loading in background step 3");
Thread.sleep(1000);
System.out.println("Doing loading in background step 4");
Thread.sleep(1000);
System.out.println("Doing loading in background step 5");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// when loading is finished, make frame disappear
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(false);
}
});
}
};
new Thread(runnable).start();
}
display loading dialog at center of app screen.
dialog.setLocationRelativeTo(...);
An indefinite progress bar.
Read the section from the Swing tutorial on How to Use Progress Bars
From the documentation:
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
This will create the progress bar. To center it, you should take a look at the different kinds of layout managers in java.
Without any examples of your existing code, it's hard to give a more precise answer to your question.
Related
I am trying to write an application that get video frames, process them and then display them in JPanel as images. I use the OpenCV library to get video frames (one by one), then they are processed and after that displayed on the screen (to get the effect of playing video).
I created the GUI using Java Swing. A window application is created with the necessary buttons and a panel to display the video. After clicking "START", a method playVideo is called, which takes video frames from the selected video, modifies them and displays them in the panel. My code looks like this:
public class HelloApp {
private JFrame frame;
private JPanel panel;
final JLabel vidpanel1;
ImageIcon image;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
HelloApp window = new HelloApp();
window.frame.setVisible(true);
}
});
}
public void playVideo() throws InterruptedException{
Mat inFrame = new Mat();
VideoCapture camera = new VideoCapture();
camera.open(Config.filename);
while (true) {
if (!camera.read(inFrame))
break;
Imgproc.resize(inFrame, inFrame, new Size(Config.FRAME_WIDTH, Config.FRAME_HEIGHT), 0., 0., Imgproc.INTER_LINEAR);
... processing frame
ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame)); // option 0
vidpanel1.setIcon(image);
vidpanel1.repaint();
}
}
public HelloApp() {
frame = new JFrame("MULTIPLE-TARGET TRACKING");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);//new FlowLayout()
frame.setResizable(false);
frame.setBounds(50, 50, 800, 500);
frame.setLocation(
(3 / 4) * Toolkit.getDefaultToolkit().getScreenSize().width,
(3 / 4) * Toolkit.getDefaultToolkit().getScreenSize().height
);
frame.setVisible(true);
vidpanel1 = new JLabel();
panel = new JPanel();
panel.setBounds(11, 39, 593, 371);
panel.add(vidpanel1);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("START / REPLAY");
btnStart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
playVideo();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
});
}
}
I tried to delete the old panel and create a new one every time when button "START" is clicked, but it didn't work. Also I tried before running method playVideo to clean all the panel with methods:
panel.removeAll();
panel.repaint();
playVideo();
And to be honest I don't know what's wrong. The GUI is created, frames are taken and processed, but the panel displays only the last frame. I would be grateful for any advice :)
First of all, a proof it can actually work, somehow, with your code.
Here I read JPG images located in the resources folder, but it actually doesn't really matter.
Your code is a bit messy too. Where are you attaching the btnStart JButton to the outer panel? You need to understand how to layout components too.
You have a main JFrame, and a root JPanel which needs a layout. In this case we can opt for a BorderLayout.
panel = new JPanel(new BorderLayout());
Then we add our components.
panel.add(btnStart, BorderLayout.PAGE_START);
panel.add(vidpanel1, BorderLayout.CENTER);
Now coming to your issue, you say
The gui is created, frames are taken and processed, but panel display only the last frame
I don't know how much the "last frame" part is true, mostly because you're running an infinite - blocking - loop inside the Event Dispatch Thread, which will cause the GUI to freeze and become unresponsive.
In actionPerformed you should actually spawn a new Thread, and inside playVideo you should wrap
ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame));
vidpanel1.setIcon(image);
vidpanel1.repaint(); // Remove this
in EventQueue.invokeAndWait, such as
// Process frame
...
// Update GUI
EventQueue.invokeAndWait(() -> {
ImageIcon image = new ImageIcon(Functions.Mat2bufferedImage(inFrame));
vidpanel1.setIcon(image);
});
I have a JFrame containing various components and I would like to add a translucent grey overlay over the top while the application is initializing various things. Ideally it would prevent interaction with the underlying components and would be able to display some "Loading..." text or a spinning wheel or something similar.
Is there a simple way to do this using Java and Swing?
Take a look at JRootPane and JLayeredPane http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#layeredpane
What you're asking about specifically sounds like a Glass Pane.
http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
The Glass Pane prevents interaction with underlying components and can be used to display something on top of your JFrame.
As #David said, you can use the glass pane for displaying some loading text or image above the rest of the application.
As for the grey overlay: why don't you use the built in ability to disable components as long as your application is loading? Disabled components will get grayed out automatically and cannot be interacted with by the user.
Something like this:
public class LoadingFrame extends JFrame{
JButton button;
public LoadingFrame() {
button = new JButton("ENTER");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Application entered");
}
});
setLayout(new BorderLayout());
add(button, BorderLayout.CENTER);
}
public void startLoading(){
final Component glassPane = getGlassPane();
final JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
final JLabel label = new JLabel();
panel.add(label, BorderLayout.SOUTH);
setGlassPane(panel);
panel.setVisible(true);
panel.setOpaque(false);
button.setEnabled(false);
Thread thread = new Thread(){
#Override
public void run() {
for (int i = 5; i > 0; i--) {
label.setText("Loading ... " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// loading finished
setGlassPane(glassPane);
button.setEnabled(true);
}
};
thread.start();
}
public static void main(String[] args) {
LoadingFrame frame = new LoadingFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.startLoading();
frame.setVisible(true);
}
}
I am creating my own dialog which is basically a JPanel set as the glasspane on a JFrame. I want to make my dialog modal in the sense that all the code after the setVisible() is not executed while the dialog is visible and once the dialog is closed, the rest of the code after the setVisible() must continue.
To achieve this I am using a thread to display my dialog. I know that the SwingUtilities.invokeLater() method must be used to update the gui because it is executed in another thread. However my dialog does not show on the screen.
Here is my code example:
final JFrame frame = new JFrame();
frame.setBounds(0, 0, 1024, 768);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton button = new JButton("Text");
button.setBounds(200, 300, 110, 50);
button.addActionListener(new ActionListener() {
boolean dispose;
public void actionPerformed(ActionEvent e) {
try {
Thread thread = new Thread(new Runnable() {
public void run() {
final JPanel panelGlass = new JPanel(null);
panelGlass.setBounds(frame.getBounds());
panelGlass.setBackground(Color.red);
frame.setGlassPane(panelGlass);
JButton btnClose = new JButton("close");
btnClose.setBounds(100, 100, 110, 50);
btnClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose = true;
}
});
panelGlass.add(btnClose);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
dispose = false;
panelGlass.setVisible(true);
}
});
while (!dispose) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
panelGlass.setVisible(false);
}
});
thread.start();
thread.join();
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
frame.getContentPane().add(button);
frame.setVisible(true);
Why is my dialog not shown?
The problem is here:
thread.start();
thread.join();
You start the thread but you immediately wait for it to finish. This blocks the UI thread and doesn't allow it to process your SwingUtilities.invokeLater update.
I really don't see any good reason for that join call to exist.
You can't do that like that since
you're accessing Swing components from a thread other than the event disptach thread
the event disptach thread, where all the UI painting happens, is completely blocked by the call to Thread.join().
You should be able to do something like what you want with Java 7's SecondaryLoop, but I've never used it.
frame.getRootPane.setGlassPane
your idea is good, but have to consume() events came from keyboard, add there KeyListener only with e.consume() because GlassPane to consume only mouse events
create whole Gui with GlassPane too,
inside actionperformed to show prepared GlassPane, then to start a Runnable.Thread
I have one question here about multiply glasspane
use JLayer Java7, based on JXLayer Java6
your question is booking example for why reason is SwingWorker implemented in Java
reply from cellphone
I have been trying to understand how to add a progress bar, I can create one within the GUI I am implementing and get it to appear but even after checking through http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html I am still no clearer on how I can set a method as a task so that I can create a progress bar for running a method. Please can someone try to explain this to me or post an example of a progress bar being used in the GUI with a task being set as a method. Thanks.
Maybe I can help you with some example code:
public class SwingProgressBarExample extends JPanel {
JProgressBar pbar;
static final int MY_MINIMUM = 0;
static final int MY_MAXIMUM = 100;
public SwingProgressBarExample() {
// initialize Progress Bar
pbar = new JProgressBar();
pbar.setMinimum(MY_MINIMUM);
pbar.setMaximum(MY_MAXIMUM);
// add to JPanel
add(pbar);
}
public void updateBar(int newValue) {
pbar.setValue(newValue);
}
public static void main(String args[]) {
final SwingProgressBarExample it = new SwingProgressBarExample();
JFrame frame = new JFrame("Progress Bar Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(it);
frame.pack();
frame.setVisible(true);
// run a loop to demonstrate raising
for (int i = MY_MINIMUM; i <= MY_MAXIMUM; i++) {
final int percent = i;
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
it.updateBar(percent);
}
});
java.lang.Thread.sleep(100);
} catch (InterruptedException e) {
;
}
}
}
}
Your question is a bit vague, but it sounds to me like you want the progress bar to show progress for a specific running method, which I'll call the "work()" method. Unfortunately, there's no way to just pass a reference to your method to a progress bar - your method needs to explicitly tell the progress bar what to display. Here's what I would do:
Make the progress bar's reference available to work() - either pass it in as an argument to work(), or provide an accessor method that your code in work() can call to get a reference to the progress bar.
Inside work(), after you've obtained a reference to the progress bar (which I'll call "pb", call pb.setMinimum(0) and pb.setMaximum(n) where n is the number of steps your method has to get through.
As your method completes each step, call pb.setValue(pb.getValue()+1);
At the end of your method, call pb.setValue(0); to reset the progress bar prior to returning.
Also, if you want your progress bar to display a String message, you first have to call pb.setStringPainted(true), then subsequent calls to pb.setString(string) will show up on the progress bar.
See my answer on another SO question which includes an example of a JProgressBar which gets updated by using a SwingWorker. The SwingWorker is used to execute a long running task in the background (in case of the example it is just a regular Thread.sleep) and report on progress at certain intervals.
I would also strongly suggest to take a look at the Swing concurrency tutorial for more background info on why you should use a SwingWorker when performing long-running tasks which interfere with the UI.
A similar example as the one I posted is available in the Swing tutorial about JProgressBars, which it also worth looking at
How about this,
JFrame->JButton (BorderLayout.NORTH)
JFrame-> JPanel->JProgressBar (BorderLayout.SOUTH)
You can add button part where ever you like, for example when Progress progress = ...; state=true; progress.waitFor(); state=false;
private static void daa() {
//Frame
JFrame frame = new JFrame("Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setSize(frame.getWidth() + 55, frame.getHeight() + 55);
//Button
JButton jButton = new JButton("State");
frame.add(jButton, BorderLayout.NORTH);
//Progress Bar
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
//Text for progress bar
JPanel panel = new JPanel(new BorderLayout());
panel.add(progressBar);
panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);
//linking
panel.add(progressBar);
frame.add(panel, BorderLayout.SOUTH);
boolean[] state = {false};
jButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
state[0] = !state[0];
state();
}
private void state() {
if (state[0] == true) {
panel.hide();
} else {
panel.show();
}
}
});
}
I have following java code in my thread class:
#Override
public void run() {
JFrame window = new JFrame("Visualization POC");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
window.setVisible(false);
Layout<Node,Edge> layout = new CircleLayout<Node, Edge>(graph);
layout.setSize(new Dimension(300, 300));
BasicVisualizationServer<Node, Edge> vv = new BasicVisualizationServer<Node, Edge>(layout);
vv.setPreferredSize(new Dimension(350, 350));
vv.getRenderContext().setVertexFillPaintTransformer(new NodeColorTransformer());
vv.getRenderContext().setEdgeDrawPaintTransformer(new EdgeColorTransformer());
window.getContentPane().add(vv);
window.pack();
window.setVisible(true);
try {
Thread.sleep(ONE_SECOND);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I want to use it to refresh state of graph visualization, but I got stuck on massive problem. When the block of code creating layout and setting content of JFrame is inside while loop it is not displayed in output window. When I place it before while, it works fine but it isn't that what I want. I run this thread via SpringUtilities.invokeLater in my main class.
I can see that the window is refresh, because it is blinking for a while.
I'm looking forward for any tips.
You invoke your code from EDT thread. Any update to the component will be painted at the end of the EDT thread. Your thread will not exit
I have modified your code little, it works fine. please replace JLabel with your jung .
final JFrame window = new JFrame("Visualization POC");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Random ran = new Random();
while (true) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
window.setVisible(false);
JPanel panel = new JPanel();
JLabel label = new JLabel();
int nextInt = ran.nextInt(100);
label.setText("Test Label"+String.valueOf(nextInt));
System.out.println(nextInt);
panel.add(label);
window.getContentPane().removeAll();
window.getContentPane().add(panel);
window.pack();
window.setVisible(true);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}