Связь между EDT и основными потоками - PullRequest
0 голосов
/ 16 апреля 2009

Я задавал много вопросов о проекте, над которым я работал в последнее время. Вот сценарий, в котором я нахожусь, и любая помощь или указание в правильном направлении очень помогли бы ...

Это сетевая программа, построенная с сервером и несколькими клиентами. Каждый клиент имеет графический интерфейс, который должен действовать в соответствии с командами, отправленными с сервера. Каждый клиент находится в классе под названием Player. Этот Player имеет графический интерфейс (расширяет JFrame) и метод main, а у Сервера есть только метод main (без GUI). Сначала этот класс создавался в основном потоке следующим образом:

EventQueue.invokeLater(new Runnable()
{
    public void run()
    {
        new Player().setVisible(true);
    }
 });

Это работало нормально, пока я не понял, что весь класс Player теперь выполняется в EDT. Поэтому, когда я жду команд с сервера, весь графический интерфейс блокируется до тех пор, пока эта команда не будет отправлена ​​и соответствующие действия не будут выполнены. Как вы можете себе представить, это ужасный дизайн, и оказалось, что это настоящая боль в среде программирования, когда каждый раз, когда вы хотите что-то проверить, вы должны найти какую-то безумную работу, чтобы графический интерфейс все еще оставался нетронутым.

Очевидно, я должен проверить команды с Сервера в отдельном потоке и запустить компоненты графического интерфейса в EDT. Моя вторая реализация имела два класса - один для GUI и один для Player. Идея заключалась в том, что Player имеет переменную, которая содержит графический интерфейс, чтобы я мог получить доступ к графическому интерфейсу из класса Player, что-то вроде этого:

class Player
{
    public GUI gui;

    ...

    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              this.gui = new GUI().setVisible(true);
         }
    }

Это тоже не работает, потому что this внутри нового объекта Runnable ссылается на объект Runnable, а не Player.

Как я могу общаться между Player классом в одном потоке и соответствующим классом GUI в потоке EDT?

Ответы [ 6 ]

3 голосов
/ 16 апреля 2009

Чтобы решить вашу проблему с указателем this, вы должны написать:

class Player
{
    public GUI gui;

    ...

    // And then start this gui inside of the EDT.
    EventQueue.invokeLater(new Runnable()
    {
         public void run()
         {
              Playser.this.gui = new GUI().setVisible(true);
         }
    }
}
2 голосов
/ 16 апреля 2009

Борис Павлович понимает синтаксис правильно (на самом деле вы можете просто удалить this.), но все же код не имеет смысла. Поле gui инициализируется через некоторое время после того, как событие Runnable поставлено в очередь, поэтому поток игрока может использовать его.

Вы можете построить Player на EDT (но выполнять сетевые операции вне EDT). Или зарегистрируйте GUI в качестве слушателя (наблюдателя) Player. invokeAndWait будет работать, но это опасно, так как часто приводит к случайным трудным для отладки тупикам.

1 голос
/ 16 апреля 2009

"пока я не понял, что весь класс Player теперь выполняется в EDT"

Конструктор возникает в EDT, но методы, вызываемые в этом классе, могут не быть.

Вы должны создать графический интерфейс игрока, как вы изначально планировали.

 EventQueue.invokeLater(new Runnable() 
 {
    public void run()
    {
        new Player().setVisible(true);
    }
 });

Но Игрок может запустить отдельный поток в конструкторе (лично я бы поделился связью между Игроками).

Конечно, методы обратного вызова с сервера должны использовать invokeLater () при изменении видимых компонентов.

1 голос
/ 16 апреля 2009

Вы можете попробовать это:

класс игрока { общедоступный графический интерфейс;

...

// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
     public void run()
     {
          Player.this.gui = new GUI().setVisible(true);
     }
}
0 голосов
/ 16 апреля 2009

Вместо использования анонимного внутреннего класса, почему бы просто не объявить класс, реализующий Runnable, и иметь конструктор, принимающий экземпляр GUI в качестве аргумента?

Кроме того, если ваш класс графического интерфейса пользователя не является потокобезопасным, рассмотрите возможность использования очереди сообщений для связи между EDT и основным потоком.

...