如何让我的程序每小时检查一次股票市值

我正在制定一个程序,以检查股票市场的符号,我做到了这一点,并添加了一个基本的gui。 我很困惑如何每小时检查一次,如果它增加则创建绿色向上箭头,如果减少则创建红色向下箭头。

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()); } } } 

我甚至需要一个线程吗? 我以前从来没有做过,并试图添加有意义的东西。 我想我要么需要一个线程,要么使用java的Timer?

使用SwingWorker在后台执行长时间运行的任务,同时根据长时间运行的任务的某些结果更新UI。 这意味着,它实际上是两个不同的线程相互通信 – 工作线程和事件调度线程(EDT)


但在此之前,我想指出一些关于你的代码的注释。

  • 在EDT中调用UI的初始化。 也就是说,不是直接调用new QuoteTracker().buildGui() ,而是在传递给SwingUtilities.invokeLaterRunnable的run方法中调用它(就像这样 )

  • 类应该按照Java标准以大写字母开头。


要在现有代码中应用SwingWorker ,您可以执行以下操作:

首先,必须将checkQuote方法放在其他类(理想情况下是服务类)中,然后修改checkQuote方法以返回设置为textfield resultString 。 像这样的东西

 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 ""; } } 

然后,您可以使QuoteTracker类主要关注应用程序的UI部分。 只需将服务对象创建为实例级别字段,以便您可以在类中自由调用checkQuote方法。

单击按钮时调用SwingWorker。

 public void actionPerformed(ActionEvent ev) { new SwingWorker() { @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 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(); } 

请注意, done()将在doInBackground()执行完成后执行,这意味着,在我发布的代码中,它将永远不会执行,因为用于定期调用checkQuote的while循环是无限的。 只需修改它,以便您可以根据需要中断该循环

进一步阅读: Swing中的并发性

你也可以在主线程中使用thread和normal while循环,但是首先,你需要启动线程,并且该线程必须引用你的对象。

public void buildGui() {添加以下行

 Thread t1 = new Thread(new checkingQuote()); t1.start(); 

这将启动您的线程,为了测试目的,我修改了checkingQuote

 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; } } } } 

我在文本框中看到数字更改….同样,您可以更改逻辑以获取并显示引号..但您必须保留以前报价的值以与最新代码进行比较以显示绿色和红色通知。 ..

在gui应用程序中,最好使用Timer ,也可以使用ScheduledThreadPoolExecutor 。 但在第二种情况通知中,您的计划任务可能在非GUI线程中运行。 由于无法直接从另一个线程调用ATW / Swing,因此应将对Swing的任何调用包装到SwingUtilities.invokeLater()方法中。

另请注意,当您在GUI线程中执行持久性操作时,整个GUI将变得无关紧要。 因此,为了获得更好的响应性,您将在单独的线程中进行查询,并在引号检查后通过invokeLater将结果公开给Swing。 所以你的checkQuote方法可以这样重写:

 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(); } 

并从Timer和按钮单击侦听器调用它。