I want a java gui event to, when activated, call a class for processing. I am having an issue because I need to use an object "Settings" that is created earlier in the code and have it for the rest of the program. Basically when types in textfield and presses enter, this event starts and calls a class to handle the user's input. I have looked at other forum answers and their solutions involve creating "new" objects, which is not what I am trying to do. Display.TaskInput needs the "Settings" object to work. This is the event:
public class event implements ActionListener {
public void actionPerformed(ActionEvent e) {
//The text below calls a task that needs to use the settings object
//This object presets the task object for easier user input.
//Yes, this is wrong, but you can see what I am trying to do.
Display.TaskInput(settings);
//The rest of this is just for testing. It works when the above line
//is removed.
label.setText("This worked also");
label2.setText("This worked also");
panel1.add(label2);
add(panel1);
panel1.setVisible(true);
}
}
This is where the Settings Object is created. It is preset by a database. When the user enters a task, the task will have several presets ready so that the user does not have to manually enter them. This is the start of the program:
public static void main(String[] args) {
//object is created and loaded with data
Settings settings = new Settings();
DatabaseConnectSettingsSelect.Connect(settings);
//this is where the gui is initiated.
FrameStart.main(args);
//Once the gui starts working, this class will become unnecessary
Display.StartScreen(settings);
}
This is the main in the GUI class FrameStart:
public static void main(String[] args) {
FrameStart ex = new FrameStart();
ex.setVisible(true);
}
Everything would be fine if I didn't need to use a premade object. Most of the solutions could solve that, but I need to import an object created in another class. If you need more code to look at I happily provide it; this is just where the problem area is that I have run into.
To sum things up, I need to place an already created object into an event class or directly into the TaskInput class. Is there a better way than what I am doing? This program has about 15 classes and the way I am currently doing things works well, its just that I don't know how to place a created object into the ActionEvent code. Once again, I have looked at other forum answers and their solutions involve creating "new" objects which is not what I am trying to do.
Related
I am relatively new to Java and I am using IntelliJ's GUI Form wizard to create a form that uses a main() method to create the Form.
I can get the Form to create, and have added a listener to the submit button, but I am not sure about how to get the form values back out into the rest of the application.
Because the form uses main, I can only pass in Strings, and it doesn't return anything so I can't get a reference to the frame so I can't create a method to pass in a reference to the object to populate.
Because the form uses main, I can only pass in Strings, and it doesn't return anything so I can't get a reference to the frame so I can't create a method to pass in a reference to the object to populate
You should go back to the basics of OOP. The GUI designers really hide this from you, and it takes much refactoring to get them functionally clean.
You can create any instance of your class. And run that via main()
For example.
public class Gui {
private JFrame frame;
private JTextField textField;
public Gui(String title) {
frame = new JFrame(title);
}
public void run() {
// display Frame, add panels, etc
}
public String getDataFromGui() {
return textField.getText(); // for example
}
// other methods
public static void main(String[] args) {
Gui g = new Gui("Hello World!");
g.run();
}
}
Added a project to showcase this. [Link here]
In order to get data back to the first frame we would need to use the same memory reference.
Simplifying the explanation:
Imagine you have a bucket.
The first frame tells the second frame in what bucket to place the data.
The Second Frame doesn't know the data yet but knows in which bucket to place it.
The User adds the data and clicks Ok button.
The Second Frame takes the data and places them in the bucket.
Back in the first frame we take the data from the bucket.
In the project, the Bucket is the instance of DataObject, which is passed to the SecondForm and upon clicking its button we add the value to that bucket.
Finally, a WindowFocusListener to update the field when we get back to the first frame.
Code is self-explanatory.
With functional programming, the code can be improved further. Checkout this branch .
I'm currently working on a chess project.
I've set up a working code from console, and im working on setting up a GUI with swing. Debugging my application, I saw that my main and my GUI runs in different threads, so I came to the following question.
Is there a way to put my main thread to sleep while waiting for the user to click on a chess piece, then resume after the click?
To contextualize, I have a 8x8 array of buttons (board[i][j]) and for each button I set up a custom action that saves i and j into 2 static variables I declared into my main. So that after the button is clicked, I send the coordinates of that button to my main code that operates on the "real" matrix of chess pieces calling methods for controls.
Is that the correct way to go about this?
Is there a way to put my main thread to sleep while waiting for the user to click on a chess piece, then resume after the click?
It is the wrong way to think. A GUI should be event driven, rather than working in an infinite loop waiting for input (or for main to get input).
But the problems are (usually) from trying to 'match up' a command line based app and an app. with a GUI.
I say that because it sounds like the command line based app. did not go to the trouble of creating data structures for a ChessGameModel that can be acted on by the players and potentially shared amongst different classes that might need to interact with it. Classes like .. a command line based front end, or the various classes of a GUI, or a server that is running chess games between people over the net or..
Build the ChessGameModel and the rest will be a lot simpler.
What if when you click on a button you set a variable which is checked continually by your "main thread".
//In your GUIClass (GUI Thread)
btnInput1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
oProcess.setInput("Forward");
}
});
//In your Process Class (Main Thread)
private String input;
public void setInput(String input){
this.input = input;
}
public void checkInput(){
while(true){
if(input.equals("")
{
//Do nothing
Thread.Sleep(1); //Sleep so your loop doesn't use 100% of your processor
} else {
if(input.equals("Forward")
{
//Do the action
}
}
}
}
But you need to share the instance of your process class with the GUI Thread so you can use the same variable.
(Sorry for my spelling)
The answer to this is: Yes, but you shouldn't.
Putting a Thread to "sleep" is wasting CPU cycles. Instead you should strive to make the stuff you do on your main-thread after recieving input in a more "event-driven" way.
First off you should already have some class that contains the board. If you haven't: now's the time ;)
The next thing you want to do is to not make that class your GUI, because the GUI shouldn't be concerned with the gamelogic.
and then it's getting simple, assuming following GUI field:
private Board board = // your actual board;
// assuming Java 8
button.addActionListener((event) -> {
board.recieveAction(i, j);
});
I'm working on a simple Java swing project. This is the code of the main class (name changed):
public class MainProg
{
private static MainProg program;
//mainWin is a JFrame
private MainWindow mainWin;
//Event handler class which extends MouseAdapter
private TrayManager trayMgr;
public static void main(String[] args)
{
program = new MainProg();
}
public MainProg()
{
mainWin = new MainWindow();
trayMgr = new TrayManager();
mainWin.startBtn.addMouseListener(trayMgr);
mainWin.setVisible(true);
}
}
As is clear, when the program starts, in main() it creates a new instance of the MainProg class, which then calls the constructor. In the constructor, it creates a new instance of the JFrame mainWin. It then attaches an event handler to a button on mainWin.
In the event handler class trayMgr, the only method is mouseClicked() which does nothing
except a System.out.println('Clicked');
The issue is, when I run this program in Netbeans, the JFrame is shown right away, but I seem to have to click the button 2-3 times before the message is printed in the console.
Is this just something specific to Netbeans, or do I have to change something to make the event handler be set before the window is made visible?
Your threading issue is not likely one that is causing your current problem, but there's the theoretic potential for problems, and I've seen some real problems associated with some of the more touchy look and feels. Quite simply you should queue your code that starts your GUI onto the Swing event thread. You do this by doing:
public void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(
public void run() {
program = new MainProg();
}
));
}
Someone else recommended using invokeAndWait(...) instead of invokeLater(...) but this can be risky especially if you inadvertently make this call from within the Swing event thread itself. For your situation you're better off using invokeLater(...).
But again, I think the main problem with the code you have shown was inappropriate use of MouseListener where an ActionListener should have been used. Learning to code any GUI library can be quite tricky, and for that reason, you can't assume anything. Check out the tutorials and learn from the experts. Also if you are considering coding Swing for the long haul, consider ditching the NetBean's code-generation utilities and learn first to code Swing by hand. You won't regret doing this.
Since you asked, the code I posted here is a Java SSCCE on a different topic. invokeLater is a way of running computations on the EDT. (There is also invokeAndWait, which would work fine here, but under some other conditions can cause a deadlock.)
In fact this example is perhaps a bit over-conservative. Some references say you can run Swing from the main thread the call to show() or setVisible(). However I have a program that misbehaves under Java 7 when I try that.
I'm writing a 2D polygon and physics editor, one functionality is to set a rotation limit for joints.
To use this functionality, the user clicks and drags a line between the joint points which need to receive the limit.
The logic of determining if the pick is valid happens outside of the GUI code.
If a pick is found, I wanted to pop up a JOptionPane.showInputDialog where the user can input the limit.
Thing is, if I do it directly, the program becomes unresponsive, I figure it's because of threading.
I's there a way to define an event listener the GUI can use that doesn't require an actual GUI component?
I want to send an event that also contains a reference to the target object to that component, then telling it that a valid pick has been made and user input is required, and then send the value back via a method of the target object.
I am very inexperienced with Swing.
My hunch is that I might be able to add an ActionListener to the main window, but I don't know how I could address that listener specifically.
As in, how would I need to define an Action that only gets processed by that particular listener?
If that is actually possible, of course.
So far I have only used listeners to let the GUI talk to the logic, not the other way around...
Edit:
The program becomes unresponsive the movement I call
result = JOptionPane.showInputDialog(this,"Enter Limit.");
That just breaks it. Can't even enter anything into the textbox, nor close it, etc.
I figure it's because it spawns a modal dialog that pauses some thread, and calling it from somewhere in the bowels of non GUI code is just not the thing I should do, but I'm too inexperienced to know another way...
Edit2:
I should add that I can use JOptionPane.showInputDialog without any problems if I spawn it, for example, after clicking a button or choosing a popup menu option.
In fact that's how I rename the items I am working with.
But I assume at that point, the dialog is being spawned inside the GUI thread, or this Event Dispatcher queue thing.
The problem with this though is, that this takes visible, interactive GUI components that fire that event.
What I'd like, however, is some sort of component that would spawn JOptionPane.showInputDialog just like a clicked button or context menu would, but without having to be interacted with by the user, but instead by the code.
I guess I could use invisible buttons and emulate mouseclick events, but that's pretty hacky...
Also, I tried spawning Threads and Runnables which spawned the JOptionPane.showInputDialog, but that didn't help either.
Unless I spawn the JOptionPane from a GUI source, everything stalls, and the dialog won't work.
The publisher will have a public add/remove listener, where the subscriber will add itself or be added via another channel to the EventListenerList in the publisher.
You can create your own listener interface that extends EventListener and a function to shoot an event. Below is an example:
import java.util.EventListener;
public interface MyEventListener extends EventListener {
public void myEventOccurred(MyEvent event);
}
You can then create your custom event class, "MyEvent" in the example above like:
import java.util.EventObject;
public class MyEvent extends EventObject {
// customer fields and methods here
public MyEvent(Object source) //more possible args here {
super(source);
//other things here to do what you want
}
}
Now you can have your subscriber implement MyEventListener and override the myEventOccurred(..) method.
Another approach would be to use the SwingWorker class to execute the logic of determining the pick in a dedicated thread without blocking the GUI dispatch thread, and use its callback method to execute the GUI action (open the input dialog).
See : http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
(This page has a better explanation of concept than I could write.)
It should be possible for your background thread to spawn a dialog with invokeAndWait():
final double[] result = new double[1];
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
result[0] = Double.parseDouble(
JOptionPane.showInputDialog("Enter value:"));
} catch(NumberFormatException e) {
result[0] = -1;
}
}
}
// ... do something with result[0]
Here I made the result an array just so that it can be final (accessible to the anonymous class) and also mutable.
I am trying to program a java application that consists of several windows using JFrame.
Each JFrame contains a JTextField and buton to go to the next JFrame.
I need to retrieve all the information entered by the user at the end.
I created an event click on the buton to save to a public class all the data that the user introduce in the JTextField. I named that public class myData, which has a static attributes.
The problem is that I can not access this class from the button listener function.
I get an error: cannot refer to an non final variable inside an inner class defined in a different method.
My goal is to be able to share the class myData between different methods of a different class.
E.g. I have a class named myClass1 and myClass2, so I want to share the myData attribute between myClass1 methods and myClass2 methods.
Please anyone can someone help me? or propose another way to do this!
Thanks in advance !
All of the calls about MVC etc. are valid, but this isn't that hard.
What you want to do is in your Main, you can create your Data (Model) class, the class that holds all of your information.
So, you can do something like this:
public class F1 ... {
private final Data myData;
public F1(Data theData) {
myData = theData;
}
....
}
public class Main {
Data myData;
public static void main(String args[]) {
Main m = new Main();
m.setMyData(new Data());
F1 f = new F1(m.getMyData());
...
}
}
Then, later, when F1 calls F2, simply do the same thing -- create F2 with the Data passed in earlier by the constructor. That way, as each Frame runs its course, they're all working on the same instance of Data. When all is done, the single instance of Data is left within the Main class for you to do with what you will.
There are better ways to reorganize your entire program, but this should give you ideas on how to get over the hump you're having right now.
Addenda:
There are several things you can do.
When your get the ActionEvent, it contains a source. That source is the component that generated the event (most likely a Button in this case). If you know where the button is located in the hierarchy of things, you get to your Frame directly. In the pastebin example, you have Frame -> Panel -> Button. So, if you have the Button, you cat get to the Frame.
public void actionPerformed(ActionEvent e) {
JButton sourceButton = (JButton)e.getSource();
F1 f1 = (F1)sourceButton.getParent().getParent();
Data myData = f1.getMyData();
data.setField(...);
}
Again, this is not the recommended ways of doing things. The tutorials have decent examples of using MVC and property change listeners and the whole kit. But this should get you to where you want to go.
Sorry, but your design needs alot of work. I'm going to recommend you read up on MVC. it may seem like alot to chew on right now but it will help you immensely in the long run. On a side note, dont nest your data class definition(s), and remember to always distinguish between classes and objects.
Your overall design of swapping JFrame's seems a bit iffy to me. Why not instead use either dialogs such as a JDialog or JOptionPane or even better a CardLayout to swap views. Also I urge you not to use static fields for any of this as this can cause significant problems in the future and makes your code less compliant with good object oriented principles. With regards to information sharing, about all I can say is that it's all about one class having the proper reference to the other class. For more specific advice you'll likely need to show us more information and code.
Edit
Also, you know of course that you can get a reference to the JButton that stimulated the ActionListener by calling getSource() on the ActionEvent object passed into the actionPerformed method. This may allow you to get a reference to the class that holds the JButton if necessary.