简体   繁体   中英

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?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM