I made a small program that listens and sends lines on a tcp socket and appends the received info to a JTextArea. I use this to chat on a Minecraft server without having the game open.
I was working fine last night, but when I got up it wasn't working. When I opened netbeans and ran it, it gave this error:
Exception in thread "main" java.lang.NullPointerException
at com.xxx.mcchat.chat.main(chat.java:333)
Can anyone explain what's wrong?
Here is the code (http://pastebin.com/FPNty0qf):
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.xxx.mcchat;
import java.io.*;
import java.net.*;
import net.sf.json.*;
import org.apache.commons.beanutils.*;
import org.apache.commons.collections.*;
import org.apache.commons.lang.*;
import net.sf.ezmorph.*;
import org.apache.commons.logging.*;
import java.awt.event.*;
import javax.swing.UIManager;
/**
*
* #author xxx
*/
public class chat extends javax.swing.JFrame {
/**
* Creates new form chat
*/
public chat() {
initComponents();
}
public void send(String user, String message){
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
socket = new Socket("mc.xxx.net", 20060);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
System.exit(1);
}
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
//System.out.println(in.readLine()); //Uncomment to debug
if(username != null){
out.println("/api/call?method=broadcast&args="+"[\"§7[Web] §b"+username+"§7:§f "+message+"\"]"+"&key=f0e2ad47a9a43c783d2c54f396f655c9279829c8c69ae9f52934648098dec993");
chatArea.append(username + ": " + message + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else{
chatArea.append("You must set your username!!" + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}
/**
* This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jCheckBoxMenuItem1 = new javax.swing.JCheckBoxMenuItem();
jToggleButton1 = new javax.swing.JToggleButton();
jScrollPane1 = new javax.swing.JScrollPane();
chatArea = new javax.swing.JTextArea();
input = new javax.swing.JTextField();
send = new javax.swing.JButton();
user = new javax.swing.JTextField();
userset = new javax.swing.JButton();
autoscrollCheck = new javax.swing.JCheckBox();
jLabel1 = new javax.swing.JLabel();
jCheckBoxMenuItem1.setSelected(true);
jCheckBoxMenuItem1.setText("jCheckBoxMenuItem1");
jToggleButton1.setText("jToggleButton1");
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Minecraft Chat");
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowOpened(java.awt.event.WindowEvent evt) {
formWindowOpened(evt);
}
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
chatArea.setEditable(false);
chatArea.setBackground(new java.awt.Color(0, 0, 0));
chatArea.setColumns(20);
chatArea.setFont(new java.awt.Font("Consolas", 0, 14)); // NOI18N
chatArea.setForeground(new java.awt.Color(255, 255, 255));
chatArea.setLineWrap(true);
chatArea.setRows(5);
jScrollPane1.setViewportView(chatArea);
input.setToolTipText("Enter message here");
input.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
inputKeyPressed(evt);
}
});
send.setText("Send");
send.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
sendActionPerformed(evt);
}
});
user.setToolTipText("");
user.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
userActionPerformed(evt);
}
});
user.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
userKeyPressed(evt);
}
});
userset.setText("Set");
userset.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
usersetActionPerformed(evt);
}
});
autoscrollCheck.setSelected(true);
autoscrollCheck.setText("Auto Scroll");
autoscrollCheck.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
autoscrollCheckActionPerformed(evt);
}
});
jLabel1.setText("Enter Username:");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(user, javax.swing.GroupLayout.PREFERRED_SIZE, 218, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(userset)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(autoscrollCheck))
.addComponent(jScrollPane1)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(input, javax.swing.GroupLayout.PREFERRED_SIZE, 649, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(send)))
.addGap(10, 10, 10))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(11, 11, 11)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(1, 1, 1)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(user, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1)))
.addComponent(userset)
.addComponent(autoscrollCheck))
.addGap(6, 6, 6)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 316, Short.MAX_VALUE)
.addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(1, 1, 1)
.addComponent(input, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(send))
.addGap(11, 11, 11))
);
pack();
}// </editor-fold>
String username = null;
private void inputKeyPressed(java.awt.event.KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
send(username, input.getText());
input.setText("");
}
}
private void sendActionPerformed(java.awt.event.ActionEvent evt) {
send(username, input.getText());
input.setText("");
}
private void usersetActionPerformed(java.awt.event.ActionEvent evt) {
if(username == null){
if(!"".equals(user.getText())){
username = user.getText();
chatArea.append("Username set!"+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else{
chatArea.append("Username can not be blank."+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}else{
send(username, "§7changed name to " + user.getText());
username = user.getText();
}
}
private void userActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
private void userKeyPressed(java.awt.event.KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
if(username == null){
if(!"".equals(user.getText())){
username = user.getText();
chatArea.append("Username set!"+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else{
chatArea.append("Username can not be blank."+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}else{
send(username, "§7changed name to " + user.getText());
username = user.getText();
}
}
}
private void formWindowClosing(java.awt.event.WindowEvent evt) {
}
private void formWindowOpened(java.awt.event.WindowEvent evt) {
// TODO add your handling code here:
}
private void autoscrollCheckActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) throws IOException {
/* Set the system look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new chat().setVisible(true);
}
});
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
socket = new Socket("mc.xxx.net", 20060);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
System.exit(1);
}
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
//System.out.println(in.readLine()); //Uncomment to debug
out.println("/api/subscribe?source=chat&key=1e287587f5d1d45255f4708467eeaf8a71085f9ccfd8a354523d233cf5a77be4&show_previous=true");
out.println("/api/subscribe?source=connections&key=e410592b70c0288654e6c1040edb0f21811dcb3f2ee11051163f36be9be00788&show_previous=false");
while(true){
String jsonString = in.readLine();
JSONObject obj = JSONObject.fromObject(jsonString);
JSONObject success = obj.getJSONObject("success");
if(success.get("message") != null){
chatArea.append("<" + success.get("player") + "> " + success.get("message") + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else if (success.get("action") != null){
chatArea.append(success.get("player") + " " + success.get("action") + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}
}
// Variables declaration - do not modify
public static javax.swing.JCheckBox autoscrollCheck;
public static javax.swing.JTextArea chatArea;
private javax.swing.JTextField input;
private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItem1;
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JToggleButton jToggleButton1;
private javax.swing.JButton send;
private javax.swing.JTextField user;
private javax.swing.JButton userset;
// End of variables declaration
}
(P.S Please don't get grumpy because I'm using a GUI generator, this is my first program, I promise I will learn to do it by hand )
The only thing that can be null at line 333 is chatArea. (If success were null, it would've thrown an exception in the if statement at line 332.) As others have suggested, you probably have a race condition where it's not being initialized before line 333 is reached.
The correct way to fix it is to enclose chatArea calls in a call to SwingUtilities.invokeLater:
final JSONObject success = obj.getJSONObject("success");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (success.get("message") != null) {
chatArea.append("<" + success.get("player") + "> " + success.get("message") + "\n\r");
if (autoscrollCheck.isSelected()) {
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
} else if (success.get("action") != null) {
chatArea.append(success.get("player") + " " + success.get("action") + "\n\r");
if (autoscrollCheck.isSelected()) {
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}
});
Any time you make a change to a Swing component, you should call it in the event dispatch thread. What's more, since the EDT is single-threaded, queue-based kind of executor, this is guaranteed to wait until the runnable you submitted earlier is done, so chatArea will definitely be set.
One other note: it's generally good practice to wrap UIManager calls in an invokeLater call as well.
Edit: I just want to be a little more clear about what you should always wrap in an invokeLater call:
Constructing Swing components
Changing properties of Swing components
Modifying the data model of a Swing component (not necessarily getting the data, just telling the component that cares that it has changed, such as firing events, needs to happen on the EDT)
Modifying UIManager properties, including setting the look and feel or modifying the values of its keys
Instantiating a look and feel
Instantiating sublcasses of ComponentUI
Adding and removing components to and from a container
Things that don't need to be wrapped:
Changing properties on components that aren't displayed yet According to Robin in the comments, this still needs to happen on the EDT.
Calls to repaint
Calls to validate, or invalidate (I think, I need to find confirmation on this)
Do all this, and any time you switch to a new look and feel, you won't have any problems with things not being called on the EDT.
Long story short, Swing isn't thread-safe, so you should always call Swing component methods from the event dispatch thread.
Also, I welcome any suggestions for my list about things I may have forgotten.
Here's are some resources that describe threading in Swing:
Java SE 6 javax.swing javadocs
Java trail on Swing concurrency
Old blog post about the decision to make Swing single-threaded (in case you're curious)
The problem is that you're readily switching between static and non-static data. Initially, the program runs main() (static). Therein, you reference chatArea (line 333, also static). However, chatArea is only set upon calling initComponents() (non-static), which happens in the constructor (non-static). This will not always be called before the remainder of the function.
Based on your invokeLater methodology, you should move everything related to the chat program, which comes after invokeLater, into the constructor (or some method which is not static).
Basically, the only thing that should be static is your main() method. The rest should not be static. If it helps, separate things into a new class, which you reference from main(); this will help you initialize the program, then run all your chat-related things.
It is probably a race condition which makes it work sometimes. The variable chatArea is not guaranteed to be initialized by the time the main thread gets to line 333. This is due to the deferred initialization of the GUI via invokeLater() some lines before that:
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new chat().setVisible(true);
}
});
You need some synchronization between those threads, or, what also should work, just initialize the GUI in the main thread:
final chat chatObject = new chat();
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
chatObject.setVisible(true);
}
});
Related
I wan to have an inputStream that takes the value of a JTextbox and passes it into the Scanner object.
Scanner scan = new Scanner (System.in);
String input = scan.nextLine();
if (input.equalsIgnoreCase("New Match")) {
try {
newMatch(scan);
} catch (FileNotFoundException e) {
System.out.println("failed to load");
} catch (ArithmeticException e) {
}
}
if (input.equalsIgnoreCase("Load Match 1") || input.matches("1")){
try {
loadMatch(scan, "One");
} catch (FileNotFoundException e) {
System.out.println("failed to load");
} catch (ArithmeticException e) {
}
}
}
You can use a PipedOutputStream (doc) and a PipedInputStream (doc) to create a one-way pipeline which you can then use to route input from a text field into a Scanner. But you'll still have to figure out how to capture all the output that's going to System.out and display it to your GUI, nicely interwoven with the "echoed" input that came from your text field.
For what it's worth, though, I'll share a little proof-of-concept of half the solution. This program reads "commands" from a JTextField through a Scanner and produces simulated "responses" to them; a JTextArea keeps a record of the simulated "conversation". The input "commands" are logged automatically to the JTextArea, much as input from System.in would automatically echo to System.out, and I also explicitly echo them to System.out. However, my simulated "responses" go not to System.out but directly to the JTextArea`.
package test;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Scanner;
import javax.swing.JTextField;
public class PipeTest extends javax.swing.JFrame {
public PipedInputStream pi;
private PipedOutputStream po;
public PipeTest()
{
try {
pi = new PipedInputStream(); // You write data into this end...
po = new PipedOutputStream(pi); // ,,, and read it back out at this end.
} catch (IOException ioe) {
System.out.println("Failed to initialize pipe: " + ioe.toString());
}
initComponents();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents()
{
jScrollPane1 = new javax.swing.JScrollPane();
historyText = new javax.swing.JTextArea();
jTextField1 = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
historyText.setColumns(20);
historyText.setRows(5);
jScrollPane1.setViewportView(historyText);
jTextField1.setText("jTextField1");
jTextField1.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
jTextField1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jTextField1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 369, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 38, Short.MAX_VALUE)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
pack();
}// </editor-fold>
private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt)
{
JTextField tf = (JTextField) evt.getSource();
String text = tf.getText();
byte[] ca = (text + System.getProperty("line.separator")).getBytes();
try {
po.write(ca, 0, ca.length);
} catch (IOException ex) {
System.out.println("Failed to write to pipe: " + ex.toString());
}
historyText.append(text + "\n");
tf.setText("");
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) throws IOException
{
PipeTest pt = new PipeTest();
java.awt.EventQueue.invokeLater(() -> {
pt.setVisible(true);
});
Scanner scn = new Scanner(pt.pi);
while (scn.hasNextLine()) {
String line = scn.nextLine();
System.out.println(line);
java.awt.EventQueue.invokeLater(() ->
{
pt.historyText.append("Response to " + line + "\n");
});
}
}
// Variables declaration - do not modify
private javax.swing.JTextArea historyText;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField jTextField1;
// End of variables declaration
}
The way I interpret your question is that you have some existing code that is built on reading user input through an instance of Scanner. I think you're asking whether you can pull the text from a JTextField and push that into the instance of Scanner that is already used.
If the above understanding is correct and your Scanner instance is reading from System.in as it is in the code sample then my answer is no, you can't do exactly what you want.
However, you can get somewhat close to what you want.
Here is some code that creates a new Scanner each time the actionPerformed method is called and pushes data from a JTextField into that Scanner by simply passing the text from the text field into the scanner's constructor.
public void actionPerformed(java.awt.event.ActionEvent evt) {
scanner.close(); //Don't forget to close your scanner before you reassign it
String data = jTextField1.getText();
scanner = new Scanner(data);
//Just to illustrate the results I added a println here
System.out.println(scanner.nextLine());
}
I want to open a file without taking any time.When I click on open Button immediately it has been opened.But,In my application It has taken more than two minutes for large files.I try to open a file,It has size 44MB.This file takes more than two minutes time to open.I want to open large size files quickly.Once check my open action code.
The below code shows the working example of my Application.
Sample code:
public class OpenDemo extends javax.swing.JFrame {
JTextPane textPane;
JScrollPane scrollPane;
int i=0;
JTextField status;
public OpenDemo() {
initComponents();
textPane=new JTextPane();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
tp = new javax.swing.JTabbedPane();
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
open = new javax.swing.JMenuItem();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jMenu1.setText("File");
open.setText("Open");
open.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openActionPerformed(evt);
}
});
jMenu1.add(open);
jMenuBar1.add(jMenu1);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tp, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tp, javax.swing.GroupLayout.DEFAULT_SIZE, 279, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
private void openActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser fileChooser=new JFileChooser();
int result = fileChooser.showOpenDialog(this);
if (result==JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try {
textPane.setPage(file.toURI().toURL());
} catch(Exception e) {
e.printStackTrace();
}
}
scrollPane=new JScrollPane(textPane);
tp.add(scrollPane);
textPane.setCaretPosition(0);
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(OpenDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(OpenDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(OpenDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(OpenDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new OpenDemo().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JMenu jMenu1;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenuItem open;
private javax.swing.JTabbedPane tp;
// End of variables declaration
}
The SwingWorker API outlines a suitable approach. Because of the size, I'd update a TableModel, as shown here, rather than a text component. Lines will begin appearing almost immediately, while the GUI remains responsive. The listening JTable will need to render only visible lines, and you may be able to leverage sorting and filtering.
There is some overhead (progress animation) and some things I would not have done, like a AWT event thread blocking actionPerformed.
Go with your code to https://codereview.stackexchange.com/ because a code review might be useful.
What I saw as optimizable:
Give an initial capacity to the StringBuilder.
... = new StringBuilder(1024*64); // (int)file.length()?
Replace the Scanner with a BufferdReader using readLine().
Ideal would be to check the speed of Files.readAllBytes; whether a progress indication is needed.
String s = new String(Files.readAllBytes(file.toPath()));
Second attempt:
First a sanity measure: closing the file.
Then I did less progress animation, which should definitely speed things up.
It will no longer show all text in the text pane, only every hundredth line.
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
final int PROGRESS_EVERY = 100;
while ((line = br.readLine()) != null) {
lineNumber++;
text.append(line);
text.append("\n");
if (linenumber % PROGRESS_EVERY== 0) {
ProgressData data = new ProgressData();
data.number = lineNumber;
data.line = line;
publish(data);
}
}
if (linenumber % PROGRESS_EVERY != 0) {
ProgressData data = new ProgressData();
data.number = lineNumber;
data.line = line;
publish(data);
}
}
And then
private StringBuilder text = new StringBuilder(1024 * 128);
At last:
Change textPane from JTextPane to JTextArea. Considerable gain in speed.
I have a file to print and I want to send him a custom water mark via java swing.
i have 2 files NewJFrame.java and Test.java
package test;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* #author shaharnakash
*/
public class NewJFrame extends javax.swing.JFrame {
/**
* Creates new form NewJFrame
*/
public NewJFrame() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jTextField1 = new javax.swing.JTextField();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jLabel1.setText("whater mark name");
jTextField1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jTextField1ActionPerformed(evt);
}
});
jButton1.setText("submit");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(30, 30, 30)
.add(jLabel1)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jTextField1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 251, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
.add(layout.createSequentialGroup()
.add(17, 17, 17)
.add(jButton1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 206, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(41, 41, 41)
.add(jLabel1))
.add(layout.createSequentialGroup()
.addContainerGap()
.add(jTextField1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 57, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
.add(112, 112, 112)
.add(jButton1)
.addContainerGap(96, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String value;
value = jTextField1.getText();
try{
String command = "cmd /c start cmd.exe";
Process child = Runtime.getRuntime().exec(command);
OutputStream out = child.getOutputStream();
out.write("C:/PDF>pdfprint.exe -printer 'docPrint' -firstpage 1 -lastpage 1 -wtext 'value' -wo 100 -wa 50 -wf 'Arial' C:/readme.pdf".getBytes());
out.close();
}catch(IOException e){
}
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JTextField jTextField1;
// End of variables declaration
}
and the main java class Test.java that execute the program
package test;
/**
*
* #author shaharnakash
*/
public class Test {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
}
the idea is to insert a value to the text field and after that click on the submit button it will execute the cmd command
C:/PDF>pdfprint.exe -printer 'docPrint' -firstpage 1 -lastpage 1 -wtext 'value' -wo 100 -wa 50 -wf 'Arial' C:/readme.pdf
when i execute the program it will open the cmd and will not send the file to the printer
note: draft is the water mark change
i change to Process child = Runtime.getRuntime().exec("\"PDF\pdfprint.exe -printer docPrint -firstpage 1 -lastpage 1 -wtext "+value+" -wo 100 -wa 50 -wf Arial C:\readme.pdf");
and i still not working
Personally, I'd use ProcessBuilder, if for no other reason, it reduces a lot of the complexity involved with working with Process.
ProcessBuilder pb = new ProcessBuilder("pdfprint.exe", "-printer", "'docPrint'", "-firstpage", "1", "-lastpage", "1", "-wtext", "'value'", "-wo", "100", "-wa", "50", "-wf", "'Arial'", "C:/readme.pdf");
pb.redirectErrorStream(true);
Process p = pb.start();
InputStream is = p.getInputStream();
int inInt = -1;
while ((inInt = is.read()) != -1) {
System.out.print((char)inInt);
}
Now, this is a block calling, meaning if you execute this within the context of your UI (AKA The Event Dispatching Thread), the UI will appear to hang until the external process has finished running.
In this case you should call execute the command in the back. Probably the simplest approach would be to use a SwingWorker
public class ExeWorker extends SwingWorker<String, String> {
public String doInBackground() {
// Execute command here...
// Depending on what you want to return, setup a return value
// This could an error string or the path to the output file for example...
return result;
}
public void done() {
// Back on the EDT, update the UI ;)
}
}
Have a read of Concurrency in Swing for more details
use Runtime.getRuntime().exec() method. Google about its different variants.
I'm trying to make a login screen for an application. During the login, many SQL calls will be made to a MySQL database, and it may take a few seconds to set everything up. I'd like to display a status screen via Card Layout and update a JLabel while the background thread is running.
Here's the gist of what I have for my Worker Thread:
public class LoginPrepThread extends Thread {
private final UIMain parent;
public LoginPrepThread(UIMain w){
parent = w;
}
public void exec(){
EventQueue.invokeLater(this);
}
public void run(){
try{
//SqlHelper sql = SqlHelper.instance;
sleep(500);
parent.getLoadingLable().setText("Fetching preferences...");
parent.getMainFrame().revalidate();
sleep(500);
parent.getLoadingLable().setText("Scanning workbench...");
parent.getMainFrame().revalidate();
sleep(500);
parent.getLoadingLable().setText("Updating permissions...");
parent.getMainFrame().revalidate();
sleep(500);
parent.getLoadingLable().setText("Finished...Please wait");
parent.getMainFrame().revalidate();
sleep(1000);
parent.getLayout().show(parent.getMainFrame().getContentPane(), "view.main");
}catch(Exception e){
}
}
}
Here is how I am calling it (Inside the event of a JButton, after authenticating):
setActiveProfile(user);
layout.show(frame.getContentPane(), "view.loading");
frame.repaint();
LoginPrepThread pt = new LoginPrepThread(thisTrick);
pt.exec();
I put some dummy events in for now, but the status label doesn't change...any suggestions?
A simple swing worker solved it. I guess I wasn't good enough on my google'ing
public class LoginPrepThread extends SwingWorker<String,String> {
private final UIMain parent;
public LoginPrepThread(UIMain w){
parent = w;
}
#Override
protected String doInBackground() throws Exception {
try{
publish("Fetching preferences...");
Thread.sleep(1000);
publish("Updating permissions...");
Thread.sleep(1000);
publish("Scanning workbench...");
Thread.sleep(1000);
publish("Finalizing...");
Thread.sleep(2000);
publish("Finished...Please wait");
Thread.sleep(1000);
parent.getLayout().show(parent.getMainFrame().getContentPane(), "view.main");
}catch(Exception e){
}
return null;
}
protected void process(List<String> item) {
parent.getLoadingLable().setText(item.get(0));
}
}
Ideally you would be implementing a SwingWorker to perform all your heavy non-GUI related tasks. You should take the advantage of what event-driven programming is all about.
What you need to do would be something like this:
Implement a PropertyChangeListner to your GUI class, listening to updates. Based on the property changes, update the labels. It is always a good practice to have a single GUI class handle all the GUI related update activities.
Create a SwingWorker where you would perform your background-intensive tasks. As and when there're updates available, fire a property change event and let the GUI class know that there's an update.
Here's a small SSCCE example of what you can do:
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.SwingWorker;
/**
*
* #author Sujay
*/
public class SimpleWorkerUI extends javax.swing.JFrame implements PropertyChangeListener{
/**
* Creates new form SimpleWorkerUI
*/
public SimpleWorkerUI() {
initComponents();
Worker worker = new Worker();
worker.addPropertyChangeListener(this);
worker.execute();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jLabel1.setText("Current Status: ");
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2)
.addContainerGap(327, Short.MAX_VALUE))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(20, 20, 20)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(jLabel2))
.addContainerGap(20, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
);
pack();
}// </editor-fold>
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(SimpleWorkerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(SimpleWorkerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(SimpleWorkerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(SimpleWorkerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SimpleWorkerUI().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
// End of variables declaration
#Override
public void propertyChange(PropertyChangeEvent evt) {
if("status".equalsIgnoreCase(evt.getPropertyName())){
String currentStatus = (String) evt.getNewValue();
jLabel2.setText(currentStatus);
}
}
}
class Worker extends SwingWorker<String, String>{
private static final int FINAL_VALUE = 1000;
#Override
protected String doInBackground() throws Exception {
int counter = 0;
while(counter < FINAL_VALUE){
firePropertyChange("status", "", "value is: "+counter);
try{
Thread.sleep(100);
}catch(InterruptedException ixe){
}
counter++;
}
return null;
}
}
You should not perform any long-running operations on the event dispatch thread. You are performing an operation that takes 3 seconds to complete. During those 3 seconds, you are monopolizing the EDT and no other GUI updates can happen.
You started out with good intentions...
public class LoginPrepThread extends Thread {
private final UIMain parent;
public LoginPrepThread(UIMain w){
parent = w;
}
public void exec(){
EventQueue.invokeLater(this);
}
public void run(){
try{
//SqlHelper sql = SqlHelper.instance;
sleep(500);
parent.getLoadingLable().setText("Fetching preferences...");
parent.getMainFrame().revalidate();
sleep(500);
parent.getLoadingLable().setText("Scanning workbench...");
parent.getMainFrame().revalidate();
sleep(500);
parent.getLoadingLable().setText("Updating permissions...");
parent.getMainFrame().revalidate();
sleep(500);
parent.getLoadingLable().setText("Finished...Please wait");
parent.getMainFrame().revalidate();
sleep(1000);
parent.getLayout().show(parent.getMainFrame().getContentPane(), "view.main");
}catch(Exception e){
}
}
}
Basically, what's happening, is when you call exec your actually placing a request onto the EDT to call the run method, which is then been executed within the EDT, causing the blockage.
Also, in your original example, it's pointless to extend from Thread as you never actually start it.
For future reference, I would have a closer look at Concurrency in Java
You are correct (in your self answer), SwingWorker is a much easier solution.
I'm writing an application with Java Swing. What i need is a procedure where i can stop the "elaboration" thread using a button in the graphic interface.
Here a simple project focused on what i need
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextArea;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Nikola
*/
public class Main extends javax.swing.JFrame
{
private MyThread THREAD;
public Main()
{
initComponents();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jButton1 = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
jButton2 = new javax.swing.JButton();
jButton3 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jButton1.setText("Pause Thread");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jScrollPane1.setViewportView(jTextArea1);
jButton2.setText("Resume Thread");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
jButton3.setText("Start Thread");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton3ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jButton3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 63, Short.MAX_VALUE)
.addComponent(jButton2)
.addGap(18, 18, 18)
.addComponent(jButton1))
.addComponent(jScrollPane1))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jButton1)
.addComponent(jButton2)
.addComponent(jButton3))
.addContainerGap())
);
pack();
}// </editor-fold>
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt)
{
THREAD = new MyThread(jTextArea1);
THREAD.start();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
try
{
THREAD.pauseThread();
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)
{
THREAD.resumeThread();
}
public static void main(String args[])
{
/*
* Set the Nimbus look and feel
*/
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/*
* If Nimbus (introduced in Java SE 6) is not available, stay with the
* default look and feel. For details see
* http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try
{
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (ClassNotFoundException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (InstantiationException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (IllegalAccessException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (javax.swing.UnsupportedLookAndFeelException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/*
* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Main().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration
}
class MyThread extends Thread
{
JTextArea area;
private final Object lock = new Object();
public MyThread(JTextArea area)
{
super();
this.area = area;
}
#Override
public void run()
{
for(int i=0 ; ; i++)
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
synchronized(lock)
{
lock.wait();
}
}
public void resumeThread()
{
synchronized(lock)
{
lock.notify();
}
}
}
The question is simple:
In the real application, the user set some options and then start the thread which doing the elaboration of the selected data.
I want to provide a "pause" button so the user can stop temporarily the elaboration and make some needed check and after that can resume the operation.
In the way i coded is the graphic thread that stop, not the "elaboration" one.
If you run my sample code and press "Start" the textarea starts to counting. The final result that i need is that when i press the "Pause" button the thread go to "sleep" and the counting stops, when i press the "Resume" button the thread "wakes up" and the counting in the text area starts againt to count.
You can't definitively pause one thread from another in the way you seem to want.
What you need to do instead, is signal that the other thread should stop, by setting some sort of flag. The thread in question must have logic to check this flag and pause its work when that happens.
So in this particular case, perhaps change MyThread as follows:
class MyThread extends Thread {
private volatile boolean running = true; // Run unless told to pause
...
#Override
public void run()
{
for(int i=0 ; ; i++)
{
// Only keep painting while "running" is true
// This is a crude implementation of pausing the thread
while (!running)
yield;
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
running = false;
}
public void resumeThread()
{
running = true;
}
}
This is a crude example that for brevity uses a sort of spinlock rather than proper monitor-based sleeping. Hopefully though it communicates the idea of how you use a flag to control the pausing of the thread.
Note that if you were doing some long-running set of steps within the block, instead of just the setText call, it would be good practice to check Thread.currentThread().interrupted() between each of the steps - and exit the loop if the itnerrupt flag is set. This is broadly what the built-in blocking methods (e.g. I/O) do so that they can be interrupted by other threads - since the running flag is only checked one per loop, it doesn't do much good to set it if each loop takes 20 minutes.
Try it like this:
class MyThread extends Thread {
JTextArea area;
private final Object GUI_INITIALIZATION_MONITOR = new Object();
private boolean pauseThreadFlag = false;
public MyThread(JTextArea area) {
super();
this.area = area;
}
#Override
public void run() {
for(int i=0 ; ; i++) {
checkForPaused();
area.setText(i+"");
}
}
private void checkForPaused() {
synchronized (GUI_INITIALIZATION_MONITOR) {
while (pauseThreadFlag) {
try {
GUI_INITIALIZATION_MONITOR.wait();
} catch (Exception e) {}
}
}
}
public void pauseThread() throws InterruptedException {
pauseThreadFlag = true;
}
public void resumeThread() {
synchronized(GUI_INITIALIZATION_MONITOR) {
pauseThreadFlag = false;
GUI_INITIALIZATION_MONITOR.notify();
}
}
}
It is a good idead to use monitors like you did. But you can not force the wait from outside. You have to tell the thread to wait, until you notify him again (over the monitor). In this case, you just have this simple method checkForPaused() that you will have to put in strategic positions so there is not a long delay until the thread is paused.
You can also extend this function so you can ask the thread if he is paused with a flag set in checkForPaused() and a public boolean isPausing().