I have written a Java XML Parser as an Applet. It is looking and functioning well enough in this form.
My Question, Is if I want to run this without a browser, how Would I properly wrap it to run as an executable?
GUI.java
--------------
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GUI extends JPanel implements ActionListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
private Parser xmlEditor;
private String startTimeValue;
private String endTimeValue;
public GUI(){
init();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new GUI();
}
});
}
public void init() {
this.setXmlEditor(new Parser("C:\\Users\\Administrator\\workspace\\XMLParser\\src\\test.xml"));
add(new Label("Start Time"));
startTimeValue = xmlEditor.getStartTimeValue();
endTimeValue = xmlEditor.getEndTimeValue();
startTime = new TextField(startTimeValue);
add(new Label("End Time"));
endTime = new TextField(endTimeValue);
save = new Button("save");
save.addActionListener(this);
add(startTime);
add(endTime);
add(save);
}
public void actionPerformed(ActionEvent e)
{
System.out.println(endTime.getText());
xmlEditor.updateStartTimeValue(startTime.getText());
xmlEditor.updateEndTimeValue(endTime.getText());
System.out.println(e);
System.exit(0);
}
public Parser getXmlEditor() {
return xmlEditor;
}
public void setXmlEditor(Parser xmlEditor) {
this.xmlEditor = xmlEditor;
}
TextField startTime, endTime;
Button save;
}
While trying things with Swing and JFRame etc, I am not getting properly layout, or am opening multiple windows. Can anyone provide assistance? The second Panel Keeps replacing the First. Id like to really try to learn how to place multiple components inside an executable jar is the goal.
SwingPaintDemo.java
import java.awt.Label;
import java.awt.TextField;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
public class SwingPaintDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
Parser myParser = new Parser("C:\\Users\\Administrator\\workspace\\XMLParser\\src\\test.xml");
JPanel top = new JPanel();
top.add(new Label("Start Time"));
TextField startTimeField = new TextField(myParser.getStartTimeValue());
top.add(startTimeField);
f.getContentPane().add(top);
JPanel bottom = new JPanel();
bottom.add(new Label("End Time"));
TextField endTimeField = new TextField(myParser.getEndTimeValue());
bottom.add(endTimeField);
f.getContentPane().add(bottom);
f.pack();
}
}
JFrame uses a BorderLayout by default, where as a JPanel uses a FlowLayout
Instead of rebuilding the UI in the JFrame, simply add an instance of GUI to it, since you've already defined the functionality in a JPanel, this makes it easily reusable.
public class SwingPaintDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new GUI());
f.pack();
f.setVisible(true);
}
}
FYI: You should never reference src in any path element, src won't exist once the program is built and packaged. This is also doubly concerning for applets, as applets run in a tight security model, which prevents them from accessing the file system by default.
Instead, you should be using Class#getResource or Class#getResourceAsStream, depending on your needs.
this.setXmlEditor(new Parser(getClass().getResource("/test.xml")));
for example. You may need to change your Parser to accept either a URL and/or InputStream as well
Related
I am currently practicing OOP with Java.
I have created a GUI project via WindowBuilder with Eclipse IDE and below is the result.
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Example window = new Example();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Example() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JProgressBar progressBar = new JProgressBar();
frame.getContentPane().add(progressBar, BorderLayout.CENTER);
}
What I am trying to do is to connect the JProgressBar to another class that has the actual task, to show the progress.
For example, if the other class contains the following code:
int i = 0;
while(i <= 100) {
progressBar.setValue(i);
i++;
}
how should I change the progressBar.setValue(i); part?
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.
Here's the simplest working example I could create. As you can see in the picture, I caught the JProgressBar in the middle.
Each time you press the button, the progress bar will count from 0 to 100, one unit every 100 milliseconds.
In order to access the progress bar, you have to make it a class field or variable. You can then access the class field with a setter. Getters and setters are a basic Java concept. You can see another example of a plain Java getter/setter class in my JProgressBarModel class.
I used a Swing Timer to add a delay to the updating of the progress bar so you can see the bar update and simulate an actual long-running task. The actual work takes place in the WorkListener class. Because the code is inside an ActionListener, the Swing update of the progress bar takes place on the Event Dispatch Thread.
Here's the complete runnable code. I made all the additional classes inner classes so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
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.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class JProgressBarExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JProgressBarExample());
}
private JProgressBar progressBar;
private final JProgressBarModel model;
public JProgressBarExample() {
this.model = new JProgressBarModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Progress Bar Example");
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 FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
progressBar = new JProgressBar();
panel.add(progressBar);
JButton button = new JButton("Start Process");
button.addActionListener(event -> {
model.setIndex(0);
setValue();
Timer timer = new Timer(100, new WorkListener(this, model));
timer.start();
});
panel.add(button);
return panel;
}
public void setValue() {
progressBar.setValue(model.getIndex());
}
public class WorkListener implements ActionListener {
private final JProgressBarExample view;
private final JProgressBarModel model;
public WorkListener(JProgressBarExample view, JProgressBarModel model) {
this.view = view;
this.model = model;
}
#Override
public void actionPerformed(ActionEvent event) {
Timer timer = (Timer) event.getSource();
int index = model.getIndex() + 1;
model.setIndex(index);
view.setValue();
if (index >= 100) {
timer.stop();
}
}
}
public class JProgressBarModel {
private int index;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
}
One option is to do it similar to the frame part. You Example class has a field variable that could be directly accessible to your other code.
A better way would be to have a private field for the JProgressBar and a getProgressBar() method.
But currently you are using a method variable that is forgotten when initialize() returns.
Does anyone know why my image is not loading? I tried many things and so far nothing, first of all the folder "IMGFiles" is already like Source Folder.
package Main;
import javax.swing.*;
public class Menu extends JFrame {
public Menu()
{
ImageIcon imagem = new ImageIcon(Menu.class.getResource("/LiturgisGame/IMGFiles/LiturrgisLogoLoad.png"));
JLabel logo = new JLabel();
logo.setIcon(imagem);
}
public static void main(String[] args) {
//new Menu();
JFrame janela = new JFrame();
janela.setSize(816, 419);
janela.setUndecorated(true);
janela.setVisible(true);
janela.setLocationRelativeTo(null);
}
}
I'm assuming you are using UNIX (for the shape of the path you are using).
Here is an approach for you:
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import com.apple.eawt.Application;
public class Menu extends JFrame {
public Menu(){ }
public static void main(String[] args) {
Application.getApplication().setDockIconImage(new ImageIcon("/LiturgisGame/IMGFiles/LiturrgisLogoLoad.png").getImage());
//new Menu();
JFrame janela = new JFrame();
janela.setSize(816, 419);
janela.setUndecorated(true);
janela.setVisible(true);
janela.setLocationRelativeTo(null);
}
}
Output:
This happens because you prepare the JLabel inside Menu constructor and you do not initiate any instance of Menu class. Also, you do not add the JLabel into the frame (content pane).
Check this sample:
public class Menu extends JFrame {
public Menu()
{
ImageIcon imagem = new ImageIcon(Menu.class.getResource("/LiturgisGame/IMGFiles/LiturrgisLogoLoad.png"));
JLabel logo = new JLabel();
logo.setIcon(imagem);
setSize(816, 419);
setUndecorated(true);
setLocationRelativeTo(null);
getContentPane().add(logo); //Add the label to the content pane
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->{
new Menu().setVisible(true);
});
}
}
What is the correct way of disposing a frame which is created inside a Runnable object?
The code below returns a null pointer exception when the endDialog is called before the LoadingRunnable has completed its constructor.
How can the endDialog be executed after the constructor has finished?
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LoadingRunnable implements Runnable
{
private JFrame jFrame;
#Override
public void run()
{
jFrame = new JFrame("Window");
JPanel jPanel = new JPanel();
JLabel label = new JLabel("Loading...");
jPanel.add(label);
jFrame.setContentPane(jPanel);
jFrame.pack();
jFrame.setVisible(true);
}
public void endDialog()
{
jFrame.setVisible(false);
jFrame.dispose();
}
public static void main(String args[])
{
LoadingRunnable l = new LoadingRunnable();
SwingUtilities.invokeLater(l);
//work done here
l.endDialog();
}
};
You have a concurrency problem here because SwingUtilities.invokeLater() schedules your runnable class execution in the Event Dispatch Thread asynchronously while your main thread's flow still running, causing a NPE.
The correct way to dispose a frame is through events, just as Swing is designed to be used. For instance by clicking the "X" (close) button or by dispatching a WindowEvent:
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
You may want to take a look to this question too: Optional way to close a dialog window
In addition
If you just want to show something during your application start up, then you can use SplashScreen API instead of JFrame. See How to Create a Splash Screen for further details.
Based on your previous question and this new one, I'd suggest you read the whole Concurrency in Swing tutorial to understand about common concurrency problems in Swing and how to deal with them.
Ok found how:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Loading
{
private JFrame jFrame;
public void startDialog()
{
jFrame = new JFrame("Window");
JPanel jPanel = new JPanel();
JLabel label = new JLabel("Loading...");
jPanel.add(label);
jFrame.setContentPane(jPanel);
jFrame.pack();
jFrame.setVisible(true);
}
public void endDialog()
{
jFrame.setVisible(false);
jFrame.dispose();
}
public static void main(String args[])
{
final Loading l = new Loading();
for (int i = 0; i < 200; i++)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
l.startDialog();
}
});
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
l.endDialog();
}
});
}
}
};
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));
}
}
I'm just getting into GUI programming, slowly learning.
However I'm having a problem right of the bat. I can't get the Fore/Background color to change in my window at all.
However when I add a label via JLabel and then use setFore/Back, they change colors just fine. Just not the whole window.
I thought .setForeground and .setBackground are supposed to change the color of the window?
import javax.swing.*;
import java.awt.*;
public class MyWindow {
public static void main(String args[])
{
Runnable init = new Runnable()
{
public void run()
{
JFrame myWindow = new JFrame("Hola!");
myWindow.setForeground(Color.YELLOW);
myWindow.setBackground(Color.YELLOW);
myWindow.setSize(400, 300);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setLayout(null);
myWindow.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
First of all, do not use a null layout. Let the layout manager do its job. Second of all, you need to set the background of the content pane of the JFrame instance, as such
myWindow.getContentPane().setBackground(Color.YELLOW);
See also:
Using Top-Level Containers
you cannot color a frame. However you can color the ContentPane inside.
import javax.swing.*;
import java.awt.*;
public class MyWindow {
public static void main(String args[])
{
Runnable init = new Runnable()
{
public void run()
{
JFrame myWindow = new JFrame("Hola!");
myWindow.getContentPane().setBackground(Color.YELLOW);
myWindow.setSize(400, 300);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setLayout(null);
myWindow.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
this should fix your problem...
tangina naman ang bobo naman neto, pokegooo
import javax.swing.;
import java.awt.;
public class MyWindow {
public static void main(String args[])
{
Runnable init = new Runnable()
{
public void run()
{
JFrame myWindow = new JFrame("Hola!");
myWindow.getContentPane().setBackground(Color.YELLOW);
myWindow.setSize(400, 300);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setLayout(null);
myWindow.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
// tanga amputa aral ka muna dudong
// pakangkang