Implementing GUI with Java application - java

I'm quite the beginner when it comes to java & coding in general, so I apologise for any overly obvious questions asked. I've just completed part of an application which reads data from an SQL database, then sends some stuff to print to socket depending on what information is read. I'm now trying to learn swing and get a GUI working with the application. Currently I have 2 forms, the first is used to select a printer, then the second will (hopefully) work as a log/ console which tells the user what and when stuff is happening. I've got the code and the forms together in a project.
I was wanting to find out how I can make the class which has my code in run when a Jbutton is pressed on a GUI, as well as how I can stop it from running when a different JButton is pressed.
The code from the Swing Form (Form2.java) is as follows:
package com.company;
import javax.swing.*;
public class Form2
{
private JTextArea jtaConsole;
private JPanel Jframer;
private JButton stopButton;
private JButton startButton;
public Form2(String message)
{
JFrame frame = new JFrame("Print Application");
frame.setContentPane(this.Jframer);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(true);
frame.setVisible(true);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
jtaConsole.append(" Printer selected: " + message + "\n");
}
}
And the code from the class I want the JButton to run is as follows:
package com.company;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ZebraCode
{
public static void main(String[] args)
{
{
while (true)
{
//SQL login.
String connectionString = "jdbc:sqlserver://:;database=;user=;password=!!;";
//Select Data.
String SQL = "SELECT TOP 2 [PK_PrintQueueID],[FK_PrinterID],[FK_BarcodeTypeID],[Barcode],[Quantity],[QueueDate],[ProcessedDate] FROM [Brad].[dbo].[PrintQueue] -- WHERE ProcessedDate IS NULL";
//Connection Variable & Time Settings.
Connection connection = null;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
try
{
connection = DriverManager.getConnection(connectionString);
Statement stmt = connection.createStatement();
Statement stmt2 = null;
ResultSet rs = stmt.executeQuery(SQL);
while (rs.next())
{
// Get barcode value to split & Set date.
String FK_BarcodeTypeID = rs.getString("FK_BarcodeTypeID");
String barcode = rs.getString("Barcode");
String[] parts = barcode.split("-");
String part1 = parts[0];
String SQL2 = "UPDATE PrintQueue SET ProcessedDate = '" + dateFormat.format(date) + "' WHERE PK_PrintQueueID = '" + rs.getString("PK_PrintQueueID")+"'";
stmt2 = connection.createStatement();
stmt2.executeUpdate(SQL2);
// Action based on type of barcode.
if (FK_BarcodeTypeID.equals("1"))
{
// Type 128 barcode.
String zpl = "^XA^BY2,3,140^FT80,200^BCN,Y,N,N^FD>:" + rs.getString("Barcode") + "^FS^FT200,250^A0N,42,40^FH^FD" + part1 + "^FS^XZ";
printlabel(zpl);
System.out.println("New serialized barcode added.\nPrinting: " + (rs.getString("Barcode")));
System.out.println("Process date: " + dateFormat.format(date) + ".\n");
}
else
{
// Type 39 barcode.
String zpl = "CT~~CD,~CC^~CT~ ^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR4,4~SD15^JUS^LRN^CI0^XZ^XA^MMT^PW674^LL0376 ^LS0 ^BY2,3,151^FT84,249^BCN,,Y,N^FD>:" + rs.getString("Barcode") + "^FS ^PQ1,0,1,Y^XZ";
printlabel(zpl);
System.out.println("New un-serialized barcode added.\nPrinting: " + (rs.getString("Barcode")));
System.out.println("Process date: " + dateFormat.format(date) + ".\n");
}
}
} catch (SQLException e)
{
e.printStackTrace();
}
try
{
//Makes execution sleep for 5 seconds.
Thread.sleep(5000);
}
catch (InterruptedException ez)
{
}
}
}
}
//Printer Info.
public static void printlabel(String zpl)
{
try
{
Socket clientSocket;
clientSocket = new Socket("", );
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
outToServer.writeBytes(zpl);
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Any tutorials or direction as to how I can learn this would be appreciated.
Thanks!

You want to add an action listener.. here is an example. Below are two examples on how to do so using lambdas and not using one.
JButton button = new JButton("Click Me!");
// Without lambda
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Code to execture when clicked
}
});
//With lambda
button.addActionListener(e -> {
//code to execute when clicked
});
I'd also advise you to do a little reading, http://www.tutorialspoint.com/design_pattern/mvc_pattern.htm

