在开发Swing应用程序时,我遇到了一个自己无法处理的问题。我正在努力坚持
Model-Viewer-Presenter
图案请记住,我可能误解了如何利用这种模式。在
Presenter
层我正在读取文件内容(I/O操作,相当长)。阅读完成后,我想设置的内容
JLabel
到从文件中读取的内容。看起来很容易。然而,读取文件内容的代码非常快,它试图在构建GUI和初始化类中的JLabel字段之前设置JLabel域的内容。
import javax.swing.SwingUtilities;
public class Presenter {
private final View view;
private final Model model;
@Inject
public Presenter(final View view, final Model model) {
this.view = view;
this.model = model;
/**
* In reality, I have here reading a file and invoking
* view.updateStatusLabel() with its content.
* The following code will produces NPE as view has not been initialized.
* */
SwingUtilities.invokeLater(() -> view.updateStatusLabel("test"));
}
}
这是
View
GUI初始化的部分:
public class View {
private final Presenter presenter;
private JLabel statusLabel;
private JTextField inputField;
public View() {
this.presenter = new Presenter(this, new Model());
}
public void createUI() {
this.statusLabel = new JLabel();
// other GUI initilization
// ...
}
//called by the presenter to update the status label
public void updateStatusLabel(final String text) {
statusLabel.setText(text);
}
}
应用
main
方法:
import com.google.inject.Guice;
import com.google.inject.Inject;
import lombok.RequiredArgsConstructor;
import javax.swing.SwingUtilities;
@RequiredArgsConstructor(onConstructor = @__(@Inject))
public class Main {
private final View view;
public static void main(final String[] args) {
final Main main = Guice.createInjector().getInstance(Main.class);
SwingUtilities.invokeLater(main.view::createUI);
}
}
如果这是重要的事情,我使用
Guice
以覆盖依赖项注入。即使没有
Guice
就会出现这个问题。以下是我的依赖项:
<guice.version>7.0.0</guice.version>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
编辑
感谢@Gilbert勒布朗克的评论,我设法重写了代码以避免NPE。请参阅下面的更新代码。我通过删除了依赖项注入
Guice
这样代码现在读起来(我希望如此)就更容易了。代码按预期工作。然而,由于我是Swing的新手,我可能犯了一些错误,希望有人能指出这些错误,以便纠正。
应用程序起点:
import javax.swing.SwingUtilities;
public class Main {
public static void main(final String[] args) {
SwingUtilities.invokeLater(new View()::createUI);
}
}
型号:
public class Model {
private String password;
private boolean initiliaized;
// getters and setters here
}
所需的接口
Observer
设计模式:
interface Observer {
void guiInitialized();
}
interface Subject {
void registerObserver(Observer observer);
void notifyObservers();
}
节目主持人
public class Presenter implements Observer {
private final View view;
private final Model model;
public Presenter(final View view, final Model model) {
this.view = view;
this.model = model;
new Thread(() -> {
try {
Thread.sleep(5_000);
model.setPassword("password");
model.setInitiliaized(true);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
@Override
public void guiInitialized() {
// wait until gui is initialized
new Thread(() -> {
while ( !model.isInitiliaized() ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// GUI is initliazed by now
view.updateStatusLabel("init");
}).start();
}
}
看法
public class View {
private final Presenter presenter;
private final List<Observer> observers = new ArrayList<>();
private JLabel statusLabel;
private JTextField inputField;
public View() {
this.presenter = new Presenter(this, new Model());
}
@Override
public void registerObserver(final Observer observer) {
this.observers.add(observer);
}
@Override
public void notifyObservers() {
observers.forEach(Observer::guiInitialized);
}
public void createUI() {
this.statusLabel = new JLabel();
// other GUI initilization
// ...
registerObserver(presenter);
notifyObservers();
}
//called by the presenter to update the status label
public void updateStatusLabel(final String text) {
statusLabel.setText(text);
}
}