JFileChooser Thread & JLabel - java

I'm creating a parser that's why I use JFileChooser.
When I select a file with JFileChooser, I would like to have a JLabel that says : "parsing in progress" or smth like that.
And when it's done : "parsing done".
(My first aim was to use progress bars, but it's a bit complicated for me now)
The ReadFile class will take array of files and create Callable for each file. If 5 files : 5 threads will be called. I used Callable because I need to get back Strings of data for each Threads and write it in a same csv file.
Well, when I click on Cancel on JFileChooser, the JLabel displays correctly at the right moment but when I select files / file for the parsing function, the JLabel waits the entire execution of my Callables and then "processing" appears (but when it has already ended ^^).
I cannot manage to display processing at the beginning of the threads.
Note : I called CardLayout at this moment, but it is not used yet.
Here is my code :
public class Main {
private static final String CARD_MAIN = "Card Main";
private static final String CARD_FILE = "Card File";
public static void main(String[] args) throws IOException {
createGUI();
}
public static void createGUI(){
// the JFrame
final JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationRelativeTo(null);
window.setTitle("TMG Parser - Thales");
window.setSize(400, 100);
// the buttonPanel ( one to open JFileChooser & one to quit )
JPanel container = new JPanel();
JPanel buttonPanel = new JPanel();
final JButton fileButton = new JButton("Choose File");
fileButton.setBackground(Color.BLACK);
fileButton.setForeground(Color.WHITE);
final JButton quitButton = new JButton("Quit");
quitButton.setBackground(Color.RED);
quitButton.setForeground(Color.WHITE);
// adding buttons to panel
buttonPanel.add(fileButton);
buttonPanel.add(quitButton);
// the status label that says : processing or done
final JLabel status = new JLabel();
container.add(status);
fileButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JFileChooser dialogue = new JFileChooser(new File("."));
dialogue.setMultiSelectionEnabled(true) ;
if (dialogue.showOpenDialog(null)==
JFileChooser.APPROVE_OPTION) {
status.setText("Processing");
File[] fichiers=dialogue.getSelectedFiles();
for( int i = 1; i<fichiers.length; ++i){
fichiers[i].getName();
fichiers[i].getAbsolutePath();
}
// calling my execution function (threads)
ReadFile readProgram = new ReadFile(fichiers);
}
else{status.setText("Action cancelled");}
}
});
quitButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
System.exit(0);
}
});
window.add(container, BorderLayout.CENTER);
window.add(buttonPanel, BorderLayout.PAGE_END);
window.setVisible(true);
}
}

Ok so #tobias_k was right ! Thank you man.
When I launched ReadFile, that was freezing my swing thread until ReadFile was done.
I changed ReadFile to a thread (and calling callables), and now it works perfectly.
Thanks !

Related

typewriter effect with JTextArea and Scanner JAVA

I'm making a game with my teammate for a school project.
I have created a JTextArea where the lines of a text file would be printed.
I would like to add the typeWriter effect, therefore I searched for answers on this website.
I found some pretty information here :
java-add-typewriter-effect-to-jtextarea
using-timer-to-achieve-typewriter-effect-in-jtextarea
I tried the solutions above, without success.
I'll put my code :
public static void ui() {
Font baseText = new Font("Roboto", Font.PLAIN, 30);
JFrame mainWindow = new JFrame("Main Window");
JTextArea textArea = new JTextArea();
textArea.setFont(baseText);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
JPanel panelButton = new JPanel();
panelButton.setLayout(new FlowLayout());
JButton bContinue = new JButton("Continue");
bContinue.setFont(baseText);
Path path = FileSystems.getDefault().getPath("beginning.txt");
try {
Scanner sc = new Scanner(path);
while(sc.hasNextLine()){
slowDisplay(line, textArea);
}
} catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panelButton.add(bContinue);
mainWindow.add(textArea);
mainWindow.add(panelButton, BorderLayout.SOUTH);
mainWindow.setBounds(0, 0, 1920, 1080);
mainWindow.setVisible(true);
}
Here is the content of the slowDisplay Method :
public static void slowDisplay(String line, JTextArea textArea){
Timer timer = new Timer(500, null);
timer.addActionListener(new ActionListener(){
int index=0;
#Override
public void actionPerformed(ActionEvent e) {
if(index<line.length()){
textArea.append(String.valueOf(line.charAt(index++)));
}
else if(index==line.length()){
textArea.append("\n");
}
else{
timer.stop();
}
}
});
timer.start();
}
What it does is that it browses the columns of the text files and write the characters, it creates something awful, unreadable and I don't know why :
The thing
I'll put the content of my text file :
-Mmmh...
-I-I feel cold. Where am I?
-Huh? Is this thing where I'm lying is a human sized plant?!
I looked around, I saw nothing but trees, bushes, and plants.
-What the...
If someone can guide me please, I would be grateful.
I have also tried typewriter effect way long ago.
Instead i used Thread.sleep() function to perform this task.
So here is the method for it.
void typeEffect(String str,JTextArea textArea)throws Exception{
//loop through each character and append it to the JTextArea
for(int i==0;i<str.length();i++){
textArea.append(str.charAt(i)+"");
Thread.sleep(20);//stops for 20 milliseconds
}
}
This looks very simple.
EDIT 1:-
I Have this code which is working as required.
import javax.swing.*;
class DelayTest
{
public static void main(String args[])throws Exception
{
JFrame f=new JFrame("Main Frame");
JTextArea textA=new JTextArea();
f.setSize(720,600);
f.add(textA);
f.setVisible(true);
typeEffect("Hello This is a sample String",textA);
}
static void typeEffect(String str,JTextArea textArea)throws Exception{
//loop through each character and append it to the JTextArea
for(int i=0;i<str.length();i++){
textArea.append(str.charAt(i)+"");
Thread.sleep(100);//stops for 100 milliseconds
}//closing of loop
}//closing of method
}//closing of class
I have executed this code and found it working.