Your question is a bit broad but let me offer some suggestions:
First off, you really don't want to have a JButton run the database code unchanged as doing this would be shoehorning a linear console program into an event-driven GUI, a recipe for disaster. Note that as written all your database code is held within a single static main method, and so there would be no way for the GUI to be able to control the running of that code. Either it runs or it doesn't, that's it, and no easy way for the database code to return its data to the GUI.
Instead first change that database code so that it is much more modular and OOP-friendly, including creating proper classes with state (instance fields) and behavior (instance methods), and getting almost all that code out of the static main method.
What I'm asking you to do is to create a proper model for your GUI, aka your view. Only after doing this would you have your GUI create a model object and call its methods on button push within your ActionListener. You will also want to call any long-running code within a background thread such as can be obtained with a SwingWorker.
Other issues:
You never initialize your JPanel or JTextArea variables, and so you're both adding a null variable as your JFrame's JPanel and calling methods on a null JTextArea variable, both of which will throw NullPointerExceptions.

Here's a part of code I developed to better understand Java gui. I'm also a begginer.
It's three classes: starter class, ongoing non gui processes, gui with the swingworker method. Simple, works, can safely update a lot of gui components from Swingworkers process method (passes a class instance as argument). Whole code so it can be copy/pasted:
package structure;
public class Starter {
public static void main(String[] args) {
Gui1 thegui = new Gui1();
}
}
LOGIC
package structure;
public class Logical {
String realtimestuff;
public String getRealtimestuff() {
return realtimestuff;
}
public void setRealtimestuff(String realtimestuff) {
this.realtimestuff = realtimestuff;
}
//MAIN LOGICAL PROCESS..
public void process(){
// do important realtime stuff
if (getRealtimestuff()=="one thing"){
setRealtimestuff("another thing");
}else{setRealtimestuff("one thing");
}
// sleep a while for readibility of label in GUI
//System.out.println(getRealtimestuff());
try {
Thread.sleep(250);
} catch (InterruptedException e) {
System.out.println("sleep interrupted");
return;
}
}
}
GUI CLASS with Swingworker
package structure;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JLabel;
import java.util.List;
import javax.swing.*;
public class Gui1 {
final class Dataclass{
String stringtosend;
public Dataclass(String jedan){
//super();
this.stringtosend = jedan;
}
}
// EDT constructor
JFrame frame;
public Gui1(){
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
initialize();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void initialize() {
// JUST A FRAME WITH A PANEL AND A LABEL I WISH TO UPDATE
frame = new JFrame();
frame.setBounds(100, 100, 200, 90);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.NORTH);
JLabel lblNovaOznaka = new JLabel();
panel.add(lblNovaOznaka);
frame.setVisible(true);
SwingWorker <Void, Dataclass> worker = new SwingWorker <Void, Dataclass>(){
#Override
protected Void doInBackground() throws Exception {
Logical logic = new Logical();
boolean looper = true;
String localstring;
while (looper == true){
logic.process();
localstring = logic.getRealtimestuff();
publish(new Dataclass(localstring));
}
return null;
}
#Override
protected void process(List<Dataclass> klasa) {
// do a lot of things in background and then pass a loto of arguments for gui updates
Dataclass xxx = klasa.get(getProgress());
lblNovaOznaka.setText(xxx.stringtosend);
}
};
worker.execute();
}
}

Related

Java loading gif freeze while processing data?

