我正在尝试使用JFrame显示图像,但该图像的路径每两秒更改一次。该路径包含在文本文件中。我可以毫无问题地在JFrame中显示单个图像,并且可以使用计数器显示一系列不同的图像,前提是我对路径进行硬编码。但我只是不知道如何每隔2秒显示一个在文本文件中记录新路径的图像。
我尝试使用缓冲区读取器读取文本文件然后将路径保存到bean但是因为我在循环中有缓冲区读取器,所以如果我从循环外部调用它,则返回null。
除了这种接缝之外,还有很长时间才能完成这项任务。有人能提出一个简单的方法来实现我的目标。我不能缝合从树上看木头。
感谢。
顺便说一句:这不是一个家庭作业,它只是我正在制作的个人计划。答案 0 :(得分:2)
以下解决方案最适合未运行Java 7+的用户。考虑查看MadProgrammer的解决方案,这对几乎每个应用程序来说都会更好。
可能不是最好的答案,只是觉得至少在这里找到一个问题会很好。
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @author Obicere
*/
public class LoadImageTest {
public LoadImageTest() {
final JFrame frame = new JFrame("Load Image Test");
final MyPanel panel = new MyPanel(ImageScanner.loadImage());
final ImageScanner scanner = new ImageScanner(panel);
frame.add(panel);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
new Thread(scanner).start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new LoadImageTest();
}
});
}
public static class ImageScanner implements Runnable {
private static final File PATH_FILE = new File("image.txt");
private final MyPanel instance;
private long lastModified = PATH_FILE.lastModified();
public ImageScanner(final MyPanel panel) {
this.instance = panel;
}
@Override
public void run() {
while (true) {
if (PATH_FILE.lastModified() != lastModified) {
System.out.println("Loading");
instance.setImage(loadImage());
lastModified = PATH_FILE.lastModified();
}
try {
Thread.sleep(50);
} catch (final Exception ignored) {
}
}
}
public static Image loadImage() {
try {
final byte[] data = Files.readAllBytes(Paths.get(PATH_FILE.toURI()));
final String path = new String(data);
System.out.println(path);
return ImageIO.read(new URL(path));
} catch (final Exception e) {
e.printStackTrace();
return null;
}
}
}
public class MyPanel extends JPanel {
private Image render;
public MyPanel(final Image render) {
this.render = render;
}
@Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
g.drawImage(render, 0, 0, this);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(render.getWidth(this), render.getHeight(this));
}
public void setImage(final Image image) {
this.render = image;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
repaint();
revalidate();
}
});
}
}
}
这样做会创建一个新线程来检查文件是否已更新。该线程将运行EDT,因此无需担心冻结应用程序。我还添加了一个50毫秒的超时,以免过多地对CPU征税。这取决于您自行决定。
这将是加载图像并将其渲染到JPanel上。这只是关于如何做到这一点的简单草案,仅仅是一个概念,而不是你真正想要使用的代码。我甚至觉得写这个有点不好。
答案 1 :(得分:2)
如果您使用的是Java 7,那么您可以利用内置的文件监视器服务...
首先看看Watching a Directory for Changes和Concurrency in Swing,特别是Worker Threads and SwingWorker
SwingWorker
将允许您监视事件调度线程之外的更改,允许您的UI继续响应用户和系统事件。
SwingWorker
还具有将更新重新同步回EDT的便捷方法,允许您安全地更新UI。
public class WatcherWorker extends SwingWorker<Void, String> {
private WatchService watcher;
private Map<WatchKey, Path> keys;
private Path path;
public WatcherWorker(Path path) throws IOException {
watcher = FileSystems.getDefault().newWatchService();
this.path = path;
path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE);
}
@Override
protected Void doInBackground() throws Exception {
while (true) {
WatchKey key = watcher.take();
List<String> lines = Files.readAllLines(path, Charset.defaultCharset());
if (lines.size() > 0) {
String imagePath = lines.get(0);
publish(imagePath);
}
}
}
@Override
protected void process(List<String> chunks) {
String imagePath = chunks.get(chunks.size() - 1);
// load new image
// apply image to what ever you need to use it with
// This would assume that you have a reference to something capable of
// using the said image ;)
}
}
然后你可以使用类似......
的东西Path p1 = Paths.get("/path/to/configuration/config.txt");
WatcherWorker worker = new WatcherWorker(p1);
worker.execute();