2011-01-28 48 views
1

我真的需要找到更好的方式来提出我的问题。 基本上我创建了一个程序,它从网页获取信息并在整个屏幕上很好地显示它。让一个主要方法等待更小的方法(java)

当用户关闭程序时,他们实际上隐藏了它。

我也有另一种方法,不断循环检查信息,看看是否已更新。 不幸的是,我现在遇到的问题是它循环快,我只希望它每40秒左右检查一次信息。

我试过的是在方法本身和程序的主体中插入一个等待(1000,1000)。但这两者都会导致IllegalMonitorStateException。

这是使线程正确等待的正确方法吗?或者,还有更好的方法? 注意:我唯一的线程是主要的。

主要

class Marquee 
{ 
public static void main(String[] args) throws InterruptedException 
{ 
    MyFrame frame = new MyFrame(); 
    frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 
    frame.setVisible(true); 
    frame.setAlwaysOnTop(true); 
    frame.setBackground(Color.BLACK); 
    frame.setResizable(true); 


    while(true) 
    { 
     // this doesnt work 
     frame.wait(1000,1000); 
     frame.notifyAll(); 

     frame.checkForNewUpdate(); 
     System.out.println(" ____________________________next line _______________________________"); 

    } 
} 
} 

检查更新

public String[] checkForNewUpdate() 
{ 
    //setVisible(true); 
    String tempUpdate = getEngineersUpdate(); 

    if (latestUpdate[0] != tempUpdate) 
    { 
     // do nothign 
     setVisible(false); 
    } 
    else if(latestUpdate[0]==tempUpdate) 
    { 
     latestUpdate[0] = tempUpdate; 
     //show the page again 
     setVisible(true); 
    } 
    else if(latestUpdate[0]!= "NULL") 
    { 
     // do nothing 
     //latestUpdate[0] = tempUpdate; 
    } 
    else 
    { 
     latestUpdate[0] = tempUpdate; 
    } 
    return latestUpdate; 
} 

1:我究竟做错了得到这个例外

2:是否有任何其他方法,使时间的差距在方法

3:我将不得不把所有这些方法放到另一个线程?请说不


// my constructor which I failed to mention has a timer in it. only i dont know hwo to use it 

class MyFrame extends JFrame implements ActionListener 
{ 
private ActionListener listener; 
private Timer t1; 
private String [] latestUpdate = new String[1]; 


public MyFrame() 
{ 
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();// gets the maximum size of the screen 
    setSize(d.width,(d.height/100)*10);//sets it to max. need to change this 

    // this shit find the max size of screen and puts it bottom left 
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
    GraphicsDevice defaultScreen = ge.getDefaultScreenDevice(); 
    Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds(); 
    int x = (int)rect.getMinX(); 
    int y = (int)rect.getMaxY()-getHeight(); 
    setLocation(x,y-30); 
    setTitle("ALERT::OUTAGE"); 
    MyPanel panel = new MyPanel(); 
    add(panel); 
    listener = this; 
    t1 = new Timer(50,listener); 
    t1.start(); 
} 

的要求,这里是getEngineersUpdate()

public String getEngineersUpdate() //gets data from page and sets it to string. 
{ 
    String update = "blank"; 

    final WebClient webClient = new WebClient(); 
    webClient.setJavaScriptEnabled(false);// javascript causes some serious problems. 
    webClient.setCssEnabled(false); 
    String forChecking; 

    HtmlPage page; 

    try 
    { 

     URL outageURL = new URL("file:\\C:\\Users\\0vertone\\Desktop\\version control\\OUTAGE\\Outages.html"); //local drive at home 


     page = webClient.getPage(outageURL); 


     //All this crap can be gone if we just give the table an id 
     Object[] dates = page.getByXPath("//span[@id='date']/text()").toArray(); 
     Object[] sites = page.getByXPath("//span[@id='site']/text()").toArray(); 
     Object[] issues = page.getByXPath("//span[@id='issue']/text()").toArray(); 
     System.out.println("" + dates[0].toString()); 
     System.out.println("" + sites[0].toString()); 
     System.out.println("" + issues[0].toString()); 

     update = (dates[0].toString() + " " + sites[0].toString() + " " +issues[0].toString()); 
     forChecking = dates[0].toString(); 




     /**some examples of the getCellAt() method*/ 
     //update = table.getCellAt(0,0).asText(); // This returns DATE/Time 
     //update = table.getCellAt(1,0).asText(); // This return the actual date 
     //update = table.getCellAt(0,1).asText(); // This returns, SITE/Sector 
     //update = table.getCellAt(1,1).asText(); // This returns the actual site issue 

    } 
    catch (FailingHttpStatusCodeException a) 
    { 
    System.out.println("Failing HTTP Status Execution"); 
    a.printStackTrace(); 
    } 
    catch (MalformedURLException b) 
    { 
    System.out.println("Malformed URL"); 
    b.printStackTrace(); 
    } 
    catch (IOException c) 
    { 
    System.out.println("IO PROBLEMS!"); 
    c.printStackTrace(); 
    } 
webClient.closeAllWindows(); 
return update; 
} 
+2

所有与GUI相关的调用应该发生在Swing事件调度线程(EDT)中。查看SwingUtilities.invokeLater或进行网络搜索以获取详细信息。即使您看起来只有一个线程,EDT在创建GUI时就开始运行。你也使用==来比较字符串,改用string.equals(otherString)。 – 2011-01-28 13:49:02

+0

你确实使用swing,所以main不是你唯一的线程。至少有事件调度线程 – 2011-01-28 13:52:45

回答

0
  1. 我认为你不能调用的JFrame的wait()的,但我不知道。
  2. 您必须在snychronized-block内调用wait()。 (下面的示例)
  3. Thread.sleep(1000l)可以使用,如果它在一个线程中运行,但看类Timer
  4. 这将是更好的设计,如果你创建一个线程,检查更新。您可以通过某种事件侦听器通知GUI(JFrame)关于要显示的新日期。

看看TimerCallable

+1

wait()可用于任何对象,但所有对wait()的调用都必须发生在同步块中:synchronized(object){object.wait(); } – 2011-01-28 13:47:33

+0

我实际上在MyFrame的构造函数中定义了一个计时器,我只是把它放在那里。但我不知道如何使用它。我仍然没有。 – OVERTONE 2011-01-28 14:05:23

0

你应该创建另一个线程,你应该从这个线程调用checkforNewUpdate方法。也别忘了使用SwingUtilities.invokeLater方法来更新你的UI在checkforNewUpdate方法中。这里是代码的一部分;

public class Marque   { 

