2014-11-20 37 views
0

是否可以将GUI呈现到BufferedImage或其他类型的内存图像而不显示在屏幕上?将GUI渲染到内存中的图像

我知道这会松散所有类型的硬件加速,但对于每秒刷新一次或两次的简单GUI,这不应该成为问题。

已经尝试让JavaFX输出一个图像,但我找不到一种方法可以忽略屏幕上的渲染。有谁知道用JavaFX或Swing做这件事的方法吗?

使用简单的图像操作自己绘制一个简单的GUI是没有问题的,但是接下来我必须手工完成所有操作,并且使用Swing或FX会使它更容易。

编辑: 为了使它更清晰一点,我没有一个活动的显示,但我可以保存一个图像,然后通过其他方式显示。确切地说,它是一个覆盆子pi,但没有使用GPIO端口连接tft显示器的主显示设备。所以我不能直接将UI呈现给显示设备,但需要创建一个可以保存在特定位置的图像。到目前为止我尝试过的所有方法都需要主显示设备。

+0

如果我正确地理解了你,这个术语称为* double buffering *,并且是可能的。这取决于你如何处理你的渲染。现在这个问题太广泛了。选择FX或Swing(或两者的组合),并且更具体(在这种情况下输出图像和渲染它们之间的区别是什么?您的GUI包含组件?..) – 2014-11-20 20:23:09

回答

3

是的,有可能呈现一个GUI到图像离屏。

这里是使用JavaFX的样品,与实施例的图像输出如下:

image

的示例的工作原理是在图表渲染到未添加到任何窗口和没有窗口(阶段在一个场景JavaFX术语)已经被显示。 snapshot方法用于拍摄节点的快照,然后使用ImageIO实用程序将快照保存到磁盘。

如果底层硬件/软件平台支持,则屏幕外场景的渲染将被硬件加速。

import javafx.application.*; 
import javafx.collections.*; 
import javafx.embed.swing.SwingFXUtils; 
import javafx.scene.*; 
import javafx.scene.chart.PieChart; 
import javafx.scene.image.Image; 
import javafx.scene.layout.Region; 
import javafx.stage.Stage; 

import javax.imageio.ImageIO; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.*; 
import java.util.logging.*; 

public class OffscreenImageRecorder extends Application { 
    private static final Logger logger = Logger.getLogger(OffscreenImageRecorder.class.getName()); 

    private static final String IMAGE_TYPE = "png"; 
    private static final String IMAGE_FILENAME = "image." + IMAGE_TYPE; 
    private static final String WORKING_DIR = System.getProperty("user.dir"); 
    private static final String IMAGE_PATH = new File(WORKING_DIR, IMAGE_FILENAME).getPath(); 

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS"); 
    private final Random random = new Random(); 

    private final int CHART_SIZE = 400; 

    @Override 
    public void start(Stage stage) throws IOException { 
     Parent chart = createChart(); 
     Image image = snapshot(chart); 
     exportPng(SwingFXUtils.fromFXImage(image, null), IMAGE_PATH); 

     Platform.exit(); 
    } 

    private Parent createChart() { 
     // create a chart. 
     final PieChart chart = new PieChart(); 
     ObservableList<PieChart.Data> pieChartData = 
       FXCollections.observableArrayList(
         new PieChart.Data("Grapefruit", random.nextInt(30)), 
         new PieChart.Data("Oranges", random.nextInt(30)), 
         new PieChart.Data("Plums", random.nextInt(30)), 
         new PieChart.Data("Pears", random.nextInt(30)), 
         new PieChart.Data("Apples", random.nextInt(30)) 
       ); 
     chart.setData(pieChartData); 
     chart.setTitle("Imported Fruits - " + dateFormat.format(new Date())); 

     // It is important for snapshots that the chart is not animated 
     // otherwise we could get a snapshot of the chart before the 
     // data display has been animated in. 
     chart.setAnimated(false); 

     chart.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); 
     chart.setPrefSize(CHART_SIZE, CHART_SIZE); 
     chart.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); 

     return chart; 
    } 

    private Image snapshot(final Parent sourceNode) { 
     // Note: if the source node is not in a scene, css styles will not 
     // be applied during a snapshot which may result in incorrect rendering. 
     final Scene snapshotScene = new Scene(sourceNode); 

     return sourceNode.snapshot(
       new SnapshotParameters(), 
       null 
     ); 
    } 

    private void exportPng(BufferedImage image, String filename) { 
     try { 
      ImageIO.write(image, IMAGE_TYPE, new File(filename)); 

      logger.log(Level.INFO, "Wrote image to: " + filename); 
     } catch (IOException ex) { 
      logger.log(Level.SEVERE, null, ex); 
     } 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

谢谢!我不知道在场景显示之前你能看到场景元素的图形。 Allways认为你必须做primaryStage.setScene(...); primaryStage.show();创建图形。现在只需要弄清楚如何创建Application对象作为后台线程而不是主线程。但那是另一个话题。 – 2014-11-21 08:12:29

+0

非常好的解决方案! – 2014-11-21 14:29:18

0

这是一个黑客攻击的一位,但你可以(在本例中使用的Swing)创建一个不可见的位置的框架,它的位置是:

frame = new JFrame("Invisible frame"); 
frame.setBounds(-1000, 100, 640, 480); 
+0

这仍然会接管我想要避免的rapsberry的图形输出。 – 2014-11-20 21:36:59