I call a method which lists all the files in a directory, and adds them to a JTable:
addFilesWithSubsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
reverseLoadingVisibility(loaderLabel); //set Visible
addFilesWithSubs2(chooser, loaderLabel);
}
});
public void addFilesWithSubs2(JFileChooser chooser, JLabel loaderLabel) {
//loading all files ....
//when every file is listed:
//Set invisible
reverseLoadingVisibility(loaderLabel);
}
The another method change reverse the visibility of the JLabel in which the loading .gif is.
public void reverseLoadingVisibility(JLabel loaderLabel) {
loaderLabel.setVisible(!loaderLabel.isVisible());
}
The problem is: the gif doesn't play, freezes while the files are added to the JTable.
UPDATE: Still have problem the loading gif freezes
addFilesButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
reverseLoadingVisibility(loaderLabel);
try {
new AddFiles().doInBackground(
chooser, CHOOSERTITLE,
lastDictionary,
sdf,
filesTable,
model,
columnNames,
loaderLabel);
} catch (Exception e) {
e.printStackTrace();
}
}
});
public class AddFiles extends SwingWorker{
#Override
protected Void doInBackground() throws Exception {
return null;
}
protected void doInBackground(JFileChooser chooser, String CHOOSERTITLE,
String lastDictionary,
SimpleDateFormat sdf,
JTable filesTable,
DefaultTableModel model,
String[] columnNames,
JLabel loaderLabel) throws Exception {
//Set visible
reverseLoadingVisibility(loaderLabel);
chooser.setDialogTitle(CHOOSERTITLE);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//
chooser.setAcceptAllFileFilterUsed(true);
//TODO: this changed to chooser
if (chooser.showOpenDialog(chooser) == JFileChooser.APPROVE_OPTION) {
// create a file that is really a directory
File aDirectory = new File(chooser.getSelectedFile().toString());
lastDictionary = chooser.getSelectedFile().toString();
// get a listing of all files in the directory
String[] filesInDir = aDirectory.list();
// TODO
System.out.println("Number of files: " + filesInDir.length);
// have everything i need, just print it now
for ( int i=0; i<filesInDir.length; i++ )
{
File currentFile = new File(aDirectory + "\\" + filesInDir[i]);
System.out.println(filesInDir[i] );
System.out.println(aDirectory );
System.out.println(currentFile.length()/1024 + " KB");
System.out.println(sdf.format((currentFile).lastModified()));
// Avoid duplicates
int row = 0;
boolean duplicate = false;
for (; row < filesTable.getRowCount(); row++) {
if (model.getValueAt(row, 1).equals(filesInDir[i]) &&
model.getValueAt(row, 3).equals(aDirectory)
) {
duplicate = true;
break;
}
System.out.println("model.getValueAt(row, 1) " + model.getValueAt(row, 1));
System.out.println(filesInDir[i]);
System.out.println("model.getValueAt(row, 3) " + model.getValueAt(row, 3));
System.out.println(aDirectory);
}
if (!duplicate && currentFile.isFile()) {
model.addRow(new Object[]{
filesTable.getRowCount()+1,
filesInDir[i],
null,
aDirectory,
currentFile.length()/1024 + " KB",
sdf.format((currentFile).lastModified())
});
}
}
}
else {
System.out.println("No Selection ");
}
// Readjust columns
adjustTableColumns(filesTable, columnNames);
//Set unvisible
reverseLoadingVisibility(loaderLabel);
}
...
That's why because all files are loaded in the EDT (Event Dispatch Thread) (hopefully you launch your application using SwingUtilities.invokerLater() method) which cause all swing components to freeze. For more details read this java document by oracle: Initial Threads.
In order to solve your problem, you have to use a SwingWorker. A class responsible for heavy background tasks in Swing applications. With a simple google search, you can take an idea from here: How do I use SwingWorker in Java?
UPDATE in order to answer OP's comment.
The truth is that your code is a little bit big, and the most important, it is not an SSCCE.
In order to give you one more hand to find the solution you are looking for, i have created an SSCCE, using a SwingWorker that does something "heavy". In our case, the something heavy, is to write 1000 lines in a .txt file, but each line, thread (our worker) will sleep for 10ms.
Take it a look, run it if you want (i recommend it). Some extra comments inside the code, do not forget to check them.
package test;
import java.awt.BorderLayout;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class SwingWorkerExample extends JFrame {
/*
* Worker has Void doInBackground a.k.a, doInBackground method needs to return nothing.
* Worker needs to process-publish Integers.
*/
private SwingWorker<Void, Integer> writeToFileWorker = null;
private JLabel gifLabel;
private JButton doSomethingHeavy;
public SwingWorkerExample() {
super("Just a test.");
createWorker();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
gifLabel = new JLabel();
ImageIcon gif = new ImageIcon("C:/Users/George/Desktop/giphy.gif");
gifLabel.setIcon(gif);
gifLabel.setVisible(false); //Initialy non visible
gifLabel.setHorizontalTextPosition(JLabel.CENTER);
gifLabel.setVerticalTextPosition(JLabel.BOTTOM);
gifLabel.setHorizontalAlignment(JLabel.CENTER);
getContentPane().add(gifLabel, BorderLayout.CENTER);
doSomethingHeavy = new JButton("Do something heavy in another thread and start dancing...");
doSomethingHeavy.addActionListener(e -> {
//Before start the worker, show gif and disable the button
doSomethingHeavy.setEnabled(false);
gifLabel.setVisible(true);
writeToFileWorker.execute();
});
getContentPane().add(doSomethingHeavy, BorderLayout.PAGE_END);
setSize(500, 300);
setLocationRelativeTo(null);
}
private void createWorker() {
writeToFileWorker = new SwingWorker<Void, Integer>() {
#Override
protected Void doInBackground() throws Exception {
File fileToWrite = new File(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "hello_worlds.txt");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileToWrite));) {
for (int line = 0; line < 1000; line++) {
writer.append("Hello World! My name is Swing Worker.");
writer.append(System.lineSeparator());
Thread.sleep(10);
publish(line);
}
}
return null;
}
/*
* Runs in Event Dispatch Thread (EDT)
*/
#Override
protected void process(List<Integer> chunks) {
int line = chunks.get(0);//First parameter is the line
gifLabel.setText("Written " + line + " lines in the txt.");
super.process(chunks);
}
/*
* Runs in Event Dispatch Thread (EDT)
*/
#Override
protected void done() {
//When swing worker is finished, a.k.a the heavy work, stop the gif and enable the button
gifLabel.setVisible(false);
doSomethingHeavy.setEnabled(true);
super.done();
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SwingWorkerExample swe = new SwingWorkerExample();
swe.setVisible(true);
});
}
}
Small preview:
My guess would be that your addFilesWithSubs2-Method is blocking the UI thread. If you have long running tasks, than you have to execute them in a separate thread e.g. SwingWorker

