【问题标题】:Make a main method wait on a smaller method (java)使主要方法等待较小的方法(java)
【发布时间】:2011-01-28 13:30:07
【问题描述】:

我真的需要找到更好的方式来表达我的问题。 基本上我已经创建了一个程序,它从网页中获取信息并在屏幕上很好地显示它。

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

我还有另一种方法,它不断循环检查信息以查看是否已更新。 不幸的是,我遇到的问题是它循环速度很快,我只希望它每 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;
}

【问题讨论】:

  • 所有与 GUI 相关的调用都应该发生在 Swing 事件调度线程 (EDT) 中。查看 SwingUtilities.invokeLater 或进行网络搜索以了解详细信息。尽管您似乎只有一个线程,但 EDT 正在运行,因为它是通过创建 GUI 启动的。您还使用 == 来比较字符串,请改用 string.equals(otherString)。
  • 您确实使用了 swing,因此 main 不是您拥有的唯一线程。至少有事件调度线程

标签: java swing wait


【解决方案1】:

我已经更改了您的代码,因此它应该可以按您的预期工作。我不清楚 getEngineersUpdate() 的作用,所以我不能确定它是否会起作用,但我已经给了你一个开始。我已经包含了 2 个关于如何处理它的选项,并在 cmets 中进行了解释。您还可以看到如何在构造函数中正确使用 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;
    }
}

【讨论】:

  • getEngineersUpdate 只是在从网页获取后返回一个字符串。
  • 实际上更容易看到这里发生了什么。非常感谢。我很好奇为什么你有 math.random 。我很抱歉我是个菜鸟,我不擅长事件驱动的东西。基本上:get EngineersUpdate 从 http 网页返回一个字符串,它的大量代码会引起混淆。检查更新运行 getEngineersupdate 并检查它是否最近更新。如果它已更新,则页面上会显示一个简洁的图形和消息。我创建了一个带有动作监听器的框架和面板来为我做这件事
  • 永远不要为缺乏知识而道歉。 math.random() 在那里为代码创建一个“随机”测试。值得一提的是,您不能将架构更改为事件驱动(因为您是从网站拉取数据)。
  • 好吧,这可能是可行的。这段代码很棒,它可能正是我需要的。计时器如何工作的一个例子很棒。我觉得我让自己变得复杂。目前我试图弄清楚如何在面板而不是文本字段上显示消息。顺便说一句,网站页面上的文字总是在变化。所有 checkforUpdates 的设计目的是检查我收到的最后一条消息是否与这条消息不同,以重新显示已最小化的框架,因此从这个意义上说,它可能是事件驱动的(除非我完全错误地理解了事件是什么
  • ive 包含了获取工程师更新消息。但我可以看到程序的流程没有什么区别。我需要等待的方法仍然只是比较2个字符串。
【解决方案2】:
  1. 我认为您不能在 JFrame 上调用 wait(),但我不确定。
  2. 您必须在同步块内调用wait()。 (以下示例)
  3. Thread.sleep(1000l) 可以使用,如果它在线程中运行,但要查找类 Timer
  4. 如果您创建一个检查更新的线程,那将是更好的设计。您可以使用某种事件侦听器通知 GUI (JFrame) 要显示的新日期。

看看TimerCallable

【讨论】:

  • wait() 将适用于任何对象,但对 wait() 的所有调用都必须发生在同步块中: synchronized (object) { object.wait(); }
  • 我实际上在 MyFrame 的构造函数中定义了一个计时器,我只是把它放在那里。但我不知道如何使用它。我还是没有。
【解决方案3】:

你应该创建另一个线程,你应该从这个线程调用 checkforNewUpdate 方法。并且不要忘记使用 SwingUtilities.invokeLater 方法在 checkforNewUpdate 方法中更新你的 UI。这是代码的一部分;

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


    }

【讨论】:

  • 试图将它与我的代码结合起来会很困难。对于某些部分,我了解您在做什么。我还有其他方法可以尝试使用,所以我想我只需要解决它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多