Отправка сообщений на качели JTextArea из разных мест

У меня есть JTextArea, всегда видимый в моем главном окне приложения (журнал, если хотите), и я хочу использовать его для отображения активности, происходящей в системе (например, вывод имитации отладки, который вы бы сделали с помощью System.out.println( ) в условиях if или что-то еще)

Я имею в виду то, что делает пользователь на высоком уровне (например, «успешно загруженный файл» или «записанный на диск», «завершенный» и т. д.)

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

Может быть, сохранить сообщения во временный файл, а текстовое поле «отслеживает» этот файл на предмет изменений, как это можно сделать?


person Recct    schedule 28.11.2010    source источник


Ответы (4)


Самый простой способ — определить интерфейс регистратора:

package com.example.logging;
public interface ActivityLogger {
    void logAction(String message);
}

Затем передайте его своим компонентам без графического интерфейса, чтобы они не были привязаны к конкретной реализации:

public class FileLoader {

    private ActivityLogger logger;
    public FileLoader(ActivityLogger logger){
        this.logger = logger;
    }

    public void loadFile(){
        // load stuff from file
        logger.logAction("File loaded successfully");
    }

}

Теперь сделать реализацию, которая записывает в текстовый компонент, очень просто:

public class TextComponentLogger implements ActivityLogger{
    private final JTextComponent target;
    public TextComponentLogger(JTextComponent target) {
        this.target = target;
    }

    public void logAction(final String message){
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                target.setText(String.format("%s%s%n", 
                                             target.getText(),
                                             message));
            }
        });
    }
}
// Usage:
JTextArea logView = new JTextArea();
TextComponentLogger logger = new TextComponentLogger(logView);
FileLoader fileLoader = new FileLoader(logger);
fileLoader.loadFile();

Конечно, вы также можете использовать стандартную структуру ведения журнала (java.util.logging, slf4j, log4j и т. д.) и написать приложение, которое «записывает» текстовый компонент.

person gustafc    schedule 28.11.2010

Дизайн может быть довольно сложным. Возможно, у вас может быть метод открытого доступа, такой как updateText(), в классе, где будет ваш TextArea. Затем вы создаете своего рода «ресурсный» или «общий» класс (просто простой класс), который будет инициализироваться вместе при запуске вашего main(). Когда создается класс, содержащий ваш TextArea, экземпляр будет помещен в «общий» класс (этот общий класс должен быть одноэлементным), и поэтому все остальные классы вызывают этот «общий» класс (возможно, такой метод, как updateTextArea()) и что он будет делать, так это вызывать класс, содержащий TextArea, через этот экземпляр и вызывать TextArea для обновления текста.

person thotheolh    schedule 28.11.2010

Возможно, вам нужна консоль сообщений.

Java также имеет API "Logger".

person camickr    schedule 28.11.2010

Вы можете использовать EventBus, чтобы отделить свой графический интерфейс от других частей вашего приложения. (В моем блоге есть еще одно введение). Вы можете сделать что-то следующим образом:

public class LogArea extends JTextArea {
    public static final String LOG_TOPIC = "logarea_topic";

    public LogArea() {
        super();
        // Read in the annotations, register self as a listener to the topic
        AnnotationProcessor.process(this);
    }

    @EventTopicSubscriber(topic=LOG_TOPIC)
    public void logEvent(String topic, String text) {
        append(text + "\n");
    }

}

public class DomainClass {

    public void foo() {
        // Send out a notification throughout the system to whichever components
        // are registered to handle this topic.
        EventBus.publish(LogArea.LOG_TOPIC, "some text you want to appear in the log area");
    }

}

В реальной системе вы, вероятно, захотите переместить объявления тем в другой класс, чтобы их можно было использовать, не привязываясь к конкретной реализации. Например. у вас может быть класс Topics, который просто содержит статические строковые константы тем. Затем у вас может быть несколько классов, которые слушают эти темы и обрабатывают сообщения (например, у вас может быть стандартная структура ведения журнала, которая записывает в файл журнала в дополнение к компоненту jtextarea).

person I82Much    schedule 28.11.2010