将代码从ActionListener移到main()

问题描述 投票:0回答:1

问题:

我对java.awt.Button有以下代码:

Button btn = new Button("abcde");
btn.addActionListener((ActionEvent e) ->
{
    String s = btn.getLabel().toUpperCase();    
    btn.setLabel(s);    
});

我需要将btn.addActionListener中的代码移至public static void main(String[] args),如下所示(使用伪代码):

Button btn = new Button("abcde");
btn.addActionListener((ActionEvent e) ->
{
    notify_main()_that_button_had_been_clicked();  
});

public static void main(String[] args)
{
    block_until_button_clicked();

    String s = UI.getButton().getLabel();
    s = s.toUpperCase();
    UI.getButton().setLabel(s);
}

相关信息:

我知道有更好的GUI开发解决方案,但仅限于将AWT用于UI。

由于法律限制,我无权更改上述内容,也无法提供有关真实代码的详细信息。

为了补救上述问题,我将提交以下MVCE。请基于此回答:

import java.awt.Frame;
import java.awt.Button;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class ResponsiveUI extends Frame
{
    public final Button btn = new Button("abcde");

    public ResponsiveUI()
    {
        add(btn);

        btn.addActionListener((ActionEvent e) ->
        {
            String s = btn.getLabel().toUpperCase();    
            btn.setLabel(s);    
        });
    }

    public static void main(String[] args)
    {
        ResponsiveUI rui = new ResponsiveUI();
        rui.addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent we)
            {
                System.exit(0);
            }
        });
        rui.setSize(250, 150);
        rui.setResizable(false);
        rui.setVisible(true);
    }
}

我为解决这个问题而努力:

我已经广泛使用Google,并且能够找到一些有用的链接。

  1. UI将在单独的线程中运行,这将使它响应(尽管我不知道如何正确地join())。
  2. 对于信令机制,wait()notify()似乎是正确的选择。
  3. 要设置Button的文本,我可以使用EventQueue.InvokeAndWait
  4. 要获取Button的文本,我不知道该怎么办,但是我有一个丑陋的解决方法。

下面是修改后的MVCE:

import java.awt.Frame;
import java.awt.Button;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;

public class ResponsiveUI extends Frame
{

    public final Object lock = new Object();  // POINT #2 : signaling mechanism
    public final Button btn = new Button("abcde");

    public ResponsiveUI()
    {
        add(btn);

        btn.addActionListener((ActionEvent e) ->
        {
            // POINT #2 : signal the main() thread that button is clicked
            synchronized (lock)
            {
                lock.notify();
            } 
        });
    }

    public static void main(String[] args)
    {
        ResponsiveUI rui = new ResponsiveUI();

        // POINT #1: put UI into separate thread, so we can keep it responsive
        // POINT #1: I still do not know how to properly join() (it works OK though)
        Runnable r = () ->
        {
            rui.addWindowListener(new WindowAdapter()
            {
                @Override
                public void windowClosing(WindowEvent we)
                {
                    System.exit(0);
                }
            });
            rui.setSize(250, 150);
            rui.setResizable(false);
            rui.setVisible(true);
        };

        EventQueue.invokeLater(r);

        try
        {
            synchronized (rui.lock)    // POINT #2  
            {                          // POINT #2 
                rui.lock.wait();       // POINT #2 : wait for button press

                final Button b = new Button();  // POINT #4 : EventQueue uses final local variables
                                                // store text into temp button (ugly but works)
                EventQueue.invokeAndWait(() ->  // POINT #4
                {
                    b.setLabel(rui.btn.getLabel());  
                });
                // we could do all kind of things, but for illustrative purpose just transform text into upper case
                EventQueue.invokeAndWait(() ->    // POINT #3 :
                {
                    rui.btn.setLabel(b.getLabel().toUpperCase());

                });
            }
        }
        catch (InterruptedException | InvocationTargetException ex)
        {
            System.out.println("Error : " + ex);
        }
    }
}
java awt
1个回答
0
投票

一般方法是,您需要与main方法和ActionListener实现同时共享一些锁或信号灯。拥有共享信号量后,main方法可以阻止(等待)该信号量,并且ActionListener可以通知该信号量。

使用伪代码:

Lock lock = new Lock();

Button btn = new Button("abcde");
btn.addActionListener((ActionEvent e) -> {
    lock.notify();
});

public static void main(String[] args) {

    lock.waitUntilNotified();

    String s = UI.getButton().getLabel();
    s = s.toUpperCase();
    UI.getButton().setLabel(s);
}

我已将确切的信号量实现留给您,因为您的应用程序的性质将决定哪种机制最有效。例如,也许您想使用一个简单的对象并在其上调用waitnotify方法,或者,如果您需要对加载到该队列中的元素(即项)进行处理,则可以使用阻塞队列。排队,按下按钮表示排队的物品现在应处理)。

您可以在此处找到有关如何实现waitnotify方法的信息:

共享锁可能很困难,因为在main方法中,不能将锁作为方法参数传递。一种简单的方法(在此上下文之外不是首选)是将锁创建为static变量:

public class Application {

    public static final Lock LOCK = new Lock();

    public static void main(String[] args) {

        LOCK.waitUntilNotified();

        String s = UI.getButton().getLabel();
        s = s.toUpperCase();
        UI.getButton().setLabel(s);
    }
}

在其他班级:

public class SomeOtherClass {

    Button btn = new Button("abcde");
    btn.addActionListener((ActionEvent e) -> {
        Application.LOCK.notify();
    });
}

请记住,Lock只是伪代码,应该用您决定使用的锁的任何实现方式替换。

© www.soinside.com 2019 - 2024. All rights reserved.