Trying to start program on JButton press

I am trying to make a simple program that will ask the user a question and then compare their answer with a stored correct answer. The problem seems to be that the main loop of the program is not running when I click the Ready JButton.
I tried changing the main method to another non-default name and adding a call to it in the actionPerformed() method, and it did seem to execute the loop at least once, but then led to not being able to close the applet without the task manager once I clicked the button. I don't know if that means it hit an endless loop or what.
I'm sure there is more to fix in this code besides this issue, but I cannot make any progress on that without clearing this up first. If there is a problem with the way I went about creating the GUI please let me know. I tried to base it off of an assignment I did that worked just fine, so I don't know whether or not that is the issue.
Any help provided is appreciated.
Here is the code:
import java.awt.*;
import javax.swing.*;
public class Langarden_App extends JApplet{
private int width = 800, height = 600;
private LangardenPanel langPanel;
public void init(){
langPanel = new LangardenPanel();
getContentPane().add(langPanel);
setSize(width, height);
}
}
And the class with the logic
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.*;
public class LangardenPanel extends JPanel{
private static JButton submit;
private static JButton ready = new JButton("Ready");
private static JLabel instruct;
private JTextField input = new JTextField(100);
private static String inString;
private static ArrayList<String> questions;
private static ArrayList<String> answers;
private static Random rand = new Random();
public LangardenPanel(){
questions = new ArrayList<String> (Arrays.asList("¿Qué es la palabra para 'inveirno' en ingles?", "¿Qué es la forma de 'yo' del verbo 'venir'?"));
answers = new ArrayList<String> (Arrays.asList("winter", "voy"));
instruct = new JLabel("Welcome to Langarden! Press Submit to begin. You have one minute and three attempts for each question.");
submit = new JButton("Submit");
this.setLayout(new BorderLayout());
add(BorderLayout.SOUTH, ready);
add(BorderLayout.NORTH, instruct);
add(BorderLayout.CENTER, input);
ready.addActionListener(new SubListener());
}
public static void main(String[] args){
try{
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e){
}
System.out.println("Setting text");
instruct.setText("Alright! Let's Go!");
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e){
}
do{
System.out.println("Running loop");
int qnum = rand.nextInt(questions.size());
instruct.setText(questions.get(qnum));
for (int i=0; i<3; i++){
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e) {
}
if(checkAnswer(qnum, inString)){
instruct.setText("Correct!");
break;
} else {
instruct.setText("Try again...\n" + questions.get(qnum));
}
}
instruct.setText("The correct answer was " + answers.get(qnum));
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e){
}
questions.remove(qnum);
answers.remove(qnum);
instruct.setText("Would you like to continue? Enter No and click Submit to exit.");
} while (!inString.equalsIgnoreCase("No") && questions.size() != 0);
instruct.setText("Congratulations, you have completed this module!");
}
private static boolean checkAnswer(int qnum, String inString) {
if (answers.get(qnum).equalsIgnoreCase(inString))
return true;
return false;
}
private class SubListener implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println("Button Pressed!");
if(e.getSource() == ready){
add(BorderLayout.SOUTH, submit);
submit.addActionListener(new SubListener());
} else {
inString = input.getText();
}
}
}
}
Get rid of the main method. If this is running as an applet, then the program has no business having a main method.
Make all fields non-static. Yes all.
Get rid of the while-true loop. If this runs, this will squelch your Swing event thread rendering your GUI frozen and helpless. Use a Swing Timer instead as a "pseudo" loop. Please check out the Swing Timer Tutorial for more on this.
Any time you add a component to a container, you should call revalidate() and repaint() on that same container so that the container's layout managers can layout the new component, and so that the OS can repaint over any "dirty" pixels.
Rather than add a new JButton as you're doing, much better is to swap components using a CardLayout. The tutorial can be found here: CardLayout tutorial.

