I want a temporary loading screen in the transition from one frame to another.
In the mainframe I create the loading screen which creates the other screen (employmentframe). It only creates it, it does not show it yet.
In the employment frame I have put some loadingframe.setloadingbar() methods which call the setloadingbar method in loadingframe. This works perfect until it reaches 100. At getvalue() == 100 it should set the employmentframe visible, but instead it gives me a nullpointerexception. Which is weird because the employment-screen IS created.
The code is below -
Employmentframe:
public EmploymentFrame(int eid, JFrame thisframe) {
initComponents();
//loadCaseFileList();
e_id = eid;
loadCourseList();
EmploymentFrame.thisframe = thisframe;
LoadingFrame.setLoadingBar(1);
}
public static void setEmploymentFrameVisible()
{
thisframe.setVisible(true);
}
The loadingframe:
private static JFrame Employmentframe;
private static int oldvalue;
private int e_id;
public LoadingFrame(int type, int eid) {
initComponents();
this.e_id = eid;
if(type == 1)
{
Employmentframe = new EmploymentFrame(eid, Employmentframe);
}
}
public static void setLoadingBar(int load)
{
oldvalue = LoadingBar.getValue();
System.out.println(""+oldvalue);
int newvalue = oldvalue+load;
System.out.println("nv"+newvalue);
LoadingBar.setValue(newvalue);
if(LoadingBar.getValue() == 100)
{
EmploymentFrame.setEmploymentFrameVisible();
}
}
Thanks.
The stacktrace indicates that this line is throwing the NPE
thisframe.setVisible(true);
so thisframe is null.
When you create Employmentframe here
Employmentframe = new EmploymentFrame(eid, Employmentframe);
you are passing in null as an argument to the constructor as the JFrame has not yet been initialized. In fact, the EmploymentFrame does not need to be passed an instance of itself.
There are a number of other issues:
Static methods are seen as a poor design choice in any OO language
Multiple JFrames are considered difficult to manage. Preferred alternatives are 1.) CardLayout on a single JFrame or 2.) In cases where multiple windows are required a single JFrame with a modal JDialog can be used. Also discussed here.
Code conventions in Java indicate that variables should begin with a lowercase letter.
Related
What I want to achieve is very simple.
I have 2 classes. "SpeedingTicket" & "SpeedingTicket GUI".
Inside my GUI I have 1 textbox name txtSpeedLimit & a button.
Inside my SpeedingTicket class I have a variable "int speedingTicket".
Inside my SpeedingTicket class I also have a get & set method for "speedingTicket".
I know how to get and set text using JTextFields, but I want to be able to:
receive input from the "txtSpeedLimit", and store that value into the "txtSpeedLimit" instance variable in the "SpeedTicket" class. I can then check for validation etc when I come to adding the vehicle speed.
Maybe this isn't the most efficient way of dealing with this program. Maybe I should scrap the instance variables in SpeedingTicket, and deal with it all in the GUI.
Any advice would be hugely appreciated.
Basically what I'm trying to do is this:
class confirmHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
String val = txtSpeedLimit.getText();
int realNum = speed.getSpeedLimit() = txtSpeedLimit; < but obviously that doesn't work, but I want the textbox link to the variable.
EDIT: If we take away the GUI, all I want my program to do is the following:
Speed Limit: 50 < enterd via textfield
Speed: 60 < entered via textfield
if the speed is blah blah (ive already coded this).. then output a result to one of my labels.
I achieved this without making a GUI and making it only console based, but instead of the user typing it via the console, I want it to be typed via textfields.
THe values that are entered into the textfields should be stored in the two variables (speed and speedlimit) that are in the SpeedingTicket class.
You can update a value in:
public class SpeedingTicket {
int speedingTicket;
public SpeedingTicket() {
speedingTicket = 500;
}
public int getSpeedingTicket() {
return speedingTicket;
}
}
by:
public class SpeedingTicketGUI extends JPanel{
SpeedingTicket st;
SpeedingTicketGUI() {
st = new SpeedingTicket();
setLayout(new FlowLayout(FlowLayout.LEFT));
JTextField txtField = new JTextField(10);
txtField.setText(""+st.getSpeedingTicket());
add(txtField);
JButton btn = new JButton("Update");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setSpeedingTicket(txtField.getText());
}
});
add(btn);
}
private void setSpeedingTicket(String text) {
try {
int speedTicket = Integer.parseInt(text);
st.setSpeedingTicket(speedTicket);
System.out.println("Speeding ticket set to " +st.getSpeedingTicket());
} catch (NumberFormatException ex) {
System.out.println("Invalid value " +text);
ex.printStackTrace();
}
}
public static void main(String[] args){
JFrame frame = new JFrame("Speeding Ticket");
frame.setSize(400,100);
frame.add(new SpeedingTicketGUI());
frame.setVisible(true);
}
}
You don't need to store values in JText or any GUI componenets...
Use global static variables. For example:
public static int speed_limit;
You can access this variable from ANY method,class, etc.
There are multiple ways to do it.
You can detect textfield changes by using a DocumentListener or if you want (not recommended) by a KeyListener.
The Listener could be implemented directly by your gui class or by your other class. If you want more abstraction you could implement the DocumentListener by your gui class and create a method
public void addSpeedChangeListener(SpeedChangeListener scl) {
this.speedChangeListeners.add(scl);
}
Your SpeedChangeListener could be very simple:
public interface SpeedChangeListener {
public void speedChanged(int value);
}
Then your second class implements the SpeedChangeListener and calls addSpeedChangeListener(this) on your gui class. Inside the gui class, your document listener calls speedChanged(val) for every listener registered.
EDIT
You can also use the Button and call the speedChanged on every listener inside the actionPerformed method of the ActionListener.
I think it would be easier to use a JOptionDialog which pop ups when the button is clicked. That way you can easily get input and also validate the input straight away.
I am programming an application that deals with orders from a database. It has several pages, a navigation, a header that always should show information about the actual order you are working with and a content area, in which the details of said order get shown:
My MainProgram extends a JFrame and contains a CardLayout, in which the other pages are hosted, so when the user clicks on the page in the navigation, only the view of the content-area changes. Logo, header and the navigation stay the same. The header keeps displaying the order number.
As there are several different pages that contain details about the same order, I need to "send / transfer" information about the order from one page to the other so I can show some information in the header and in the content area from the order object.
But I am not getting this to work as intended, mostly to my misunderstand of static and when to use it, where objects get created exactly and also the complexity of my program: I am using a class that is intended for the navigation and therefore should also handle
the information transfer from one page to the other.
Since I am using a database, creating a MVCE will be hard, so instead I will show the important parts of my program.
MainProgram.java
Here the navigation and the content panel (centerPanel) get created, also the CardLayout. centerPanel and the CardLayout are static, so I can call this from other classes and switch the page that is shown (probably not a good idea?):
NavigationPanel navigationPanel = new NavigationPanel();
public static JPanel centerPanel = new JPanel();
public static CardLayout contentCardsLayout = new CardLayout();
I create the pages and put them into my CardLayout:
OverviewPage overviewPage = new OverviewPage();
BasicDataPage basicDataPage = new BasicDataPage();
centerPanel.setLayout(contentCardsLayout);
overviewPage.setName("overviewPage");
basicDataPage.setName("basicDataPage");
centerPanel.add(overviewPage, "overviewPage");
centerPanel.add(basicDataPage, "basicDataPage");
The main method, where I create a MainProgram object:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
MainProgram window = new MainProgram();
window.setVisible(true);
window.initialize();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
OverviewPage.java
The overview page contains a JTable which gets populated from a database. If the user double-clicks an entry, he gets transfered to the BasicDataPage where he can see the details of the order.
But in order to show the details, I need to somehow transfer the information of the order object into the target class and thats the point I am struggling with!
// I tried several things like object into constructor, static object, creating a method etc...
if (mouseEvent.getClickCount() == 2 && row != -1) {
String workNumberOfOrderObject = (String) table.getValueAt(row, 0);
OrderObject orderObject = GetOrderObject.getOrderObjectFromDatabase(workNumberOfOrderObject);
BasicDataPage basicDataPage = new BasicDataPage();
basicDataPage.recieveOrderObject(orderObject);
workNumberPanel.recieveOrderObject(orderObject);
workNumberPanel.setTxtWorkNumber(workNumberOfOrderObject);
MainProgram.contentCardsLayout.show(MainProgram.centerPanel, "basicDataPage");
}
I tried "sending" the order object to the BasicDataPage via the constructor and set the text in the JTextFields in the BasicDataPage accordingly. This did not work, the textfields simply stayed empty altough I can System.out.println(orderObject.toString()) the recieved object.
BasicDataPage.java
I also tried creating a method receiveOrderObject that I use in the OverviewPage, which should set the textfields of the basicDataPage AND the workNumberPanel, but the fields stay empty:
WorkNumberPanel workNumberPanel = new WorkNumberPanel();
JTextField txtCarWidth = new JTextField(TEXTFIELD_LENGTH);
JTextField txtCarDepth = new JTextField(TEXTFIELD_LENGTH);
JTextField txtCarHeight = new JTextField(TEXTFIELD_LENGTH);
public void recieveOrderObject(OrderObject orderObject){
txtCarDepth.setText(orderObject.getCar_depth());
}
Before posting my question I've read several Q/As here on SO like this:
Accessing UUID from another class in Java ... suggesting to use static for global variables.
I know that static variables are class variables, that all instances can use and only one version exists of. So I tried to send a static object from one class to the other.
But since I am using JTextFields, I had to mix static and non-static content, which either did not work at all or the textfields disappeared.
I have the feeling that I am getting a very basic concept in java wrong, so any help, no matter in which direction, is appreciated!
EDIT:
Based on Reşit Dönüks answer, I was able to fill the textfields by making BasicDataPage and loadBasicData(orderObject) in MainProgram static. Now I can do MainProgram.loadBasicData(orderObject); ... and the textfields in the BasicDataPage get filled as intended.
Is this a valid approach or do I get problems for using static for GUI-Elements? ..... Don't!
I realized that, your are creating BasicDataPage in each double click.
if (mouseEvent.getClickCount() == 2 && row != -1) {
String workNumberOfOrderObject = (String) table.getValueAt(row, 0);
OrderObject orderObject = GetOrderObject.getOrderObjectFromDatabase(workNumberOfOrderObject);
BasicDataPage basicDataPage = new BasicDataPage();
This is the main problem. Do not create BasicDataPage there, just reach the created instance and set the order object to that. My solution is below.
public class MainProgram implements OrderView{
//remove statics here
private JPanel centerPanel = new JPanel();
private CardLayout contentCardsLayout = new CardLayout();
private BasicDataPage basicPage;
public MainProgram() {
//other codes
OverviewPage overviewPage = new OverviewPage();
basicPage = new BasicDataPage();
centerPanel.setLayout(contentCardsLayout);
overviewPage.setName("overviewPage");
basicDataPage.setName("basicDataPage");
centerPanel.add(overviewPage, "overviewPage");
centerPanel.add(basicPage, "basicDataPage");
//oher codes
}
#Override
public void loadOrder(OrderObject order) {
basicPage.recieveOrderObject(orderObject);
contentCardsLayout.show(centerPanel, "basicDataPage");
}
}
public interface OrderView {
public void loadOrder(OrderObject order);
}
public class OverviewPage {
OrderView orderView;
public OverviewPage(OrderView orderView) {
this.orderView = orderView;
}
//in ActionPerformed
if (mouseEvent.getClickCount() == 2 && row != -1) {
String workNumberOfOrderObject = (String) table.getValueAt(row, 0);
OrderObject orderObject = GetOrderObject.getOrderObjectFromDatabase(workNumberOfOrderObject);
orderView.loadOrder(orderObject);
workNumberPanel.recieveOrderObject(orderObject);
workNumberPanel.setTxtWorkNumber(workNumberOfOrderObject);
}
}
As pointed already, Singleton is the way to go. I would just like to point out a mistake in the code provided in the answer before.
private static MainFrameinstance = null;
Rename MainFrameinstance to instance or vice-versa; because the same variable is checked by the getInstance() method.
I've created an application that uses FocusListener to make sure a text fieid's value is always positive. When the user inputs negative value and then click the "tab" key to move focus away from the text field, the value will be multiplied by -1 so that the resulted value is positive. However, when I ran the application, the text field didn't change. I am not sure what I did wrong, and will appreciate any help.
Here is my code:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class AlwaysPositive extends JFrame implements FocusListener {
JTextField posField = new JTextField("30",5);
public AlwaysPositive() {
super("AlwaysPositive");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel pane = new JPanel();
JTextField posField = new JTextField("30",5);
JButton ok= new JButton("ok");
posField.addFocusListener(this);
pane.add(posField);
pane.add(ok);
add(pane);
setVisible(true);
}
public void focusLost(FocusEvent event) {
try {
float pos = Float.parseFloat(posField.getText());
if (pos < 0)
pos = pos*-1;
posField.setText("" + pos);
} catch (NumberFormatException nfe) {
posField.setText("0");
}
}
public void focusGained(FocusEvent event) {
}
public static void main(String[] arguments) {
AlwaysPositive ap = new AlwaysPositive();
}
}
The main problem is you are shadowing your variables
You declare
JTextField posField = new JTextField("30",5);
As an instance variable, but in your constructor, you redeclare it again...
public AlwaysPositive() {
//...
JTextField posField = new JTextField("30",5);
posField.addFocusListener(this);
//...
}
Add attach the focus listener to it, but in the focusLost method, you are referring to the instance variable, which isn't the one that is actually on the screen
Start by changing the declaration within the constructor
public AlwaysPositive() {
//...
posField = new JTextField("30",5);
posField.addFocusListener(this);
//...
}
However, there are better solutions to use then FocusListener.
For example, you could use an InputVerifier that will allow you to verify the value of the field and make decisions about whether focus should be moved or not.
Take a look at How to Use the Focus Subsystem and Validating Input in particular
You could also use a DocumentFilter to restrict what the user can actually enter, filtering the input as the user types it. Take a look at Text Component Features and Implementing a Document Filter in particular.
You can also take a look at these examples for more ideas
When you create object of same name inside a method, the listener is set to the method object and not to the Class object.
So I'm having these classes
public class Init {
...
JFrame addStream = new AddStream();
addStream.setVisible(true);
addStream.setLocationRelativeTo(null);
addStream.getData(); //not working
}
public class AddStream extends javax.swing.JFrame {
private String nameData, urlData, qualityData;
/** Creates new form AddStream */
public AddStream() {
initComponents();
}
private void initComponents() {
...
}
private void addActionPerformed(java.awt.event.ActionEvent evt) {
nameData = name.getText();
urlData = url.getText();
qualityData = quality.getSelectedItem().toString();
}
public String[] getData() {
return new String[]{nameData, urlData, qualityData};
}
}
Note the classes arent complete, just snippets.
When the user clicks on the Add button(addActionPerformed) the values get saved to local variables in the AddStream class and get returned by getData().
The problem I'm having is with addStream.getData();, I get "cannot find symbol"
Is there a way to get that data from AddStream JFrame to Init class?
Your problem can be easily fixed by changing this line:
JFrame addStream = new AddStream();
To this:
AddStream addStream = new AddStream();
What's happening in your code is that you're trying to call a method on a JFrame that doesn't exist on a JFrame, it only exists in an AddStream. Even though your JFrame is-a AddStream in this case, the compiler forbids this unless you tell the compiler that it is-a AddStream. And you do that with the code I've shown you.
Another way is to cast it in your call. Imagine you were using your code from above, you could then do this on your last line:
((AddStream) addStream).getData();
In runtime when you do
JFrame addstream = new AddStream();
the object is viewed as a simple JFrame (using the JFrame part of class AddStream).
getData() is only available for AddStream type objects. You could trick the JVM into using the assigned type
if( addstream instanceof AddStream ){
(AddStream) addstream.getData();
} else {
//TODO
}
this is sometime useful when switching between different implementations of the same Interface. Note that the cast is only there to pass the compiler. The runtime checks instanceof only and go aheads if the condition evaluate to true.
I'm very new to Java and I'm setting myself the challenge on writing a Caesar shift cipher decoder. I'm basically trying to clear a JTextArea from another class. I have two classes, a GUI class called CrackerGUI and a shift class. The JtextArea is in the GUI class along with the following method:
public void setPlainTextBox(String text)
{
plainTextBox.setText(text);
}
The GUI class also has a clear button with the following:
private void btnClearActionPerformed(java.awt.event.ActionEvent evt) {
Shift classShift = new Shift();
classShift.btnClear();
}
Lastly i have the method in the shift class to clear the JTextArea.
public class Shift extends CrackerGUI {
public void btnClear()
{
CrackerGUI gui = new CrackerGUI();
gui.setPlainText(" ");
System.out.println("testing");
}
}
The testing text is printing out to console but the JTextArea wont clear. I'm not sure as to why :). I am sure it's a very simple mistake but it has me baffled. Any help would be appreciated.
Thank you in advance.
You're misusing inheritance to solve a problem that doesn't involve inheritance. Don't have Shift extend CrackerGUI and don't create a new CrackerGUI object inside of the btnClear() method since neither CrackerGUi is the one that's displayed. Instead have Shift hold a reference to the displayed CrackerGUI object and have it call a public method of this object.
e.g.,
public class Shift {
private CrackerGUI gui;
// pass in a reference to the displayed CrackerGUI object
public Shift(CrackerGUI gui) {
this.gui = gui;
}
public void btnClear() {
//CrackerGUI gui = new CrackerGUI();
gui.setPlainText(" ");
System.out.println("testing");
}
}
You also should probably not be creating new Shift objects in your GUI's actionPerformed methods, but rather use only one Shift object that is a class field.
The btnClear method clears the text area of a new CrackerGUI instance. It's like if you wanted to clear a drawing on a sheet of paper by taking a new blank sheet and clearing it. The original sheet of paper will keep its drawing.
You need to pass the gui instance to your Shift:
public class Shift {
private CrackerGUI gui;
public Shift(CrackerGUI gui) {
this.gui = gui;
}
public void btnClear() {
this.gui.setPlainText(" ");
}
}
and in the CrackerGUI class :
private void btnClearActionPerformed(java.awt.event.ActionEvent evt) {
Shift classShift = new Shift(this);
classShift.btnClear();
}
Assuming CrackerGUI is your GUI, you should have the following instead:
public class CrackerGUI {
public void setPlainTextBox(String text)
{
plainTextBox.setText(text);
}
public void btnClear()
{
setPlainTextBox("");
System.out.println("testing");
}
}
One last thing, never make your GUI elements public! You should ask the GUI to clear itself and leave that knowledge of clearing elements hidden inside it.
You could try using static methods, as you would end up creating a new gui, then displaying that one, in stead of the current one already displayed.
This would require the parent class to be static too, which may cause errors in some of your methods, just a heads up.
Or else, you could create your own setText method:
void setText(JTextField t, String s){
t.setText(s);
}
that may enable you to directly edit components in the current GUI.