After thinking I was on course to solving a problem with making text (read from a file) appear in a JPanel, I`m frustratingly back to square one.
The code is below. The result is just a blank screen 400x500 screen. Some combinations of using nextLine() + nextLine() as displayText commands result in one word coming up from the file (the word has been different multiple times). This makes me wonder: do I need code that deals with text wrapping? The textfile itself is in paragraphs, and as such, I thought that sf.displayText should say sf.displayText(reader.next() + reader.nextline() + reader.nextline(), and have tried other combinations, but this may be confusing the while parameters. Have also tried a different textfile with simple sentences, no paragraphs, but again, nothing comes up.
Having looked online, I have found that layouts may be an issue, and that alternative options may be BufferedReader or using JTextArea. Browsing through Big Java didn`t provide anything I felt I could take, as all discussion on the scanner went towards integers, whereas the file I want read is prose. I also tried putting a small piece of text in the code itself and cancelling out everything else below it to see if I could transfer text from the code to the JPanel:
StoryFrame sf = new StoryFrame();
sf.displayText("Life is beautiful");
but still nothing came up. Ultimately, I want to put text from a file into a JPanel, and have each paragraph come up 5 seconds after the one before. So ultimately, my questions are:
Why does my text fail to show up, or only display one word? Is it because I don`t specify a layout?
Do I need to think about text wrapping?
Should I look into JTextArea instead of JPanel, and BufferedReader instead of Scanner?
Have I been using the nextLine method from the Scanner correctly?
Can I put a command to read a file and display that file`s text in the display
method of StoryFrame (I think this would make things a lot easier)?
I know it`s a lot, so any answers to any of the questions would be greatly appreciated, thank you.
Tom
import javax.swing.JFrame;
import javax.swing.JLabel;
public class StoryFrame extends JFrame {
private JLabel mylabel;
public StoryFrame() {
setTitle("見張ってしながら...");
setSize(400,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
mylabel = new JLabel();
this.add(mylabel);
setVisible(true);
}
public void displayText(String text) {
JLabel storyText = new JLabel();
add(storyText);
}
}
ShowIntro
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
class ShowIntro {
public static void main(String args[])
throws IOException {
StoryFrame sf = new StoryFrame();
Scanner reader = new Scanner(new File("Try.txt"));
while (reader.hasNextLine()) {
//String line = in.nextLine() Not sure whether this would contribute, I doubt it does though
sf.displayText(reader.next());
//sf.displayText(reader.next() + reader.nextLine() + reader.nextLine()); was also attempted.
try {
Thread.sleep(5000);
} catch (InterruptedException e) { }
}
}
}
it fails because you never call a method to use the text in your displaytext method
public void displayText(String text) {
mylabel.setText(text);
}
You are also reading the file one word at a time:
sf.displayText(reader.next());
should be:
sf.displayText(reader.nextLine());
if you want to read upto the next newline character.
Even though this was not in the original question to satisfy some of the comments below here is a modified version of the program
package com.vincentramdhanie.kitchensink;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
public class StoryFrame extends JFrame {
private JTextArea area;
public StoryFrame() {
setTitle("見張ってしながら...");
setSize(400,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
area = new JTextArea(10, 30);
area.setEditable(false);
area.setCursor(null);
area.setOpaque(false);
area.setFocusable(false);
this.add(area);
setVisible(true);
}
public void displayText(String text) {
area.setText(text);
}
public static void main(String args[])
throws IOException {
StoryFrame sf = new StoryFrame();
Scanner reader = new Scanner(new File("Try.txt"));
while (reader.hasNextLine()) {
String line = reader.nextLine();
sf.displayText(line);
try {
//to skip blank lines. If the line has no non-space characters then do not sleep
if(!line.trim().equals("")){
Thread.sleep(5000);
}
} catch (InterruptedException e) { }
}
}
}
Related
I would like to check the validity of user input every time they change a value on the JTable. The method I thought of is similar to this simplified sample code:
public static void main(String[] args) {
JFrame main = new JFrame();
JTable table = new JTable(6, 4);
table.setSize(300, 300);
table.getModel().addTableModelListener((TableModelEvent e) -> {
Object s = e.getSource();
TableModel d = (TableModel) s;
if(!checkValid(d.getValueAt(e.getFirstRow(), e.getColumn())))
{
d.setValueAt(" - ", e.getFirstRow(), e.getColumn());
}
});
main.add(table);
main.setSize(300,300);
main.setLocationRelativeTo(null);
main.setVisible(true);
main.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
The code will check the input if a change in the table occurs and will revert back to "-" if the input is invalid.
However, an error will occur stating that Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError.
a.) Could someone explain the error and how to solve the issue?
b.) Or is there a better way of implementing a listener that checks the user input BEFORE exiting editing mode or saving the table?
EDIT: I have tried implementing the CellEditorListener like the sample below:
table.getCellEditor().addCellEditorListener(new CellEditorListener() {
public void editingStopped(ChangeEvent e)
{
}
public void editingCanceled(ChangeEvent e)
{
}
});
This in turn prompted an error Exception in thread "main" java.lang.NullPointerException. There isn't that much of documentation on CellEditorListener and didn't quite understood on how it works and how to use it.
According to the corresponding section of the corresponding Java tutorials, you can override stopCellEditing of DefaultCellEditor to return false if the editor should not lose focus or true otherwise. Which means we can use it to check user input first and then, according to the user's input, return false if he/she enters invalid text (or true if he/she enters valid one).
In the following example code I'm using a JTextField, which lets the users type whatever they want and then checks the user's input in stopCellEditing to be non-empty (as defined by my static checkValid method, but you can obviously alter it according to your needs):
import java.awt.Toolkit;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
public class Main {
public static boolean checkValid(final String text) {
return text != null && !text.trim().isEmpty(); //Your checks here...
}
public static class MyCellEditor extends DefaultCellEditor {
public MyCellEditor() {
super(new JTextField());
}
#Override
public boolean stopCellEditing() {
final JTextField field = (JTextField) getComponent();
if (checkValid(field.getText())) {
//field.setBackground(Color.WHITE);
return super.stopCellEditing(); //Fires 'editing stopped' event and returns true.
}
Toolkit.getDefaultToolkit().beep();
//field.setBackground(Color.ORANGE.darker());
JOptionPane.showMessageDialog(field, "You must enter a non-empty value!", "Oups!", JOptionPane.ERROR_MESSAGE);
return false;
}
}
public static void main(final String[] args) {
final JTable table = new JTable(new DefaultTableModel(10, 10));
table.setDefaultEditor(Object.class, new MyCellEditor());
final JFrame frame = new JFrame("JTable DefaultEditor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(table);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I use DefaultTableModel for easy initialization of the table. It also returns that each cell in the table is editable (we obviously need at least one cell to be editable, in order to check the validity of the program). Every cell starts initially empty, but the cell editor won't let you leave it empty, if you start an editing event.
An alternative solution could be to add an InputVerifier in the JTextField of the editor, but this would be a bit more tricky as I tested it, so I would rather not post it here in favor of the better above solution (and also suggested by the Java tutorial).
For my application, I keep getting this compilation error saying **FileNotFoundException is never thrown in body of corresponding try statement** I have this within the actionlistener event handling part so I'm not sure whether it's the correct way to do it.
I do understand that the catch exception bit is related to the try statement and it must be so called related so in this case, I'm initiating a new File object class from the user's input but the error stays.
Could you guys give me some advice as I'm still a novice and I just started on GUI not long ago?
Main class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
class MyFileLister extends JPanel implements ActionListener {
private JLabel prompt = null;
private JTextField userInput = null;
private JTextArea textArea = null;
public MyFileLister()
{
prompt = new JLabel("Enter filename: ");
prompt.setOpaque(true);
this.add(prompt);
userInput = new JTextField(28);
userInput.addActionListener(this);
this.add(userInput);
textArea = new JTextArea(10, 30);
textArea.setOpaque(true);
JScrollPane scrollpane = new JScrollPane(textArea);
this.add(textArea, BorderLayout.SOUTH);
}
Scanner s = null;
File af = null;
public void actionPerformed(ActionEvent f)
{
try
{
af = new File(userInput.getText());
}
catch(FileNotFoundException e)
{
System.out.println("Error");
}
}
}
And the driver class:
import java.util.*;
import java.awt.*;
import javax.swing.*;
class TestMyFileLister {
public static void main(String [] args)
{
MyFileLister thePanel = new MyFileLister();
JFrame firstFrame = new JFrame("My File Lister");
firstFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
firstFrame.setVisible(true);
firstFrame.setSize(500, 500);
firstFrame.add(thePanel);
}
}
It's because the constructor of File taking a String can only throw a NullPointerException.
public File(String pathname)
Creates a new File instance by converting the given pathname string into an abstract pathname. If the given string is the empty string, then the result is the empty abstract pathname.
Parameters:
pathname - A pathname string
Throws:
NullPointerException - If the pathname argument is null
Change your catch to
catch(NullPointerException e) {
and act accordingly.
The java.io.File object just represents an abstract path. Whether a file (or directory) denoted by it exists or not is irrelevant at its creation time.
The constructor of File does not check whether the path points to an existing file or folder.
It only matters if you want to open the file. Then you would get a FileNotFoundException (if it doesn't exist).
The error is pretty clear: the statement af = new File(userInput.getText()); does NOT throw FileNotFoundException (at any time). Java allows you to create File object that does not exist on your file system. How would you create a new file if not ;) So your try catch block is useless here. You might want to change the exception type to NullPointerException so you can handle case when null is passed to File constructor.
I just have a very basic question about how to use textfields in Java. It's very simple, but the tutorials and other questions I've been looking for haven't been helpful, and I'm hoping that someone can explain things a little more clearly for me.
Right now I have the following code that I just sort of slapped together for the sake of example:
import javax.swing*;
public class testText {
public static void main(String[] args){
JFrame frame = new JFrame();
JTextField text = new JTextField();
frame.add(text);
frame.setVisible(true);
System.out.println(text.getText());
}
}
All I'm trying to do, is print what the user types into the text field in the console. But nothing happens when I type into the text field.
Now,based on the research I've done, I think the problem is that I'm not using an actionListener. The thing is, I really don't understand how those work, and I'm hoping someone can clarify for me.
I've been using this tutorial to try and figure things out, and particularly the TextDemo example they have near the top. I'm still kind of at a loss though, and I can't seem to find any way to use the actionlistener interface without breaking the program. If someone could either just explain simply and directly how to use the actionlistener to pull a string from a text field and then use it, or else point me to somewhere else where I can FIND a simple straightforward explanation, I would immensely appreciate it. I've been beating my head against this for five hours now with absolutely nothing to show for it, so I apologize for asking such a basic question but I'm at a loss.
An action listener will be called when an enter key is pressed while typing in the field. From the JTextfield Javadoc :
How the text field consumes VK_ENTER events depends on whether the
text field has any action listeners. If so, then VK_ENTER results in
the listeners getting an ActionEvent, and the VK_ENTER event is
consumed.
Here is your example modified to work with an action listener :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class testText {
public static void main(String[] args){
JFrame frame = new JFrame();
final JTextField text = new JTextField();
frame.add(text);
frame.setVisible(true);
text.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(text.getText());
}
});
}
}
And here is an object oriented complete example not relying only on a static main method.
EDIT at end of post
Test Code and Output
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.text.NumberFormatter;
public class Test{
private JFormattedTextField input, input2;
private NumberFormatter formatter;
private PropertyChangeListener listener;
public Test(){
formatter = new NumberFormatter(NumberFormat.getNumberInstance());
input = new JFormattedTextField(formatter);
input2 = new JFormattedTextField(formatter);
listener = new PropertyChangeListener(){
#Override
public void propertyChange(PropertyChangeEvent evt) {
convert(evt);
}
};
input.setColumns(4);
input2.setColumns(4);
input.addPropertyChangeListener("value", listener);
input2.addPropertyChangeListener("value", listener);
input.setValue(0.0);
JPanel panel = new JPanel();
panel.add(input);
panel.add(input2);
JOptionPane.showMessageDialog(null, panel);
}
private void convert(PropertyChangeEvent evt){
if (evt.getSource()== input){
if (evt.getSource()!= null){
double temp;
temp = converter((Double)evt.getNewValue());
input2.setValue(temp);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
public void run(){
new Test();
}
});
}
private double converter(double value){
value = value*2;
return value;
}
}
The stack trace:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Double
at test.Test.convert(Test.java:46)
My thoughts
Because I have a method that passes in a double (it's convert()) , and seemingly evt.getNewValue() returns the direct value, which at the time of input is technically a long, it's throwing that error.
But every attempt at parsing my evt.getNewValue() to a double hasn't worked. Perhaps a little knowledge of what I'm trying to do with this program would help.
What The Program is for
So I've got a JPanel (in a tabbedPane) that has two JFormattedTextField inputs. It's a conversion application. My conversion class method passes in a double and returns a double. I'd like the fields to be linked together, or in other words, as soon as one field's input is changed the other changes with it (as in it's the output of the conversion).
I was considering scrapping the PropertyChangListener and going for a DocumentListener instead, but opted to try the former first as the latter has 3 overrideable methods I have to take care of, one of which might cause some unexpected results (highlighting and deleting the field would trigger two events for example).
TL;DR:
Is there a better way of getting a dynamically updating, dual input field application? Input one number into one field and the other field's number automatically updates.
Still a novice at Java.
Edit1
I've found a temporary solution: Have a DecimalFormat as the format in the JFormattedTextField. But if it could work without having a decimal as well I'd love it.
Edit2
Question answered, didn't realize evt.getNewValue() was returning a Number instance.
All you know for sure is that the object returned by evt.getNewValue() is a Number object. What if you use that information to your advantage and try something along these lines:
temp = ((Number)evt.getNewValue()).doubleValue();
After more than a couple of days I am still unable to populate a text area by going through an array as I can in other languages. I have tried Google, YouTube, stackoverflow, and others and I am still unable to use any examples to help me do this. I have also referenced Java texts. Here is exactly what I am trying to do:
public void getDrinks() {
//System.out.println(theDrinks[arrayCount].toString());
for(int i=0; i<arrayCount; i++) {
area.append(theDrinks[i].toString());
}
}
This code works in other languages but something is wrong with the way I am using the TextArea or the array because I am getting a null pointer. I would love to paste the entire program, but that is not working either. This is the only part that will even remotely paste correctly. Please help me if you can.
You do not, in general, want to use a variable like arrayCount when you can help it. A better version is this:
public void getDrinks() {
for(int i = 0; i < theDrinks.length; i++)
area.append(theDrinks[i].toString());
}
When doing this, it is important to make sure that area has been instantiated already (i.e. it is not null).
If I were implementing this, I would use Java's foreach construct instead, as I find it's a bit more expressive. The following code assumes that theDrinks is an array of Drink objects.
public void getDrinks() {
if(area != null) {
for(Drink drink : theDrinks) {
area.append(drink.toString());
}
}
}
I can't way whay your specific problem can be without more code but here some java code that works.
import java.awt.BorderLayout;
import java.awt.TextArea;
import javax.swing.JFrame;
public class Driver {
public static void main(String[] args) {
// 1. Create the frame.
JFrame frame = new JFrame("FrameDemo");
// 2. Optional: What happens when the frame closes?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 3. Create components and put them in the frame.
// ...create emptyLabel...
TextArea area = new TextArea("Area");
frame.getContentPane().add(area, BorderLayout.CENTER);
// 4. Size the frame.
frame.pack();
// 5. Show it.
frame.setVisible(true);
String[] drinks = {"Drink1","Drink2"};
getDrinks(area, drinks);
}
public static void getDrinks(TextArea area, String[] theDrinks) {
// System.out.println(theDrinks[arrayCount].toString());
for (String drink : theDrinks) {
area.append(drink.toString());
}
}
}