Trouble Adding text to JTextArea (append or settext) - java

So the program I am making uses 2 threads: One for the GUI and one to do the work.
I want updates from the work thread/class to print out on JTextArea in GUI class.
Everything I tried didn't seem to work. I added lines to print out text on the console right after lines to add text to the JTextArea to make sure it had got to the line but everytime console got text but no changes happened to JTextArea in the GUI.
public static void consoleText(String consoleUpdate){
GUI.console.append(consoleUpdate);
}
I tried this in the work class but nothing happened.
Anyone know how to fix my problem?
Edit:
MAIN.JAVA
public class main {
public static void main(String[] args) {
Thread t1 = new Thread(new GUI());
t1.start();
}
GUI.JAVA
public class GUI extends JFrame implements Runnable{
public static JTextArea console;
private final static String newline = "\n";
public void run(){
GUI go = new GUI();
go.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
go.setSize(350, 340);
go.setVisible(true);
}
public GUI(){
setLayout(new FlowLayout());
console = new JTextArea(ConsoleContents, 15, 30);
add(console);
}
WORK.JAVA
...{
consoleText("\nI want this text on the JText Area");
}
public static void consoleText(String consoleUpdate){
GUI.console.append(consoleUpdate);
}

First, as has been said, your GUI should only run on the Event dispatch thread.
As it is written, your GUI class does two things : it's a frame, and a runnable, and both
are used completely independently. As a matter of fact, calling "run" on a your GUI object creates another, unrelated GUI object. That's probably the reason why you see nothing.
So I suggest making your main the following:
... main(...) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUI gui= new GUI();
gui.setVisible(true); // and other stuff
}
});
}
(I would also suggest getting rid of all "static" fields BTW. It's probably the source
of your problems, along with the weird place of the "run" method).
Now, your "consoleText" method, which I assume you call from another thread, should not
modify the text directly, but call SwingUtilities.invokeLater() to do so :
public void consoleText(final String consoleUpdate){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.append(consoleUpdate);
}
});
}
(the "final" declaration is important, as it allows the Runnable to use the consoleUpdate variable).

Related

Use swing in a different thread

I'm developing a cli-based custom web crawler in Java. Since it needs to have a user-friendly graphical interface for showing the result, I should add a swing frame to that involving some trees, labels, tables and so on.
That graphical interface is one of its switches, and must be started just in case user calls it. Thus, I have to start this interface in a new thread so that the application can proceed with other tasks and update components inside of GUI frame if needs.
My GUI class is some thing like:
public class Frame extends JFrame {
......
public static JLabel urlLabel;
......
public static void run() {
urlLabel = new JLabel();
urlLabel.setText("Test Url");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Frame().setVisible(true);
}
});
}
.....
}
And, I fork it from my main class like this:
.....
if(cmd.gui){
Frame.run();
Frame.urlLabel.setText("New Url");
}
......
Unfortunately, the text of label doesn't change. I already tested repaint(), revalidate() and such other functions like these, but, nothing turned up.
I tested getText() in order to make sure it is possible to access urlLabel from main class, and it worked (I could retrieved text of label).
I was wondering how I can sort out this issue? (Basically, I need to start a swing frame in a different thread and control its components from the main thread)
Thanks in advance.
If you use invokeLater(), your Runnable will be started in the EventThread after the current operation in this thread is finished. If your label is not updated, it might be that your EventThread is busy doing something else - e.g. crawling the web.
You definitely need to make sure that your crawling work is done in another thread (start a new one, don't use the one that runs anyway, since this is most probably the EventThread). Then you might use invokeLater() in this other Thread to change the label in the EventThread.
Hint: You can check if you are in the EventThread by using SwingUtilities.isEventDispatchThread().
Remember that your data/models will be used by different threads and that this might cause problems when the data is changed in your worker thread while your GUI is trying to display it.
Thank you guys for helping.
Finally, I could overcome this obstacle by using SwingUtilities.invokeLater for updating the label's text.
I mention the approach here, since someone else might need it:
The main class:
public class Frame extends JFrame {
......
private static JLabel urlLabel;
......
public JLabel getU(){
return urlLabel;
}
public static void run() {
urlLabel = new JLabel();
urlLabel.setText("Test Url");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Frame().setVisible(true);
}
});
}
.....
}
The GUI class:
if(cmd.gui){
Frame().run();
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
gui.getU().setText("New Url");
}
});
}
.....
Just a question about this manner:
Since I need to update some labels and tree nodes a couple of times during crawling, wanted to know if starting a new Runnable for each of those would be overload? If yes, how can I manage that?
---UPDATE---
According to the #xander's comment, it is possible to use lambda instead of Runnable. I think lambda doesn't have overload as much as a new object does.

How to call a GUI (Swing) from a Class to the Main Class?