JTextArea.append not displaying

I'm trying to write the contents of an array to a JTextArea. I've tried everything I can think of, and I can't understand what isn't working here. I've stripped the unnecessary stuff out of my code, here's the two relevant classfiles:
Main class:
package irclogtest;
public class BriBotMain {
public static void main(String args[]) throws Exception {
boolean startup = true;
//frame test launch
BriDisplayGUI data = new BriDisplayGUI(startup);
data.irclog.append("BriBot Startup Successful!" + "\n");
//example access through function when startup is false (only in main class for sample code to demonstrate issue)
try {
BriDisplayGUI data2 = new BriDisplayGUI(false); //tells us which class we're accessing
String[] textForGUI = new String[2]; //tells us the array has 2 lines
textForGUI[0] = "this is the first line"; //set the first line of the array to this text
textForGUI[1] = "this is the second";
data2.arrayToDisplay(textForGUI); //appends contents of array to text window
}
catch(Exception e) {
System.out.println(e);
}
}
}
GUI display class:
package irclogtest;
import java.awt.event.*;
import java.io.IOException;
import javax.swing.*;
public class BriDisplayGUI extends JFrame implements ActionListener {
private static final long serialVersionUID = -7811223081379421773L;
String file_name = "C:/Bribot/logfile.txt";
//these lines create the objects we use
JFrame frame = new JFrame();
JPanel pane = new JPanel();
JButton pressme = new JButton("Click here");
JButton pressme2 = new JButton("Also here");
JTextArea irclog = new JTextArea( 20, 70);
JScrollPane scrollirc = new JScrollPane(irclog);
public BriDisplayGUI(boolean startup) { //startup function, opens and sets up the window
if(startup == true){
frame.setTitle("Bribot Test Frame"); frame.setBounds(100,100,840,420); //sets title of window, sets position and size of window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //tells program to end on window close
frame.add(pane); //adds the main display pane to the window
//panel customization goes here
pressme.addActionListener(this);
pane.add(pressme);
pressme2.addActionListener(this);
pane.add(pressme2);
pressme.requestFocusInWindow();
irclog.setEditable(false);
scrollirc.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.add(scrollirc);
irclog.setLineWrap(true);
irclog.setWrapStyleWord(true);
//pane.add(inputthing);
frame.setVisible(true);
} else {
System.out.println("Display Class Called");
}
}
public void arrayToDisplay(String[] text) throws IOException {
int i;
for ( i=0; i < text.length; i++) {
irclog.append( text[i] + "\n");
System.out.println( i + ": " + text[i]);
}
}
public void singleToDisplay(String text) throws IOException {
irclog.append(text + "\n");
System.out.println(text);
}
//basic event handler
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == pressme) {
} else if(source == pressme2) {
}
}
}
The first append works fine, but the second doesn't, and I can't figure out why (although the for loop does, as the contents of the array get written to console). I've searched quite a bit and nothing I've tried works. Can anyone point out the inevitable obvious oversight here? I'm the definition of a novice, so any advice is appreciated.
Thanks!
The default constructor doesn't do anything, meaning it doesn't construct any kind of UI or display, what would be, an empty frame.
You seem to be thinking the text will appear in data when you are appending it to data1
Try calling this(false) within the default constructor
A better solution would be to construct the core UI from the default constructor and from the "startup" constructor call this() and then modify the UI in what ever way this constructor needs
It seems like you write a new program. Why do you use Swing? Did you take a look at JavaFX?
I am not sure if that is going to fix your problem but you could try a foreach
for(String s : text){
irclog.append(s+"\n");
}