Use KeyListener in a loop

I don't have a lot of experience with KeyListeners but I used one in my application and it works fine except I need to wait for input before my program can continue. For this I made a while loop that loops until the String temp is not null (which would mean there would be input).
The problem is there is no way to type in the JTextField (called input). Below is code from my two methods that are supposed to work together so that the text in my JTextField (input) can be returned (as temp). I'm not sure why this doesn't work or how to fix it.
The keyPressed method for my KeyListener:
public void keyPressed(KeyEvent e)
{
//only sends text if the enter key is pressed
if (e.getKeyCode()==KeyEvent.VK_ENTER)
{
//if there really is text
if (!input.getText().equals(""))
{
//String temp is changed from null to input
temp=input.getText();
//text sent to another JTextField
output.append(temp+"\n");
//input no longer has text
input.setText("");
}
}
}
The method thats trying to get text, also in my KeyListener class
public String getTemp()
{
booleans isNull=temp==null;
//loops until temp is not null
while (isNull)
{
//unnecessary line of code, only used so the loop not empty
isNull=checkTemp();
}
return temp;
}
public boolean checkTemp()
{
return temp==null;
}
Your while loop is a common console program construct, but understand that you're not creating a console program here but rather an event-driven GUI, and in this situation, the while loop fights against the Swing GUI library, and you need to get rid of it. Instead of a while loop with continual polling you now want to respond to events, and if you're listening for user input into a JTextField do not use a KeyListener as this low-level listener can cause unwanted side effects. Instead add a DocumentListener to the JTextField's Document.
Edit: You're listening for the enter key, and so the solution is even easier: add an ActionListener to the JTextField!
e.g.,
input.addActionListener(e -> {
String text = input.getText().trim();
if (text.isEmpty()) {
return;
}
output.append(text + "\n");
input.setText("");
});
More complete example:
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ChatBox extends JPanel {
private static final int COLS = 40;
private JTextField input = new JTextField(COLS);
private JTextArea output = new JTextArea(20, COLS);
private JButton submitButton = new JButton("Submit");
public ChatBox() {
output.setFocusable(false); // user can't get into output
JScrollPane scrollPane = new JScrollPane(output);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
ActionListener inputListener = e -> {
String text = input.getText().trim();
if (text.isEmpty()) {
return;
}
output.append(text + "\n");
input.setText("");
input.requestFocusInWindow();
};
input.addActionListener(inputListener);
submitButton.addActionListener(inputListener);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
bottomPanel.add(input);
bottomPanel.add(submitButton);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
ChatBox mainPanel = new ChatBox();
JFrame frame = new JFrame("Chat Box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

using listeners with both list and button

Very new to Java, but I am slowly picking my way through things. So please be kind. I understand most things I've tried so far, and built a version of the following that uses console output, but now I'm trying to make a GUI. I tried the netbeans GUI maker, but it created so much new code that when I tried to pick through it, I got lost. I'm much better at learning by piecing new things together myself, not having an IDE generate a ton of code and then attempt to find where I want to work.
I am trying to build an window that has a list with three choices on the left side, a button in the middle that confirms your choice, and an answer output on the right. Once the button is pressed, the input from the list is read and is converted into a corresponding answer. As of right now, all I get is "We recommend... null" after selecting an option in the list. The button appears to do nothing at the moment.
I have used tutorials, hacked up others' code from online, and referenced a few books, but I'm stuck.
Here is what I have:
package diffguidegui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class DiffGuideGUI extends JPanel implements ListSelectionListener {
private JList resultsTabList;
private DefaultListModel listModel;
private static final String recommendString = "Recommend a Option";
private JButton recommendButton;
private String recommendOutput;
final JLabel output = new JLabel("We recommend..." + recommendOutput);
//build list
public DiffGuideGUI () {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("A");
listModel.addElement("B");
//create the list and put it in the scroll pane
resultsTabList = new JList(listModel);
resultsTabList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
resultsTabList.setSelectedIndex(0);
//listener for user input
resultsTabList.addListSelectionListener(this);
resultsTabList.setVisibleRowCount(2);
JScrollPane listScrollPane = new JScrollPane(resultsTabList);
//build the button at the bottom to fire overall behavior
recommendButton = new JButton(recommendString);
recommendButton.setActionCommand(recommendString);
recommendButton.addActionListener(new RecommendListener());
//create a panel that uses Boxlayout for the button
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.add(recommendButton);
//create a panel that uses Boxlayout for the label
JPanel outputPane = new JPanel();
outputPane.setLayout(new BoxLayout(outputPane, BoxLayout.LINE_AXIS));
outputPane.add(output);
add(listScrollPane, BorderLayout.WEST);
add(buttonPane, BorderLayout.CENTER);
add(outputPane, BorderLayout.EAST);
}
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
}
}
public void valueChanged(ListSelectionEvent e) {
if(e.getValueIsAdjusting() == false) {
if(resultsTabList.getSelectedIndex() == -1) {
recommendButton.setEnabled(false);
} else {
recommendButton.setEnabled(true);
}
}
}
//Create GUI and show it
private static void createAndShowGUI() {
JFrame frame = new JFrame("Recommend Window");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create and set up content pane
JComponent newContentPane = new DiffGuideGUI();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//display the window
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The button appears to do nothing at the moment.
It does something. It calculates the value for your recommendOutput varable. But you never output this value.
try the following:
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
System.out.println(recommendOutput); // <-###################
}
}
This should print the value to stdout
To put the value into your label try this instead:
output.setText(recommendOutput);
where do you set the text for the JLabel? It says "We recommend NULL" because recommenedOutput is null when the object is created. I dont see
output.setText("We recommend "+value) anywhere. You probably need output.invalidate() also. Try putting setText(String text)/invalidate() in the RecommendListener.actionPerformed() method.
output.setText("We recommend A");
output.invalidate();

Java moving back and forth between content in runnable Jar file

I'm quite new to programming so I don't know the right way to do things and have been just experimenting a bit. I want to create a runnable where I can move back and forth between different content. The following works when run from inside eclipse, but if I export it as a JAR file, once I've moved forward once and then back again, moving forward won't give me the content anymore, but just the back button.
I tried something like this:
public class TestMain extends JFrame {
static PanelClass panel;
static boolean inUse = false;
public static void main(String[] args) {
panel = new PanelClass();
final TestMain test = new TestMain();
final Container container = test.getContentPane();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
test.setSize(500, 500);
final JButton back = new JButton("Back");
back.setAlignmentX(Component.CENTER_ALIGNMENT);
back.setMaximumSize(new Dimension(200, 80));
back.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
test.getContentPane().removeAll();
test.setContentPane(container);
test.getContentPane().revalidate();
}
});
final JButton exit = new JButton("Exit");
exit.setAlignmentX(Component.CENTER_ALIGNMENT);
exit.setMaximumSize(new Dimension(200, 80));
exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JButton problem = new JButton("Problem");
problem.setMaximumSize(new Dimension(200, 80));
problem.setAlignmentX(Component.CENTER_ALIGNMENT);
problem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
inUse = true;
test.setContentPane(panel);
test.getContentPane().add(back);
test.getContentPane().revalidate();
}
});
container.add(problem);
container.add(exit);
test.setVisible(true);
test.setDefaultCloseOperation(EXIT_ON_CLOSE);
test.setLocationRelativeTo(null);
while (true) {
while (!panel.stop && !inUse) {
}
inUse = false;
panel = new PanelClass();
test.setContentPane(panel);
test.getContentPane().add(back);
test.getContentPane().revalidate();
}
}
}
And the class for what I want to have as the second content:
public class PanelClass extends JPanel {
JTextArea text = new JTextArea("Some text here!" + '\n' + '\n');
JButton button1 = new JButton("Button 1");
JButton button2 = new JButton("Button 2");
boolean stop = false;
public PanelClass() {
text.setEditable(false);
text.setMaximumSize(new Dimension(300, 300));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
Dimension d = new Dimension(200, 60);
button1.setAlignmentX(Component.CENTER_ALIGNMENT);
button1.setMaximumSize(d);
button2.setAlignmentX(Component.CENTER_ALIGNMENT);
button2.setMaximumSize(d);
this.add(text);
this.add(button1);
this.add(button2);
}
}
What is the actual working way to do this? What if I have a lot of windows I'd like to be able to move back and forth between? I know it's a lot of bad/possibly-hard-to-read code, but I hope someone could help me out.
This is the code that runs when you press "Problem":
test.setContentPane(panel);
test.getContentPane().add(back);
test.getContentPane().revalidate();
and this is the code that runs when you press "Back":
test.getContentPane().removeAll();
test.setContentPane(container);
test.getContentPane().revalidate();
What is the sequence of calls when you press "Problem" then "Back" then "Problem"? It's this. (The revalidate() calls won't mess anything up, so I won't show them)
// Problem
test.setContentPane(panel);
test.getContentPane().add(back);
// Back
test.getContentPane().removeAll();
test.setContentPane(container);
// Problem
test.setContentPane(panel);
test.getContentPane().add(back);
Notice that you set the panel as the content pane, and then remove all the components from it when "Back" is pressed. The next time you press "Problem", the panel has no components on it, because you removed them.
did you try exporting as a runnable jar and choose package required libraries into generated jar when you exported as JAR from eclipse?

