i got a problem with my SplashScreen not showing up, but running in the background..
Heres my Code, taken from this tutorial (hope it ok to post the link?!?) :
SplashScreen Class:
public final class SplashScreen extends JWindow {
BorderLayout borderLayout1 = new BorderLayout();
JLabel imageLabel = new JLabel();
JPanel southPanel = new JPanel();
FlowLayout southPanelFlowLayout = new FlowLayout();
JProgressBar progressBar = new JProgressBar();
ImageIcon imageIcon;
public SplashScreen(ImageIcon imageIcon) {
this.imageIcon = imageIcon;
try {
jbInit();
}
catch(Exception ex) {
}
}
// note - this class created with JBuilder
void jbInit() throws Exception {
imageLabel.setIcon(imageIcon);
this.getContentPane().setLayout(borderLayout1);
southPanel.setLayout(southPanelFlowLayout);
southPanel.setBackground(Color.BLACK);
this.getContentPane().add(imageLabel, BorderLayout.CENTER);
this.getContentPane().add(southPanel, BorderLayout.SOUTH);
southPanel.add(progressBar, null);
this.pack();
}
public void setProgressMax(int maxProgress)
{
progressBar.setMaximum(maxProgress);
}
public void setProgress(int progress)
{
final int theProgress = progress;
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressBar.setValue(theProgress);
}
});
}
public void setProgress(String message, int progress)
{
final int theProgress = progress;
final String theMessage = message;
setProgress(progress);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressBar.setValue(theProgress);
setMessage(theMessage);
}
});
}
public void setScreenVisible(boolean b)
{
final boolean boo = b;
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
setVisible(boo);
}
});
}
private void setMessage(String message)
{
if (message==null)
{
message = "";
progressBar.setStringPainted(false);
}
else
{
progressBar.setStringPainted(true);
}
progressBar.setString(message);
}
}
In my Main() I start the SplashScren like this:
SplashScreen initscreen;
ImageIcon myImage = new ImageIcon(FilterConfiguratorJFrame.class.getResource("/images/logo.png"));
initscreen = new SplashScreen(myImage);
initscreen.setLocationRelativeTo(null);
initscreen.setProgressMax(100);
initscreen.setScreenVisible(true);
Then I set the progress like this:
initscreen.setProgress("...loading Projects" , 40);
Then my program is loading Projects via a VPN from a Server at work.
Till here i dont get any errors, but the SplashScreen isn't showing up...
I have a OptionPane showing up when theres no connection to the server, and when THIS OptionPane is showing up the SplashScreen does to. When i click "OK" on the OptionPane it disappears, and so does the SplashScreen...
I tried it, and the SplashScreen shows up no matter when or where i let an OptionPane show...
So my Question is, how do i force the SplashScreen into the foreground?
I want the SplashScreen to show up on startup and updating its progressbar while different data ist loaded from the Database (which can last 1-2 minutes).
EDIT: Tried to force the SplashScreen to show by showinf a JFrame, doesn' work, seems like ist only working with OptionPanes.
Related
I am trying to show a progress bar while I do some tasks on a database. The Progress bar, however, freezes and the Things I want to do on the database aren't executed. I understand that, in order to guarantee proper concurrency in Swing I need to do the database tasks on a secondary thread. I also understand that somehow my bug has to do with JOptionPane. But I can't come up with a solution to fix it. Here is the Code for my Progress Dialog:
public class ProgressDialog extends JDialog {
/**
*
*/
private static final long serialVersionUID = 1L;
public ProgressDialog() {
setModal(true);
setTitle("Fortschritt");
setSize(200, 100);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JProgressBar pb = new JProgressBar();
pb.setIndeterminate(true);
pb.setValue(0);
add(pb);
setVisible(true);
}
}
And here is the Code where I call this constructor:
int result = JOptionPane.showConfirmDialog(GUIAutoTest.jtable,
"Schaden mit Testkonfig = " + index + " anlegen ?", "Bestätigen",
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
new SwingWorker<Void, Void>() {
final ProgressDialog pd = new ProgressDialog();
#Override
protected Void doInBackground() throws Exception {
InitTestLauf itl;
try {
itl = new InitTestLauf(index);
StartTestLauf stl = new StartTestLauf(itl.getIdTstLauf());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void done() {
System.out.println("done");
pd.setVisible(false);
}
}.execute();
JOptionPane.showMessageDialog(GUIAutoTest.jtable,
"Schaden angelegt. " + "Schadennummer: " + StartTestLauf.getSchadenNr(),
"Schaden angelegt", JOptionPane.PLAIN_MESSAGE);
It doesn't matter, what happens inside the doInBackground()-block , not even System.out.println("print something") does work. Where is my mistake ?
Thanks in advance!
I made an example that uses a progress bar with a dialog and a swingworker.
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import java.util.List;
/**
* Created on 13.06.17.
*/
public class DialogJunker {
static class ProgressDialog extends JDialog {
JProgressBar bar;
ProgressDialog(){
setModal(true);
bar = new JProgressBar();
add(bar);
pack();
}
void setProgress(int i){
bar.setValue(i);
}
}
public static void main(String[] args){
JFrame frame = new JFrame("diddly dialog");
JButton button = new JButton("start");
button.addActionListener(evt->{
ProgressDialog log = new ProgressDialog();
new SwingWorker<Void, Integer>(){
#Override
public Void doInBackground(){
for(int i = 0; i<100; i++){
try{
Thread.sleep(10);
publish(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
public void done(){
log.setVisible(false);
log.dispose();
}
#Override
protected void process(List<Integer> ints){
log.setProgress(ints.get(0));
}
}.execute();
log.setVisible(true);
});
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
This example will show a dialog with a progress bar that gets updated, then close the dialog when finished.
After reviewing you code a little more, I do see the problem. You are constructing the ProgressDialog in the SwingWorker class, but you set your progress dialog to visible, which blocks. Take note that I have solved quite a few issues.
I call set visible after starting the swing worker.
I publish the results so that the dialog actually gets updated.
I keep a reference to the progress bar, so it actually can be updated.
I'm quite new on JAVA, and i have a question (i hope my english is not too bad).
Here is my process :
Open a first JFrame in the Main, with a JButton (to open the second
JFrame).
On click, with ActionLister, i call the process to open my second
window, with a black background (this works very well).
BUT, if i add a long process (in my code, just a sleep(5000)) just after setVisible() my second JFrame, this one will appear in white, and waits for the sleep(5000) to end before being black.
Questions :
Can someone tell me why the second JFrames appears white until the
end of process ? Maybe i make something wrong when i build my JFrame
?
Can someone tell me how to show my second JFrame black BEFORE the process ends ?
I searched for a long time, and saw that if my second window is built direct in the main thread it's ok even with the sleep before end of process.
But when i am in another thread (like when i click on the button), that doesn't work good !
SECOND PART :
On click on the button from the first window :
The second window shows up (empty with black background). then, the result's calcul is launched.
Calculate the result cant take 20sec, and will find 1 element each 5 seconds.
Each times an element is found, i want it to be shown in the second window.
For that, i added an observer on this result from the JFrame, which will add an element each time one element is found. I hope you understand.
Here picture of what i want to make :
Process
Here my project .JAR : http://dl.free.fr/b5IUSStBJ
Here my result's calcul :
public void launchCalculateResult(){
String[] tabelements = {"test1","test2", "test3", "test4", "test5"};
for (int i=0; i < 5; i++){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
_elementslist.add(tabelements[i]);
notifyObservers();
}
}
you can see that it adds an element in a list each 2 seconds, and then notify the observers (my second window), then the observer adds an element :
public void refresh(Observable o) {
_otherwindow.addResultElement(_result.getLastElement());
}
The behaviour I got :
The Result calculates good, and in the end the second window looks good, with its 5 elements. But during the result's search, my second windows remains empty and white . . .
I repeat the aim :
Each time an element is added in the Result, i want to show it in my second window.
You're calling the long process on the Swing event thread, and this will tie up the thread preventing it from doing its important jobs, including painting your new JFrame.
The canonical solution is to use a background thread for your long processes, and for Swing GUI's, you'd want to use a SwingWorker -- if the background process needs to communicate with the GUI (which is usually the case).
For the details on this problem and solution, please check out: Concurrency in Swing
Side issue: you'll usually not want to show multiple JFrames in your application. For why this is important and for how you can improve this design, please check out Multiple JFrames
For example
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class SwingExample extends JPanel {
private JButton openDialogBtn = new JButton(new OpenDialogAction("Open Dialog"));
private JDialog dialog;
private DialogPanel dialogPanel = new DialogPanel();
public SwingExample() {
setPreferredSize(new Dimension(400, 400));
add(openDialogBtn);
}
private class OpenDialogAction extends AbstractAction {
public OpenDialogAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
dialogPanel.setText("");
if (dialog == null) {
Window win = SwingUtilities.getWindowAncestor(SwingExample.this);
dialog = new JDialog(win, "Dialog", ModalityType.MODELESS);
dialog.add(dialogPanel);
dialog.pack();
dialog.setLocationRelativeTo(win);
}
new SwingWorker<Void, Integer> () {
private final int maxI = 5;
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < maxI; i++) {
publish(i);
Thread.sleep(1000);
}
return null;
}
protected void process(java.util.List<Integer> chunks) {
for (Integer chunk : chunks) {
dialogPanel.setText("Time: " + chunk);
}
};
protected void done() {
dialogPanel.setText("Done!");
};
}.execute();
dialog.setVisible(true);
}
}
private class DialogPanel extends JPanel {
private JTextField textField = new JTextField(10);
public DialogPanel() {
setBackground(Color.BLACK);
setPreferredSize(new Dimension(200, 200));
add(textField);
}
public void setText(String text) {
textField.setText(text);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
SwingExample mainPanel = new SwingExample();
JFrame frame = new JFrame("SwingExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
Example 2: handles Strings being passed into a JList<String> using a SwingWorker<Void, String>
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class SwingExample extends JPanel {
private JButton openDialogBtn = new JButton(new OpenDialogAction("Open Dialog"));
private JDialog dialog;
private DialogPanel dialogPanel = new DialogPanel();
public SwingExample() {
setPreferredSize(new Dimension(400, 400));
add(openDialogBtn);
}
private class OpenDialogAction extends AbstractAction {
public OpenDialogAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
dialogPanel.clearList();
if (dialog == null) {
Window win = SwingUtilities.getWindowAncestor(SwingExample.this);
dialog = new JDialog(win, "Dialog", ModalityType.MODELESS);
dialog.add(dialogPanel);
dialog.pack();
dialog.setLocationRelativeTo(win);
}
new SwingWorker<Void, String>() {
#Override
protected Void doInBackground() throws Exception {
String[] tabelements = { "test1", "test2", "test3", "test4", "test5" };
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publish(tabelements[i]);
}
return null;
}
protected void process(java.util.List<String> chunks) {
for (String chunk : chunks) {
dialogPanel.addText(chunk);
}
};
protected void done() {
dialogPanel.addText("Done!");
};
}.execute();
dialog.setVisible(true);
}
}
private class DialogPanel extends JPanel {
private DefaultListModel<String> listModel = new DefaultListModel<>();
private JList<String> jList = new JList<>(listModel);
public DialogPanel() {
jList.setPrototypeCellValue("ABCDEFG HIJKLMNOP");
jList.setVisibleRowCount(6);
JScrollPane scrollPane = new JScrollPane(jList);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBackground(Color.BLACK);
setPreferredSize(new Dimension(200, 200));
add(scrollPane);
}
public void clearList() {
listModel.clear();
}
public void addText(String text) {
listModel.addElement(text);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
SwingExample mainPanel = new SwingExample();
JFrame frame = new JFrame("SwingExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
//Make constructor class for both JFrame then
//write this code into your JFrame where your button is accesing another JFrame
//Note:- jb=button var name,
// jf=JFrame vatr name,
// addnew()=JFrame Class to be open.
jb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
new addnew();
jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
});
It might work as well.
I have an application I'm making for a game to automatically update a game client.
Once you press Launch, it will open up my DownloadFrame (extends JDialog), and will look like this:
If you click the icon for the application in the taskbar, (maybe Windows 8 is the problem?) it will minimize the application like usual. However when you go to maximise the application again, the JDialog will be hidden, I'm assuming, behind the parent. It looks like this:
Here's my code for my extension of JDialog. Apologies in advance for it being messy.
public class DownloadFrame extends JDialog implements Runnable {
private static final long serialVersionUID = -8764984599528942303L;
private Background frame;
private ImageIcon[] gifs;
private JLabel spinner;
public DownloadFrame() {
super(Loader.application, false);
setLayout(null);
setUndecorated(true);
setAutoRequestFocus(true);
new Thread(this).start();
generateBackground();
generateButton();
generateGif();
}
private void generateBackground() {
frame = new Background("sub_background.png");
setSize(frame.getWidth(), frame.getHeight());
setBackground(new Color(1.0f, 1.0f, 1.0f, 0.0f));
setLocationRelativeTo(null);
setLocation(this.getX(), this.getY() + 5);
setLayout(null);
setContentPane(frame);
}
private void generateGif() {
gifs = Utils.generateGifImages();
spinner = new JLabel(gifs[0]);
spinner.setBounds(70, 30, gifs[0].getIconWidth(), gifs[0].getIconHeight());
add(spinner);
}
private HoverableButton cancel;
public HoverableButton getCancelButton() {
return cancel;
}
private void generateButton() {
cancel = new HoverableButton(Settings.CANCEL_BUTTON, 75, 145);
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
/*
* TODO -
* stop the download in progress
*/
for (HoverableButton button : Loader.application.getPrimaryButtons()) {
button.setActive(true);
button.setVisible(true);
}
dispose();
}
});
add(cancel);
}
private int cycleCount;
private void cycleGif() {
if (spinner == null) {
return;
}
cycleCount++;
if (cycleCount > 7) {
cycleCount = 0;
}
spinner.setIcon(gifs[cycleCount]);
}
#Override
public void run() {
while (true) {
cycleGif();
try {
Thread.sleep(100L);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
In case it's needed, here's my usage of it. Most of the stuff can be ignored I'm sure, it's simply there to hide the four buttons while the download is in progress.
((HoverableButton) components[2]).addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
HoverableButton source = (HoverableButton) components[2];
if (source.isActive()) {
try {
Thread.sleep(500L);
} catch (Exception ex) {
ex.printStackTrace();
}
if (panel == null) {
panel = new DownloadFrame();
panel.setVisible(true);
} else {
panel.setVisible(true);
panel.getCancelButton().removeHighlight();
}
for (HoverableButton button : getPrimaryButtons()) {
button.setActive(false);
button.setVisible(false);
button.removeHighlight();
}
/*
* TODO -
* handle checking for updates / downloading updates
*/
}
}
});
However when you go to maximise the application again, the JDialog will be hidden, I'm assuming, behind the parent
Yes. When you create the JDialog, you need to specify the "owner" JFrame of the dialog in the constructor.
So you must create and make the JFrame and make the frame visible before you create the dialog.
I have an application that after successfull login (on a JFrame), starts to create the main frame (class MainUI that extends from JFrame). That MainUI class contains a JTabbedPane (which each tab is a class that extends from JPanel) and, on setVisible method, creates and shows each tab.
I want to add on the login form, after successfull login, a Spinner image to indicate that the MainUI is being created.
After display the Spinner image, I invoke the creation of the MainUI and call the setVisible method on EventQueue.invokeLater(); but the Spinner image is not updated. If I use new Thread(runner).start(); is updated, but I get a lot of Component creation must be done on Event Dispatch Thread
Some code of Login.java:
buttonLogin.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
login();
}
});
private void login()
{
//check DB and permissions
//if all is ok
lMsj.setIcon(spinner);
new Thread(new Runnable() {
public void run() {
showMainUI(usr);
}
}).start();
}
private void showMainUI(final Usuario usr)
{
Runnable runner = new Runnable() {
public void run() {
final MainUI mui = new MainUI();
mui.setVisible(true);
dispose();
}
};
EventQueue.invokeLater(runner);
}
and some code of MainUI.java
public MainUI()
{
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
setMinimumSize(new Dimension(1280, 960));
createComponents();
}
});
}
private void initComponents()
{
//..
// menuItem = new ...
// ...
}
#Override
public void setVisible(boolean value)
{
//..
if (Security.get().isAllowed("tab1")){
addTab1();
}
//..
}
private void addTab1(){
//..
getTabbedPane().addTab("Tab1", new Tab1());
//..
}
How I can fix this, so that the image is updated and the user interface is created in the "background"?
How can i exit only they new MainGame that i created from Main?
Where Main is having an original layer of game. And the MainGame was a dialog window (such as modal windows).
Main.java: (main code)
public class Main extends JWindow
{
private static JWindow j;
public static MainGame mp;
public static void main(String[] args)
{
new Thread(new Runnable()
{
public void run()
{
mp = new MainGame();
mp.runit();
//mp.stopit();
}
}).start();
j = new Main();
j.setVisible(true);
}
}
MainGame.java: (this was extended by Main, and i would like to quite this only).
public class MainGame extends JWindow
{
private static JWindow j;
public MainGame()
{
// some GUI ...
}
public static void runit()
{
j = new MainGame();
j.setVisible();
}
}
1) better would be implements CardLayout, as create Top-Level Container for new Window, then you'll only to switch betweens Cards
2) don't create lots of Top-Level Container on Runtime, because there are still in JVM memory untill current instance exist,
create required number of and re-use that, to avoiding possible memory lacks
then you have to call setVisible(false) and setVisible(true)
JWindow missed methods for setting setDefaultCloseOperation(Whatever);
3) if you'll create constructor public JWindow(Frame owner), then you'll call directly
SwingUtilities.getAccessibleChildrenCount() and SwingUtilities.getWindowAncestor()
import javax.swing.*;
import java.awt.*;
public class Testing {
private JFrame f = new JFrame("Main Frame");
private JWindow splashScreen = new JWindow();
public Testing() {
splashScreen = new JWindow(f);
splashScreen.getContentPane().setLayout(new GridBagLayout());
JLabel label = new JLabel("Splash Screen");
label.setFont(label.getFont().deriveFont(96f));
splashScreen.getContentPane().add(label, new GridBagConstraints());
splashScreen.pack();
splashScreen.setLocationRelativeTo(null);
splashScreen.setVisible(true);
new Thread(new Runnable() {
#Override
public void run() {
readDatabase();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}).start();
}
public void readDatabase() {
//simulate time to read/load data - 10 seconds?
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
public void createAndShowGUI() {
JLabel label = new JLabel("My Frame");
label.setFont(label.getFont().deriveFont(96f));
f.add(label);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
System.out.println("JFrame getAccessibleChildrenCount count -> "
+ SwingUtilities.getAccessibleChildrenCount(f));
System.out.println("JWindow getParent -> "
+ SwingUtilities.getWindowAncestor(splashScreen));
splashScreen.dispose();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Testing t = new Testing();
}
});
}
}
I did not go really into your design. but there is 'j.dispose();'.
this should work. here is the java documentation.
notice:
dispose(); - deletes the window from memory.
setVisibilty(false); - just hides it from the screen.
You can override the 'dispose()' function to do some stuff while the widow is closing (updating scores if its a game) but at the end of the overriden function you have to call 'super.dispose();' so the function of the class Window is called.
And the MainGame was a dialog window
But thats not what your code uses. You use a JWindow.
You should be using a JDialog for a modal window. Then you just dispose() the window.