I've seen similar questions answered but could not find an answer to my question. I have a Main Class, which has it's own JFrame. However, I've created a different Class where I've created another JFrame that prompts the user for some data. The Main Class is the main app. The secondary class is supposed to pop up before the main class GUI runs. I've created 2 different packages for each one of the Classes.
So, I'm trying to call an Object of the secondary Class from Main Class but the interface does not appear. I do not get any errors in the code and the App runs as if the Object of secondary Class is not being called at all. I am new to Java and would appreciate some lights on this.
My code is as follows:
Main Class
public class TempConverter extends javax.swing.JFrame {
public TempConverter() {
initComponents();
}
// More code
public static void main(String args[]) {
DemoUserData test = new DemoUserData();
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
test.setVisible(true);
new TempConverter().setVisible(true);
}
});
}
Secondary Class
public class DemoUserData extends javax.swing.JPanel {
public DemoUserData() {
initComponents();
}
}
Your JFrame is the main window. Before it is shown at the very early start a splash screen maybe shown, normally a small rectange with a logo.
It however seems, you want some input dialog, like say a login. That cannot be a JPanel, but must be a top-level window: JFrame or JDialog. Or one of the JOptionPane dialogs (asking string input, or whatevever).
Maybe you should make a JFrame for your current JPanel, run that.
.
DemoUserDataFrame test = new DemoUserDataFrame(this);
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
test.setVisible(true);
}
});
public class DemoUserDataFrame extends JFrame {
//private final JFrame tempConverter;
public DemoUserDataFrame(final JFrame tempConverter) {
//this.tempConverter = tempConverter;
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
tempConverter.setVisible(true);
}
});
}
...
}
In the above, closing test, will make the main JFrame visible.
In order to have a better overview, have the classes not refer one to another, you might look into the Model-View-Controller concept. Then there is one global "Controller" class as intermediator for all business logic. It holds the data (Model), and so on.

Another way to use SwingUtilities.invokeLater(Runnable r)?

All my sample programs create a big JFrame which contains all the code for its components, instead of creating separate classes for components and then adding these components to the big JFrame. This big JFrame is run or displayed by instantiating it inside an anonymous Runnable as shown below.
public static void main(String args[]) {
// Create the frame on the event dispatching thread.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new StopWatch(); // Or any other JFrame
}
});
}
Class StopWatch implements ActionListener. Would it make any difference if I make it class StopWatch implements ActionListener, Runnable and then pass it as a runnable to the invokeLater method ? Is there is any other way of doing what the above code does ?

How to set the previous jframe visible when current jframe is disposed

I am making a Java gui project and it consists of two frames.
The problem is that when I call the secondframe from the firstframe, I have set it such that the firstframe visibility is set to false. The problem is how do I make the firstframe visible again by using a button from the second frame.
should i ditch this method and create a new jpanel instead??? Does jpanel have similar capabilities as jframe?
Consider using CardLayout. This way you can switch via multiple UIs without needing another frame. Here's how to use it.
Edit: As Guillaume posted in his comment, this answer from Andrew also covers how to use the layout.
Edit2:
As you requested a little more information about my latest post, here's how such a class may look like:
import javax.swing.JFrame;
public abstract class MyFrameManager {
static private JFrame startFrame,
anotherFrame,
justAnotherFrame;
static public synchronized JFrame getStartFrame()
{
if(startFrame == null)
{
//frame isnt initialized, lets do it
startFrame = new JFrame();
startFrame.setSize(42, 42);
//...
}
return startFrame;
}
static public synchronized JFrame getAnotherFrame()
{
if(anotherFrame == null)
{
//same as above, init it
}
return anotherFrame;
}
static public synchronized JFrame getJustAnotherFrame()
{
//same again
return justAnotherFrame;
}
public static void main(String[] args) {
//let's test!
JFrame start = MyFrameManager.getStartFrame();
start.setVisible(true);
//want another window
JFrame another = MyFrameManager.getAnotherFrame();
another.setVisible(true);
//oh, doenst want start anymore
start.setVisible(false);
}
}
This way you would only instantiate every JFrame once, but you could always access them via your manager class. What you do with them after that is your decision.
I also just made it thread-safe, which is crucial for singletons.

Problems with ActionListener and SystemUtil.invokeLater

I have look all over the web, and found no solution to my problem. For a AP Comp Sci project, I am making a Set of games, that will be run from a JFrame with JButtons. I have the games all ready, along with action listeners, but the games dont launch properly. The JFrame and JButtons are all setup correctly too.
private static class TetListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
GameCenter.quit();
GameCenter.startTetris();
}
}
GameCenter.quit() does nothing but run JFrame.dispose(), and GameCenter.startTetris(); constructs a new Tetris object, then run the play() method to start the game. All of Tetris is coded properly and works correctly when it is run in the main method (outside the actionlistener). But as soon as I put it in the ActionListener, it fails to be constructed properly. I tracked the problem down to:
public BlockDisplay(BoundedGrid<Block> board)
{
this.board = board;
grid = new JPanel[board.getNumRows()][board.getNumCols()];
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() // <<<<<<<<<<------------------- Problem Here
{
public void run()
{
createAndShowGUI(); // <<<<<<<<<<<<-------- Never Run
}
});
//Wait until display has been drawn
try
{
while (frame == null || !frame.isVisible()) // <<<<<<<-------- Never Resolved
{
Thread.sleep(1);
}
}
catch(InterruptedException e)
{
e.printStackTrace();
System.exit(1);
}
}
So the program always hangs. I also made a Pacman game that uses this SwingUtilities.invokeLater, so it doesnt work either. I cant figure out why this is happening or how to fix it.
Any help is appreciated. Let me know if you need any more info.
If the thread that runs SwingUtilities.invokeLater is already the swing event thread and you run in this while loop, yup, your application will hang.
Get rid of the while loop.

Categories