In November 2016, I thought, "If you want to have a JavaFX session, let's make a slideshow tool with JavaFX", so I just did it, so I decided to leave it in the article.
A slide show is a coined word that combines slide and show, and seems to be one word. [Wikipedia Japanese version of the article](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%A9%E3%82%A4%E3%83%89%E3%82% It was written in B7% E3% 83% A7% E3% 83% BC).
There are many implementation examples of slide show (presentation) tools using JavaFX, including Mr. Sakuraba of Java Champion.
-Presentation tool with JavaFX -Tools for making slides in Markdown with JavaFX
I just wanted to implement it in a way that was easy for me to use.
――Characters and images can be displayed in full screen …… Put Pane with Label in Scene and display in full screen? --Multiple slides can be switched and displayed --You can describe the contents of the slide with some kind of markup ... Markdown? --You can convert slides to PDF ... Make screenshots into one file?
I think there are several ways to do it.
-Create content with reveal.js or Remark.js and display it in WebView …… It looks good when made with this, and it is easy to arrange and convert to PDF. --Display PDF content --Convert content to JavaFX Pane for display
I've already done 1 so I decided to make it all in JavaFX this time.
Name | version |
---|---|
Java SE | 1.8.0_121 |
OS | Windows 10 |
Eclipse | 4.5 |
Gradle | 3.0 |
I put the whole source code in the GitHub repository below.
The points are introduced below.
Allowed developers to write content in Markdown, which they are familiar with on Qiita and GitHub. The degree of freedom is low, but you can easily prepare the content as shown below.
# Title
toastkidjp
##About this slide 1234567890123456789012345678901234567890
The other day, java with momentum.io.I've replaced the code that used File with Path and Files, so I'll introduce it from the perspective of rewriting the existing code. If you're already familiar with NIO2, you probably won't notice anything after reading this article.
By the way, the new file-related API from JDK7 is NIO2(New I/O 2)It seems that it is called, MUJI is 1.It seems to refer to Channels and Charsets added in the 4th era.
##Code can also be placed
` ``java
(1..100)
.collect{it % 15 == 0
? "FizzBuzz"
: it % 3 ==0
? "Fizz"
: it % 5 == 0
? "Buzz"
: it
}
.forEach{print it + ", "}
` ``
#that's all
Thank you very much.
Note that I can't use JavaCC, so Parser is a childish implementation that reads the text of the Markdown file line by line ...
In order to display the scroll bar when the height of the content exceeds the height of the display, we have implemented an implementation that inherits ScrollPane and puts a Pane that collects Nodes that display strings and images in the Content.
Put all slides in List, 1 Draw on StackPane and only current ones Is displayed, and everything else is hidden.
If you use the default Label object, strings that exceed the display area will not be displayed and will be truncated.
The following settings have been made to the Label object.
Settings to prevent strings from being truncated
label.setWrapText(true);
label.setMinHeight(Region.USE_PREF_SIZE);
With reference to the Qiita slide method, vertical scrolling is possible when the slide exceeds the display height. Specifically, the Slide class inherits ScrollPane and makes the following settings in the constructor. This allows you to disable side-scrolling and bring up the vertical scroll bar only when you need it.
Disable side-scrolling and bring up a vertical scroll bar only when needed
this.setHbarPolicy(ScrollBarPolicy.NEVER);
this.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
In addition, I think that it is because many Slide objects are overlapped, but since I could not move the scroll bar with the mouse, I am trying to move it by calling the following method with a keyboard shortcut.
Scroll up
setVvalue(getVvalue() - 0.20d);
Scroll down
setVvalue(getVvalue() + 0.20d);
Considering the ease of operation, we have prepared the following submenus.
The submenu Controller and the Main class, which implements specific functions, are separate classes. It is necessary to pass the event received in the submenu to the Main class for processing. There are several ways to do this, this time using a library called Reactor.
Prepare various message classes to convey what you want the Main class to process. Create each class as an implementation of the Message interface.
Create an event object with the @FXML annotated method and pass it to the Main class using TopicProcessor. TopicProcessor creates an instance when the submenu class is initialized, passes the object to the Main class via getter, subscribes in the Main class, and branches to the processing according to the implementation type of the event in subscribe.
This implementation is based on the mechanism called EventBus used in Android application development.
Since the execution thread of the method called from TopicProcessor is not the JavaFX application thread, you need to use Platform.runLater to execute the drawing related processing.
The drawback of adopting this mechanism is that the Main class is simply bloated. This time I'm compromising on this.
In most cases, you may need to distribute a PDF of the slideshow as a resource. In preparation for such a case, we are also creating a PDF conversion function.
Convert all slides to PDF using PDFBox
try (final PDDocument doc = new PDDocument()) {
final int width = (int) stage.getWidth();
final int height = (int) stage.getHeight();
Interval.oneTo(slides.size()).each(i ->{
moveTo(i);
final long istart = System.currentTimeMillis();
final PDPage page = new PDPage(new PDRectangle(width, height));
try (final PDPageContentStream content = new PDPageContentStream(doc, page)) {
content.drawImage(LosslessFactory.createFromImage(
doc, slides.get(current.get() - 1).generateImage(width, height)), 0, 0);
} catch(final IOException ie) {
LOGGER.error("Occurred Error!", ie);
}
doc.addPage(page);
LOGGER.info("Ended page {}. {}[ms]", i, System.currentTimeMillis() - istart);
});
doc.save(new File(DEFAULT_PDF_FILE_NAME));
} catch(final IOException ie) {
LOGGER.error("Occurred Error!", ie);
}
I flip through the slides one by one, take captured images of each slide, and combine those images into a single PDF file using a library called PDFBox.
When I tried it, it took 1 second to convert 4 slides to PDF.
2017-02-16 23:32:30 INFO Main Ended page 1. 334[ms]
2017-02-16 23:32:31 INFO Main Ended page 2. 269[ms]
2017-02-16 23:32:31 INFO Main Ended page 3. 181[ms]
2017-02-16 23:32:31 INFO Main Ended page 4. 169[ms]
2017-02-16 23:32:31 INFO Main Ended generating PDF. 1032[ms]
By the way, Interval is Eclipse Collections A class in .eclipse.org/collections/ja/).
The PDF file prepared for the actual presentation has been uploaded to Speaker Deck. https://speakerdeck.com/toastkidjp/jjug-ccc-2016-fall-number-ccc-l5
It seems that the source code is often shown in the developer's presentation. It's hard to see the code as it is in Label, so I used a library (CodeArea) called RichTextFX which is an implementation of TextArea that can be highlighted.
As an example, Groovy's FizzBuzz can be displayed with syntax highlighting as shown below.
I don't know the cause well ... By the way, in the case of gradle run
, a similar error message is displayed, but it ends normally.
Console message
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000000737b584a, pid=15116, tid=0x000000000000246c
#
# JRE version: Java(TM) SE Runtime Environment (8.0_102-b14) (build 1.8.0_102-b14)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.102-b14 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [glass.dll+0x2584a]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# /path/to/slide_show/hs_err_pid15116.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
https://gist.github.com/toastkidjp/1d216a9ad98a65dd0bc42552dfe99791
I think it's because the display area is variable, but ... The existing tools that do well in this area are wonderful. I'm wondering if I can apply the method of acquiring the display size used by Mr. Takahashi and dynamically changing the font size in JJUG CCC 2016 Fall, but I haven't tried it yet.
When I used this tool before, I had a break of 30 minutes, so I carefully checked for display corruption there.
So far, I have introduced one of the ways to create a slideshow using JavaFX. Well, it's easier, safer and more powerful to use PowerPoint or LibreOffice normally. If it is a Qiita slide, you can publish it as an article as it is and it is easy to share. At this point, it's too lacking in functionality, and complacency accounts for a significant part of the reason for using it.
However, it seems that JavaFX can be used not only in Java but also in languages that run on the JVM, so I hope this article will be useful for those who want to give a slightly different presentation.
Recommended Posts