how do I make my program check the stock market value every hour[java]

I am making a program to check the stock market for a symbol and I got that far, and added a basic gui to it. I am stumped on how to make it check every hour and create a green up arrow if it increased and red down arrow if it decreased.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class QuoteTracker {
JFrame frame;
JPanel mainPanel;
JLabel enterLabel;
JLabel resultLabel;
JTextField text;
JTextField result;
JButton query;
JButton redArrow;
JButton greenArrow;
String url;
public static void main(String[] args) {
new QuoteTracker().buildGui();
}
public class checkingQuote implements Runnable {
#Override
public void run() {
while (true) {
try {
checkQuote(url);
//if increase in value green button
System.out.println("Sleeping");
Thread.sleep(1000 * 60 * 60);
System.out.println("Waking");
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
}
}
public void checkQuote(String symbol) {
try {
String url = "http://finance.yahoo.com/q?s=" + symbol + "&ql=0";
this.url = url;
Document doc = Jsoup.connect(url).get();
Elements css = doc.select("p > span:first-child > span");
result.setText(css.text());
} catch (IOException e) {
}
}
public void buildGui() {
frame = new JFrame("QuoteTracker");
mainPanel = new JPanel();
enterLabel = new JLabel("enter symbol ");
resultLabel = new JLabel("result ");
text = new JTextField(4);
result = new JTextField(8);
query = new JButton("query");
query.addActionListener(new queryListener());
mainPanel.add(enterLabel);
mainPanel.add(text);
mainPanel.add(query);
mainPanel.add(resultLabel);
mainPanel.add(result);
frame.getContentPane().add(mainPanel);
frame.setSize(300, 400);
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class queryListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ev) {
checkQuote(text.getText());
}
}
}
Do I even need a thread? I've never made one before and tried to add things that made sense. I am thinking I either need a thread or to use java's Timer?
Use SwingWorker to execute long running task in the background while updating the UI based on some results from that long running task. That means, it is actually about two different threads communicating to each other - Worker Threads and Event Dispatch Thread (EDT)
But before that, I want to point some few notes about your code.
Invoke the initialization of your UI in the EDT. That is, instead of just straightly calling new QuoteTracker().buildGui(), call it inside the run method of a Runnable passed to SwingUtilities.invokeLater (like this)
Classes should start in capital letter as per the Java standard.
To apply SwingWorker in you existing code, you can do the following :
First, you must place your checkQuote method in some other class (ideally a service class) then modify your checkQuote method to return the String that is set to the textfield result. Something like this
public Class QuoteService{
public String checkQuote(String symbol) {
try {
String url = "http://finance.yahoo.com/q?s=" + symbol + "&ql=0";
this.url = url;
Document doc = Jsoup.connect(url).get();
Elements css = doc.select("p > span:first-child > span");
return css.text();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
You can then make your QuoteTracker class to focus mainly in the UI part of your application. Just create the service object as instance level field so that you can freely call checkQuote method within your the class.
Invoke SwingWorker when the button is clicked.
public void actionPerformed(ActionEvent ev) {
new SwingWorker<Void, String>() {
#Override // this method is done in the Worker Thread
protected Void doInBackground() throws Exception {
while(true){
String res = checkQuote(text.getText());
publish(res); //will call the process method
Thread.sleep(1000 * 60 * 60); //1 hour
}
}
#Override // this method is done in the EDT
protected void process(List<String> resultList){
String res = resultList.get(0);
if(!"".equals(res)){
result.setText(res);
}
}
#Override // this method is done in the EDT. Executed after executing the doInBackground() method
protected void done() {
//... clean up
}
}.execute();
}
Note that done() will be executed after the execution of doInBackground() is finished, which means, in the code I posted, it will never be executed since the while loop used to periodically call checkQuote is infinite. Just modify it so that you can interrupt that loop according to your need
Further Read : Concurrency in Swing
You can use thread and normal while loop in main thread as well, but at the very first , you need to start you thread and that thread must refer your object.
Add following line in public void buildGui() {
Thread t1 = new Thread(new checkingQuote());
t1.start();
This will start you thread, for testing purpose i have modified checkingQuote class
public class checkingQuote implements Runnable {
int count = 0;
#Override
public void run() {
System.out.println("Inside Runner");
while (true) {
try {
count++;
checkQuote(url);
//if increase in value green button
result.setText(""+count);
System.out.println("Sleeping");
Thread.sleep(1000);
System.out.println("Waking");
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
}
}
I am seeing number change in the text box.... same way you can alter the logic to get and show the quotes.. but you must keep the value for previous quote to compare with the latest code to show green and red notification...
In gui application it is better to use Timer, also you may use ScheduledThreadPoolExecutor. But in the second case notice, that your scheduled tasks may run in non-GUI thread. As you can't invoke ATW/Swing directly from another thread, you should wrap any call to Swing into SwingUtilities.invokeLater() method.
Also notice, that when you do something durable inside GUI thread, the whole GUI becomes unrepsonsive. So, to achieve a better responsiveness, you would query in a separate thread, and expose results to Swing through invokeLater after quotes have checked. So your checkQuote method may be rewritten this way:
public void checkQuote(String symbol) {
try {
final String url = "http://finance.yahoo.com/q?s=" + symbol + "&ql=0";
Document doc = Jsoup.connect(url).get();
Elements css = doc.select("p > span:first-child > span");
final String text = css.text();
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
this.url = url;
result.setText(text);
}
}
} catch (IOException e) {
// Don't swallow exceptions
logger.error("Something gone wrong", e);
}
}
public void checkQuote() {
final String symbol = text.getText();
new Thread(new Runnable() {
#Override public void run() {
checkQuote(symbol);
}
}).start();
}
and call it from Timer and from button click listener.

When i execute get LDAPConnection through Swing it hangs

When I run following code through Main method, it works fine but when i try to execute it on click of swing button, it hangs.
Please help
import java.util.Hashtable;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class SimpleLdapAuthentication {
public static void main(String[] args) {
String username = "user";
String password = "password";
String base = "ou=People,dc=objects,dc=com,dc=au";
String dn = "uid=" + username + "," + base;
String ldapURL = "ldap://ldap.example.com:389";
// Setup environment for authenticating
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, ldapURL);
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, dn);
environment.put(Context.SECURITY_CREDENTIALS, password);
try {
DirContext authContext =
new InitialDirContext(environment);
// user is authenticated
} catch (AuthenticationException ex) {
// Authentication failed
} catch (NamingException ex) {
ex.printStackTrace();
}
}
}
Does it really hang, or just take a long time to come back ?
It's not a good idea to do lots of processing in a Swing event handler, since Swing needs to be responsive to the user. You should delegate long-running actions to another thread.
correct this is 1 of the codes that I tried... and this is an AWT event listener. But tell what's the problem in executing it this way. If LDAPConnection works with main method why not it work with event listener ? I have seen similar posts on many forum and unable to get the resolution
Use an ActionListener instead of MouseListener
btnYourLdapButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
doLdapRequest(ev);
}
});
You need to remember that the code inside the event listener will not be run in a separate thread. It will always run inside the Event Dispatch Thread (EDT) and for as long as that code is running, no other GUI updates will be possible, and the application will look like it's hanging. Read Writing Responsive User Interfaces with Swing to understand more. Here's some very rough example code that demonstrates handing a task off to another thread. I even left a space for you to insert your LDAP call!
package examples;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class EDTSeparation {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setLayout(new GridLayout(2, 1));
final JLabel label = new JLabel("");
f.add(label);
f.add(new JButton(new AbstractAction("Do Task") {
#Override
public void actionPerformed(ActionEvent e) {
// This method will be executed on the EDT
label.setText("Working...");
// Create a new Thread to do the long-running task so this method can finish quickly.
Thread t = new Thread(new LDAPTask(label));
t.setDaemon(true);
t.start();
}
}));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
});
}
private static class LDAPTask implements Runnable {
private final JLabel label;
public LDAPTask(JLabel label) {
this.label = label;
}
#Override
public void run() {
try {
// Use sleep to simulate something taking a long time.
// Replace this your long-running method call.
Thread.sleep(1000);
// If you need to handle GUI components, it must be done on the EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
label.setText("Done.");
}
});
} catch (InterruptedException e) {
}
}
}
}

Categories

Resources