    private JFrame frame; 
    class CheckForUpdate implements Runnable { 

     public void run() { 
      while(true) { 
       checkForNewUpdate(); 
       try { 
        Thread.sleep(40000); 
       } catch (InterruptedException e1) { 
        e1.printStackTrace(); 
        throw new RuntimeException(e1); 
       }      } 

     } 

     public String[] checkForNewUpdate()  { 
      //your code 
      // user interface interaction code 
      SwingUtilities.invokeLater(new Runnable() { 
       public void run() { 
        frame.setVisible(true); 
       } 
      }); 

     } 
    } 

    public Marque() { 
     frame = new JFrame(); 
     //....frame related code 
     new Thread(new CheckForUpdate()).start(); 


    } 
    public static void main(String[] arg) { 
     Marque marque = new Marque(); 


    } 
1

我已经更改了您的代码,因此它应该按照您的预期工作。我并不清楚getEngineersUpdate()是做什么的,所以我不能确定它是否可行,但我给了你一个开始。我已经包含了2个选项来处理它,并在评论中进行了解释。您也可以在构造函数中看到如何正确使用Timer。最后,我没有完整的代码,所以我必须一起装配一些东西来模拟它。

class Marquee { 
    public static void main(String[] args) throws InterruptedException { 
     MyFrame frame = new MyFrame(); 
     frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 
     frame.setVisible(true); 
     frame.setAlwaysOnTop(true); 
     frame.setBackground(Color.BLACK); 
     frame.setResizable(true); 
    } 
} 



class MyFrame extends JFrame { 
    private String [] latestUpdate = new String[1]; 
    private static final int DISPLAY_TIME = 3000; 
    private Timer displayTimer; 

    /* 
    * Option #1: 
    * Ideally, you'd have the thread that generates the "Engineers Update" messages call this 
    * method. If you can't make this event based, then you should use option #2 
    */ 
    public void newUpdate(String message) { 
     setVisible(true); 
     // change this to whatever you need to. 
     text.setText(message); 
     displayTimer.restart(); 
    } 

    // I used this to test it 
    private JTextField text; 

    public MyFrame() { 
     // gets the maximum size of the screen 
     Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 
     //sets it to max. need to change this 
     setSize(d.width, (d.height/100) * 10); 

     // this shit find the max size of screen and puts it bottom left 
     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     GraphicsDevice defaultScreen = ge.getDefaultScreenDevice(); 
     Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds(); 
     int x = (int) rect.getMinX(); 
     int y = (int) rect.getMaxY() - getHeight(); 
     setLocation(x, y - 30); 
     setTitle("ALERT::OUTAGE"); 

     //MyPanel panel = new MyPanel(); 
     //add(panel); 
     text = new JTextField("Initial Text"); 
     add(text); 

     // this creates a timer that when it goes off, will hide the frame 
     displayTimer = new Timer(DISPLAY_TIME, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       setVisible(false); 
      } 
     }); 
     // sets the timer not to repeat 
     displayTimer.setRepeats(false); 

     //This code is for option #2: 
     updateTimer = new Timer(UPDATE_INTERVAL, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       checkForNewUpdate(); 
      } 
     }); 
     updateTimer.start(); 
    } 

    // This is for option #2 
    private static final int UPDATE_INTERVAL = 1000; 
    private Timer updateTimer; 

    /* 
    * Option #2: 
    * Not ideal, but this should work. 
    */ 
    public String[] checkForNewUpdate() { 
     // I don't know how getEngineersUpdate() works 
     // which would have made it much easier to help you. 
     String tempUpdate = getEngineersUpdate(); 

     // String comparison doesn't work like this in java. 
     // you also had a sleeping NullPointerException here 
     if (!tempUpdate.equals(latestUpdate[0])) { 
      // this is when you have a new update, correct? 
      newUpdate(tempUpdate); 
      latestUpdate[0] = tempUpdate; 
     } else if (tempUpdate.equals(latestUpdate[0])) { 
      // it's the same update as last time, so do nothing 
     } else if (tempUpdate.equals("NULL")) { 
      // You need to handle this according to what getEngineersUpdate() does 
     } 
     return latestUpdate; 
    } 

    // This code is rigged to show how it would work 
    private static int i = 0; 
    private String getEngineersUpdate() { 
     // 1 in 6 chance of returning "NULL" 
     if (Math.random() * 6 - 1 < 0) 
      return "NULL"; 

     // probability of 1 in 4 of generating a new update 
     if(Math.random() * 4 - 1 < 0) 
      return "UPDATE #"+i++; 
     else 
      return "UPDATE #"+i; 
    } 
}