Problem with Java GUI - java

I have made a java program with GUI. Now I want to add a component on the GUI where I can display whatever I want in the same way we display output through
System.out.println();
Which component I can add on the GUI and how to display content on that component.

You could define a PrintStream that prints to a JTextArea:
final JTextArea textArea = new JTextArea();
PrintStream printStream = new PrintStream( new OutputStream() {
#Override
public void write( final int b ) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append( "" + (char )b );
textArea.setCaretPosition( textArea.getText().length() );
}
});
}
} );
System.setOut(printStream);

For just one line you can use a JLabel and set its text property. How to use JLabel: http://www.leepoint.net/notes-java/GUI/components/10labels/jlabel.html
Or if you need to print multiple lines you can use a JTextArea-box.
Its also possible to draw/paint text ontop of the GUI-panel with Java2D and the Graphics object.

You can use a JTextArea and add text to it each time you print something. Call setEditable(false) so it's read-only. Add it to a JScrollPane so it's scrollable.
Or you could use a JList and add each line as a separate list item. It won't do word wrapping but if you're displaying something akin to an event log it'll look good for that purpose.

Related

Swing is very slow with long strings

I built a simple Java program that logs in a JTextArea component.
JTextArea _log = new JTextArea();
_log.setEditable(false);
JScrollPane scrollLog = new JScrollPane(_log);
scrollLog.setPreferredSize(getMaximumSize());
add(scrollLog);
The problem is that logging like this takes 15ms on average:
public void log(String info) {
_log.append(info + "\n");
}
This is far(!) slower than logging using System.out.println. Logging takes more time than the whole running time of the algorithm!
Why is the JTextArea is so slow? Is there a way to improve it?
EDIT 1:
I am using separate thread for the algorithm, and using SwingUtilities.invokeLater to update the log in the UI.
The algorithm tread finish his work after 130ms on average, but the JTextArea finish his appends after 6000ms on avarage.
EDIT 2:
I tried to test this by use setText of string that contains 2500 charaters. In that case the operation took 1000ms on average.
I tried to use another controller then JTextArea and I get same results.
Is it hard for Swing components to deal with large strings? What can I do about it?
EDIT 3:
I just test with this code:
public class Test extends JFrame {
public Test() {
final JTextArea log = new JTextArea();
log.setEditable(false);
log.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
JScrollPane scrollLog = new JScrollPane(log);
scrollLog.setPreferredSize(getMaximumSize());
JButton start = new JButton("Start");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long start = System.nanoTime();
for (int i = 0; i < 2500; i++) {
log.append("a\n");
}
long end = System.nanoTime();
System.out.println((end - start) / 1000000.0);
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 1));
panel.add(scrollLog);
panel.add(start);
add(panel);
}
public static void main(String[] args) {
Test frame = new Test();
frame.setSize(600,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
The time of that for loop is 1870ms on avarage.
This is the only code that I ran (include the declaration of _log at the top of the question)
A JTextArea is not slow.
Far(!) away from System.out.println.
System.out.println() executes on a separate Thread.
The log takes more time then the hole running time of the algorithm!
So your algorithm is probably executing on the Event Dispatch Thread (EDT) which is the same Thread as the logic that appends text to the text area. So the text area can't repaint itself until the algorithm is finished.
The solution is to use a separate Thread for the long running algorithm.
Or maybe a better choice is to use a SwingWorker so you can run the algorithm and "publish" results to the text area.
Read the section from the Swing tutorial on Concurrency for more information and a working example of a SwingWorker.
Edit:
//log.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
The above line is causing the problem. I get 125 for the first test and 45 when I keep clicking the button.
That property is not needed. The text is still displayed on the left side of the text pane. If you want right aligned text then you need to use a JTextPane and set the attributes of the text pane to be right aligned.
That is why you should always post an MCVE. There is no way we could have guessed from your original question that you were using that method.
Edit2:
Use the alignment feature of a JTextPane:
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
textPane.getStyledDocument().setParagraphAttributes(0, doc.getLength(), center, false);
Now any new text you add to the document should be center aligned. You can change this to right.

Java Timer unknown event

When I execute the following method in my program some components change when the timer runs out. For example a jTextArea I created changes in size without any events containing a construction to change its size. It doesn't matter if I first expand the jTextArea and then start the timer or vice versa.
//Show Debug Information for given Seconds with given Text
void giveUserInformation(String input, boolean function, int duration) {
//Debug information and label visibility handling
jLabelDebug.setVisible(true);
jLabelDebug.setText(input);
//Image
if (function)
jLabelDebug.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/images/ok-icon.png")));
else
jLabelDebug.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/images/Actions-edit-delete-icon.png")));
//Show duration
if (timerShowDurationRuns) {
timerShowDuration.cancel();
timerShowDuration = new Timer();
}
timerShowDurationRuns = true;
//fadeIn();
timerShowDuration.schedule(new TimerTask() {
#Override
public void run() {
jLabelDebug.setVisible(false);
timerShowDurationRuns = false;
//fadeOut();
}
}, duration * 1000);
setCursor(Cursor.getDefaultCursor());
}
When you create the JTextArea you should use code like:
JTextArea textArea = new JTextArea(5, 30);
Now the text area will be able to determine its preferred size and will remain fixed as you add text to it.
Then when you add it to the GUI you use code like:
frame.add( new JScrollPane( textArea ) );
Now as you add more data the text area size will remain fixed, but scroll bars will appear when required.

How do I add text to a JTextArea?

I'm making a java Text Editior and I can't seems to know how to insert a line of text that is "[code][/code]" Here is what I'm trying to program. The method for the inserting is called "insert". So it has to be something that is insert,(something that inserts strings of text in JTextArea)
/////////////////// CODE //////////////////////////////////////////////////////////////////////////////////////////////////
this.insert.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
/////////////// END OF CODE ///////////////////////////////////////////////////////////////////
Simple example to set/assign text to JTextArea .. this is not the solution but it will help you...
JTextArea textArea = new JTextArea(
"This is an editable JTextArea. " +
"A text area is a \"plain\" text component, " +
"which means that although it can display text " +
"in any font, all of the text is in the same font."
);
textArea.setFont(new Font("Serif", Font.ITALIC, 16));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
Although to set the text .. use this method
void insert(String str, int pos)
Inserts the specified text at the specified position.
public void setText(String t)
Sets the text of JTextArea
For refrerence and help please follow jtextareaguide
Link to video tutorial
Guide for Simple Editor in Java
Java already provides a method for inserting text in the JTextArea class. Try this...
JTextArea t = new JTextArea();
t.setText("specified string");
t.append("+ added string");
use:
JTextArea text=new JTextArea();
text.setText("Message..");
Here is a doc.
public class JTextArea extends JTextComponent
A JTextArea is a multi-line area that displays plain text. It is intended to be a lightweight component that provides source compatibility with the java.awt.TextArea class where it can reasonably do so. You can find information and examples of using all the text components in Using Text Components, a section in The Java Tutorial.
Try this:
JTextArea textj1 = new JTextArea();
textj1.setText(textj1.getText().trim() + "a string or even an arraylist");
Better using:
textArea.setText(textArea.getText()+" Message");

JOptionPane using one window for input and output

So I'm working on a little project and I'm looking for the base code for how to do this in JOptionPane. I'm still really new to this side of Java. I'm not looking for a whole lot, I just didn't know where to start.
The program should populate the screen with a JOptionPane window. I need it to be modeled like the picture below. The bottom row is a text input from the user and when they hit the enter key, the text should "refresh/clear" and then the middle string area should populate with both the user input and then just below it the result of an if statement according the the code.
for example: The user enters in: "Hello".
Then the text input should refresh and the grey box should do this: "User: Hello."
"Computer: Hello user".
I would really appreciate any and all help on this.
You don't System.out.println() into a gui component. Doesn't work like this. You can write a console program and use JOptionPanes to get user input, but the output would be used in the console program. You would need to create a gui program mimic a console.
Here's a basic layout to start you off
public class Game extends JFrame {
JTextArea jta = new JTextArea(10, 30);
JTextField jtf = new JTextField(30);
public Game(){
add(jtf, BorderLayout.SOUTH);
add(jta, BorderLayour.CENTER);
jta.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
}
});
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame frame = new Game();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
});
}
}
What I would suggest is since this is a very basic program, I would use an array of String commands and iterate through them.
For example:
String[] question = {"Do you want to go to school?",
"Do you want to drive or walk?"};
jta.setText(questions[0]);
Then in your actionPerformed get the answer from the text field. Use an if statement like
if (jtf.getText().equals("yes") {
jta.append(questions[1]);
}
And so on. If you have no idea what I'm talking about, I would really consider using the Swing tutorials I mentioned. There's a lot of info in those tutorials.

Java / Swing : JTextArea in a JScrollPane, how to prevent auto-scroll?

here's a runnable piece of code that shows what my "problem" is.
I've got a JTextArea wrapped in a JScrollPane. When I change the text of the JTextArea, the JScrollPane scrolls automatically to the end of the text and I don't want that.
Here are my requirements:
the application should not scroll vertically automatically but...
the user should be able to scroll vertically
the user should not be able to scroll horizontally
the application should never scroll horizontally
the JTextArea must not be editable
(so even if there's more text than what can fit horizontally, neither the application nor the user should be able to scroll horizontally. While vertically, only the user should be able to scroll.)
I don't know how to "fix" this: should this be fixed using JTextArea or JScrollPane methods?
Note that AFAICT this is not a duplicate at all of: JTextPane prevents scrolling in the parent JScrollPane
Here's the kinda funny example, every 200 ms it puts new text in the JTextArea and you can see the JScrollPane always scrolling automatically to the end of the text.
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public final class TextInScrollPane extends JFrame {
private static final Random r = new Random( 42 );
public static void main( final String[] args ) {
final JFrame f = new JFrame();
f.setDefaultCloseOperation( EXIT_ON_CLOSE );
f.setLayout(new BorderLayout());
final JTextArea jta = new JTextArea( "Some text", 30, 30 );
jta.setEditable( false ); // This must not be editable
final JScrollPane jsp = new JScrollPane( jta );
jsp.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
jsp.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS );
f.add( jsp, BorderLayout.CENTER );
f.pack();
f.setLocationRelativeTo( null );
f.setVisible(true);
final Thread t = new Thread( new Runnable() {
public void run() {
while ( true ) {
try {Thread.sleep( 200 );} catch ( InterruptedException e ) {}
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < 50 + r.nextInt( 75 ); i++) {
for (int j = 0; j < r.nextInt(120); j++) {
sb.append( (char) 'a' + r.nextInt(26) );
}
sb.append( '\n' );
}
SwingUtilities.invokeLater( new Runnable() {
public void run() {
jta.setText( sb.toString() );
}
} );
}
}
});
t.start();
}
}
How to set AUTO-SCROLLING of JTextArea in Java GUI?
http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/text/DefaultCaret.html#NEVER_UPDATE
Try:
JTextArea textArea = new JTextArea();
DefaultCaret caret = (DefaultCaret)textArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
This should prevent the caret from automatically making the document scroll to the bottom.
Answering my own question: I'm not exactly sure this is the best way to solve my issue, but setting the JTextArea's caret using setCaretPosition(0) seems to work fine:
jta.setText( sb.toString() );
jta.jta.setCaretPosition( 0 );
You have run into a very strange behaviour in the implementation of the Document classes. I use a DefaultStyledDocument in a JTextPane inside a JScrollPane.
Now, here is the wierd thing. If I update the document on the EventQueue (like you do by scheduling a runnable to run later) the scroll pane automatically scrolls to the end.
However, the document classes claim to be thread safe and actually updatable from another thread. If I make sure to update on another thread than the EventQueue everything works fine but the scroll pane does NOT scroll to the end.
I have no explanation as to why this is so, I haven't looked in the Swing source. I have been exploiting this "feature" since 2006 and it has been consistent so far :-)

Categories

Resources