2017-02-14 5 views
1

Я разрабатываю пользовательский веб-искатель на основе cli на Java. Поскольку для отображения результата нужен удобный графический интерфейс, я должен добавить к нему качающийся кадр, включающий некоторые деревья, метки, таблицы и т. Д. Этот графический интерфейс является одним из его переключателей и должен быть запущен на всякий случай, когда пользователь вызывает его. Таким образом, я должен запустить этот интерфейс в новом потоке, чтобы при необходимости приложения могли выполнять другие задачи и обновлять компоненты внутри фрейма GUI. Мой класс GUI некоторые вещи, как:Используйте качели в другой теме

public class Frame extends JFrame { 
    ...... 
    public static JLabel urlLabel; 
    ...... 
    public static void run() { 
     urlLabel = new JLabel(); 
     urlLabel.setText("Test Url"); 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       new Frame().setVisible(true); 
      } 
     }); 
    } 
    ..... 
} 

И я раскошелиться его от моего основного класса, как это:

..... 
if(cmd.gui){ 
    Frame.run(); 
    Frame.urlLabel.setText("New Url"); 
} 
...... 

К сожалению, текст метки не меняется. Я уже тестировал repaint(), revalidate() и другие подобные функции, но ничего не получилось. Я проверил getText(), чтобы убедиться, что можно получить доступ к urlLabel из основного класса, и он сработал (я мог получить текст метки).

Мне было интересно, как я могу разобраться в этой проблеме? (В принципе, мне нужно запустить качающуюся раму в другой нити и управлять ее компонентами из основной резьбы)

Заранее спасибо.

+2

Вам просто нужно использовать выделенный качающийся поток, чтобы изменить элементы интерфейса, как вы уже делали с 'SwingUtilities.invokeLater', каждый раз! Или, может быть, я понимаю вашу проблему неправильно? – xander

+0

@xander Я уже это сделал. Качание начинается в новом выделенном потоке, и мне нужно обновить/изменить его компоненты. Как я уже сказал, это пользовательский веб-искатель, и мне нужно добавить новые собранные данные в графический интерфейс, пока приложение сканирует веб-сайт. –

+0

@SinaYazdanmehr Также помните, что Swing не является потокобезопасным, и все обновления пользовательского интерфейса ДОЛЖНЫ быть сделаны из контекста Диспетчерского потока событий. Вы также не должны полагаться на 'static' как метод передачи перекрестных объектов, это просто боль в коде. Вместо этого вы должны поделиться моделью между пользовательским интерфейсом и другими частями кода. Пользовательский интерфейс может использовать шаблон наблюдателя для получения обновлений при изменении модели и обеспечения ее обновления из EDT с помощью 'invokeLater'. Обычно вы используете 'SwingWorker', который будет управлять частью« не-UI », но через который можно было бы уведомить UI – MadProgrammer

ответ

0

Если вы используете invokeLater(), ваш Runnable будет запущен в EventThread после завершения текущей операции в этом потоке. Если ваш ярлык не обновлен, возможно, ваш EventThread занят чем-то другим - например. сканирование в Интернете.

Вам определенно необходимо убедиться в том, что выполняемые вами операции сканирования выполняются в другом потоке (запустите новый, не используйте тот, который работает в любом случае, поскольку это скорее всего EventThread). Затем вы можете использовать invokeLater() в этой другой теме, чтобы изменить метку в EventThread.

Подсказка: вы можете проверить, находитесь ли вы в EventThread, используя SwingUtilities.isEventDispatchThread().

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

0

Спасибо, ребята, за помощь. Наконец, я смог преодолеть это препятствие, используя SwingUtilities.invokeLater для обновления текста ярлыка. я упоминаю подход здесь, так как кто-то еще может понадобиться:

Основной класс:

public class Frame extends JFrame { 
...... 
    private static JLabel urlLabel; 
...... 
    public JLabel getU(){ 
    return urlLabel; 
    } 
    public static void run() { 
    urlLabel = new JLabel(); 
    urlLabel.setText("Test Url"); 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      new Frame().setVisible(true); 
     } 
    }); 
} 
    ..... 
} 

ГИП класс:

if(cmd.gui){ 
    Frame().run(); 
    SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       gui.getU().setText("New Url"); 
      } 
    }); 
} 
..... 

Просто вопрос об этом так: Так как я нужно обновлять некоторые метки и узлы дерева пару раз во время обхода, хотел знать, может ли запуск нового Runnable для каждого из них быть перегружен? Если да, как я могу это сделать?

--- UPDATE ---

По замечанию @ Ксандра, можно использовать лямбда вместо Runnable.Я думаю, что лямбда не имеет такой перегрузки, как это делает новый объект.

+0

1. Lambdas - это просто встроенные методы, поэтому я по сути то же самое, что и ваш код, а просто для написания/чтения. 2. Если вы можете совместить свой пользовательский интерфейс с одним вызовом 'SwingUtilities.invokeLater', но при необходимости его можно запускать много раз, он просто синхронизирует ваш« Runnable »в потоке пользовательского интерфейса swing. – xander