Changing layout/frame in response to a button press

I'm trying to make a little game on Java using the Swing components (Boggle-type game).
The way I have it set up right now, it basically opens up to the game right away - but I want to have a start up window with two buttons - "Tutorial" and "Play". I already have the functionality (my Tutorial button just opens a new Window with all the things on it) I'm just not sure how to create a second JFrame and then switch to it when I press Play (or rather, create a JFrame, then switch to the one I've already created when the JButton is pressed). I guess I could cause a new JFrame to open on the same location and the old one to become non-visible - but I was hoping for a simpler solution.
I also want to do this on completion of the game, switching again automatically to a little stat page - so any info will be appreciated.
This is what I have so far in case you guys want to see my code (I haven't yet hooked up the Enter key send the userWord to be validated and scored in my other classes, or filled in the tileGrid with Tile Objects, or the timer.... but that will all come later!)
public class Game implements Runnable {
public void run(){
final JFrame frame = new JFrame("Boggle");
frame.setLocation(500,200);
// Input - holds typing box
final JLetterField typingArea = new JLetterField(1);
typingArea.setFocusTraversalKeysEnabled(false);
typingArea.setEditable(true);
typingArea.setFocusable(true);
typingArea.requestFocusInWindow(); //also this request isn't being granted..
//if anyone could explain why i would love you
// I want the focus on the TextField on startup
frame.add(typingArea, BorderLayout.SOUTH);
typingArea.addKeyListener(new KeyAdapter() {
public void keyPressed (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) { // enter key is pressed
String userWord = typingArea.getText().toLowerCase();
typingArea.setText("");
}
}
});
final JLabel status = new JLabel("Running...");
// Main playing area
GridLayout tileGrid = new GridLayout(4,4);
final JPanel grid = new JPanel(tileGrid);
frame.add(grid, BorderLayout.CENTER);
// Reset button
final JPanel control_panel = new JPanel();
frame.add(control_panel, BorderLayout.NORTH);
final ImageIcon img = new ImageIcon("Instructions.png", "My Instructions...");
final JButton info = new JButton("Help");
info.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JFrame infoFrame = new JFrame("Tutorial");
infoFrame.setLocation(500,50);
JLabel tutorialImg = new JLabel(img);
int w = img.getIconWidth();
int h = img.getIconHeight();
infoFrame.setSize(w, h);
infoFrame.add(tutorialImg);
infoFrame.setVisible(true);
}
});
control_panel.add(info);
// Put the frame on the screen
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Game());
}
}
use CardLayout instead of second JFrame, your concept is heading to OutOfMemory
use JFrame.pack(after switch betweens Cards in CardLayout) if you want to change JFrames bounds on runtime,

Categories