feature: 初步实现全屏播放

This commit is contained in:
2025-11-25 14:36:19 +08:00
parent b97d712247
commit cdc02d6bbd
4 changed files with 837 additions and 0 deletions
@@ -470,6 +470,86 @@ public class Controller implements Initializable {
} }
} }
/**
* 开始演示(默认淡出淡入效果)
*/
@FXML
public void onStartPresentation(ActionEvent actionEvent) {
if (currentSlide == null || currentSlide.getPages().isEmpty()) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
startPresentation(TransitionEffect.FADE);
}
/**
* 使用淡出淡入效果播放演示
*/
@FXML
public void onPresentationWithFade(ActionEvent actionEvent) {
if (currentSlide == null || currentSlide.getPages().isEmpty()) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
startPresentation(TransitionEffect.FADE);
}
/**
* 使用从右推入效果播放演示
*/
@FXML
public void onPresentationWithPushLeft(ActionEvent actionEvent) {
if (currentSlide == null || currentSlide.getPages().isEmpty()) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
startPresentation(TransitionEffect.PUSH_LEFT);
}
/**
* 使用从左推入效果播放演示
*/
@FXML
public void onPresentationWithPushRight(ActionEvent actionEvent) {
if (currentSlide == null || currentSlide.getPages().isEmpty()) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
startPresentation(TransitionEffect.PUSH_RIGHT);
}
/**
* 使用缩放放大效果播放演示
*/
@FXML
public void onPresentationWithZoomIn(ActionEvent actionEvent) {
if (currentSlide == null || currentSlide.getPages().isEmpty()) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
startPresentation(TransitionEffect.ZOOM_IN);
}
/**
* 使用旋转翻页效果播放演示
*/
@FXML
public void onPresentationWithRotate(ActionEvent actionEvent) {
if (currentSlide == null || currentSlide.getPages().isEmpty()) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
startPresentation(TransitionEffect.ROTATE);
}
/**
* 启动演示
*/
private void startPresentation(TransitionEffect transition) {
PresentationWindow presentationWindow = new PresentationWindow(currentSlide, transition);
presentationWindow.show();
}
/** /**
* 显示警告对话框 * 显示警告对话框
*/ */
@@ -0,0 +1,677 @@
package dev.bytevibe.hyperpoint;
import javafx.animation.*;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
/**
* 全屏演示窗口,支持翻页和动画效果
*/
public class PresentationWindow {
private final Slide slide;
private final Stage stage;
private final Canvas canvas;
private final StackPane root;
private int currentPageIndex = 0;
private TransitionEffect currentTransition = TransitionEffect.FADE;
private boolean isTransitioning = false;
public PresentationWindow(Slide slide, TransitionEffect transition) {
this.slide = slide;
this.currentTransition = transition;
this.stage = new Stage();
this.canvas = new Canvas();
this.root = new StackPane();
initializeStage();
}
private void initializeStage() {
// 页面标准宽高比 (4:3)
final double PAGE_WIDTH = 1024;
final double PAGE_HEIGHT = 768;
final double ASPECT_RATIO = PAGE_WIDTH / PAGE_HEIGHT; // 4:3 = 1.333...
// 设置全屏,获取屏幕分辨率
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.initStyle(StageStyle.UNDECORATED);
// 绑定Canvas大小到rootCanvas会根据root大小自动调整
canvas.widthProperty().bind(root.widthProperty());
canvas.heightProperty().bind(root.heightProperty());
// 添加键盘和鼠标事件处理
root.setOnKeyPressed(this::handleKeyEvent);
root.setOnMouseClicked(this::handleMouseClick);
root.getChildren().add(canvas);
root.setStyle("-fx-background-color: #000000;");
root.setFocusTraversable(true);
Scene scene = new Scene(root);
stage.setScene(scene);
// 监听Scene大小变化,计算缩放因子
scene.widthProperty().addListener((obs, oldVal, newVal) -> drawCurrentPage(null));
scene.heightProperty().addListener((obs, oldVal, newVal) -> drawCurrentPage(null));
// 显示第一页
drawCurrentPage(null);
}
/**
* 显示演示窗口
*/
public void show() {
stage.show();
root.requestFocus();
}
/**
* 处理键盘事件
*/
private void handleKeyEvent(KeyEvent event) {
if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.SPACE) {
nextPage();
} else if (event.getCode() == KeyCode.LEFT) {
previousPage();
} else if (event.getCode() == KeyCode.ESCAPE) {
exitPresentation();
}
}
/**
* 处理鼠标点击事件
*/
private void handleMouseClick(MouseEvent event) {
if (event.getClickCount() == 1) {
nextPage();
}
}
/**
* 下一页
*/
private void nextPage() {
if (isTransitioning || currentPageIndex >= slide.getPages().size() - 1) {
return;
}
currentPageIndex++;
playTransition(currentTransition);
}
/**
* 上一页
*/
private void previousPage() {
if (isTransitioning || currentPageIndex <= 0) {
return;
}
currentPageIndex--;
playTransition(currentTransition);
}
/**
* 播放过渡动画
*/
private void playTransition(TransitionEffect effect) {
isTransitioning = true;
switch (effect) {
case FADE:
playFadeTransition();
break;
case PUSH_LEFT:
playPushTransition(-canvas.getWidth(), 0);
break;
case PUSH_RIGHT:
playPushTransition(canvas.getWidth(), 0);
break;
case PUSH_DOWN:
playPushTransition(0, canvas.getHeight());
break;
case PUSH_UP:
playPushTransition(0, -canvas.getHeight());
break;
case ZOOM_IN:
playZoomTransition(0.5, 1.0);
break;
case ZOOM_OUT:
playZoomTransition(1.0, 0.5);
break;
case ROTATE:
playRotateTransition();
break;
default:
drawCurrentPage(null);
isTransitioning = false;
}
}
/**
* 淡出淡入动画
*/
private void playFadeTransition() {
int duration = currentTransition.getDuration();
int halfDuration = duration / 2;
// 保存当前页面索引
int previousPageIndex = currentPageIndex - 1;
if (previousPageIndex < 0) previousPageIndex = slide.getPages().size() - 1;
// 淡出旧页面,显示黑屏,淡入新页面
AnimationTimer animationTimer = new AnimationTimer() {
private long startTime = System.currentTimeMillis();
private final long fadeOutDuration = halfDuration;
private final long fadeInDuration = halfDuration;
@Override
public void handle(long now) {
long elapsed = System.currentTimeMillis() - startTime;
if (elapsed < fadeOutDuration) {
// 淡出阶段
double progress = (double) elapsed / fadeOutDuration;
drawFadeTransition(progress, true);
} else if (elapsed < fadeOutDuration + fadeInDuration) {
// 淡入阶段
double progress = (double) (elapsed - fadeOutDuration) / fadeInDuration;
drawFadeTransition(progress, false);
} else {
// 动画完成
drawCurrentPage(null);
isTransitioning = false;
stop();
}
}
};
animationTimer.start();
}
/**
* 绘制淡出淡入过渡
*/
private void drawFadeTransition(double progress, boolean fadeOut) {
GraphicsContext gc = canvas.getGraphicsContext2D();
double canvasWidth = canvas.getWidth();
double canvasHeight = canvas.getHeight();
final double PAGE_WIDTH = 1024;
final double PAGE_HEIGHT = 768;
double scaleX = canvasWidth / PAGE_WIDTH;
double scaleY = canvasHeight / PAGE_HEIGHT;
double scale = Math.min(scaleX, scaleY);
double scaledWidth = PAGE_WIDTH * scale;
double scaledHeight = PAGE_HEIGHT * scale;
double offsetX = (canvasWidth - scaledWidth) / 2;
double offsetY = (canvasHeight - scaledHeight) / 2;
if (fadeOut) {
// 绘制当前页面并淡出
drawCurrentPage(null);
gc.setFill(Color.BLACK.interpolate(Color.TRANSPARENT, 1 - progress));
gc.fillRect(0, 0, canvasWidth, canvasHeight);
} else {
// 绘制黑屏并淡入下一页
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, canvasWidth, canvasHeight);
gc.setFill(Color.WHITE);
gc.fillRect(offsetX, offsetY, scaledWidth, scaledHeight);
gc.save();
gc.translate(offsetX, offsetY);
gc.scale(scale, scale);
SlidePage page = slide.getPages().get(currentPageIndex);
for (DrawableObject obj : page.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
// 淡入效果
gc.setFill(Color.color(1, 1, 1, 1 - progress));
gc.fillRect(0, 0, canvasWidth, canvasHeight);
}
}
/**
* 推送动画
*/
private void playPushTransition(double offsetX, double offsetY) {
int duration = currentTransition.getDuration();
AnimationTimer animationTimer = new AnimationTimer() {
private long startTime = System.currentTimeMillis();
@Override
public void handle(long now) {
long elapsed = System.currentTimeMillis() - startTime;
if (elapsed < duration) {
double progress = (double) elapsed / duration;
drawPushTransition(progress, offsetX, offsetY);
} else {
drawCurrentPage(null);
isTransitioning = false;
stop();
}
}
};
animationTimer.start();
}
/**
* 绘制推送过渡
*/
private void drawPushTransition(double progress, double offsetX, double offsetY) {
GraphicsContext gc = canvas.getGraphicsContext2D();
double canvasWidth = canvas.getWidth();
double canvasHeight = canvas.getHeight();
final double PAGE_WIDTH = 1024;
final double PAGE_HEIGHT = 768;
double scaleX = canvasWidth / PAGE_WIDTH;
double scaleY = canvasHeight / PAGE_HEIGHT;
double scale = Math.min(scaleX, scaleY);
double scaledWidth = PAGE_WIDTH * scale;
double scaledHeight = PAGE_HEIGHT * scale;
double centerOffsetX = (canvasWidth - scaledWidth) / 2;
double centerOffsetY = (canvasHeight - scaledHeight) / 2;
// 清空背景
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, canvasWidth, canvasHeight);
// 获取前一页索引(确保有效)
int prevPageIndex = currentPageIndex - 1;
if (prevPageIndex < 0) {
prevPageIndex = slide.getPages().size() - 1; // 循环到最后一页
}
// 绘制旧页面
SlidePage prevPage = slide.getPages().get(prevPageIndex);
double slideOffsetX = offsetX * progress;
double slideOffsetY = offsetY * progress;
gc.save();
gc.translate(centerOffsetX + slideOffsetX, centerOffsetY + slideOffsetY);
gc.scale(scale, scale);
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
for (DrawableObject obj : prevPage.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
// 绘制新页面推入
SlidePage newPage = slide.getPages().get(currentPageIndex);
double newPageOffsetX = centerOffsetX - offsetX * (1 - progress);
double newPageOffsetY = centerOffsetY - offsetY * (1 - progress);
gc.save();
gc.translate(newPageOffsetX, newPageOffsetY);
gc.scale(scale, scale);
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
}
/**
* 缩放动画
*/
private void playZoomTransition(double startScale, double endScale) {
int duration = currentTransition.getDuration();
AnimationTimer animationTimer = new AnimationTimer() {
private long startTime = System.currentTimeMillis();
@Override
public void handle(long now) {
long elapsed = System.currentTimeMillis() - startTime;
if (elapsed < duration) {
double progress = (double) elapsed / duration;
double currentScale = startScale + (endScale - startScale) * progress;
drawZoomTransition(currentScale, progress);
} else {
drawCurrentPage(null);
isTransitioning = false;
stop();
}
}
};
animationTimer.start();
}
/**
* 绘制缩放过渡
*/
private void drawZoomTransition(double zoomScale, double progress) {
GraphicsContext gc = canvas.getGraphicsContext2D();
double canvasWidth = canvas.getWidth();
double canvasHeight = canvas.getHeight();
final double PAGE_WIDTH = 1024;
final double PAGE_HEIGHT = 768;
double scaleX = canvasWidth / PAGE_WIDTH;
double scaleY = canvasHeight / PAGE_HEIGHT;
double scale = Math.min(scaleX, scaleY);
double scaledWidth = PAGE_WIDTH * scale;
double scaledHeight = PAGE_HEIGHT * scale;
double offsetX = (canvasWidth - scaledWidth) / 2;
double offsetY = (canvasHeight - scaledHeight) / 2;
// 清空背景
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, canvasWidth, canvasHeight);
// 获取前一页索引(确保有效)
int prevPageIndex = currentPageIndex - 1;
if (prevPageIndex < 0) {
prevPageIndex = slide.getPages().size() - 1; // 循环到最后一页
}
// 绘制旧页面,逐渐缩小
SlidePage prevPage = slide.getPages().get(prevPageIndex);
double oldPageScale = scale * (1 - progress * 0.3); // 缩小30%
double oldPageWidth = PAGE_WIDTH * oldPageScale;
double oldPageHeight = PAGE_HEIGHT * oldPageScale;
double oldPageOffsetX = (canvasWidth - oldPageWidth) / 2;
double oldPageOffsetY = (canvasHeight - oldPageHeight) / 2;
gc.save();
gc.translate(oldPageOffsetX, oldPageOffsetY);
gc.scale(oldPageScale / scale, oldPageScale / scale);
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
for (DrawableObject obj : prevPage.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
// 绘制新页面,逐渐放大
SlidePage newPage = slide.getPages().get(currentPageIndex);
double newPageScale = scale * (0.7 + progress * 0.3); // 从70%放大到100%
double newPageWidth = PAGE_WIDTH * newPageScale;
double newPageHeight = PAGE_HEIGHT * newPageScale;
double newPageOffsetX = (canvasWidth - newPageWidth) / 2;
double newPageOffsetY = (canvasHeight - newPageHeight) / 2;
gc.save();
gc.translate(newPageOffsetX, newPageOffsetY);
gc.scale(newPageScale / scale, newPageScale / scale);
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
}
/**
* 旋转动画
*/
private void playRotateTransition() {
int duration = currentTransition.getDuration();
AnimationTimer animationTimer = new AnimationTimer() {
private long startTime = System.currentTimeMillis();
@Override
public void handle(long now) {
long elapsed = System.currentTimeMillis() - startTime;
if (elapsed < duration) {
double progress = (double) elapsed / duration;
double rotation = progress * 360; // 360度旋转
drawRotateTransition(rotation, progress);
} else {
drawCurrentPage(null);
isTransitioning = false;
stop();
}
}
};
animationTimer.start();
}
/**
* 绘制旋转过渡
*/
private void drawRotateTransition(double rotation, double progress) {
GraphicsContext gc = canvas.getGraphicsContext2D();
double canvasWidth = canvas.getWidth();
double canvasHeight = canvas.getHeight();
final double PAGE_WIDTH = 1024;
final double PAGE_HEIGHT = 768;
double scaleX = canvasWidth / PAGE_WIDTH;
double scaleY = canvasHeight / PAGE_HEIGHT;
double scale = Math.min(scaleX, scaleY);
double scaledWidth = PAGE_WIDTH * scale;
double scaledHeight = PAGE_HEIGHT * scale;
double offsetX = (canvasWidth - scaledWidth) / 2;
double offsetY = (canvasHeight - scaledHeight) / 2;
// 清空背景
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, canvasWidth, canvasHeight);
// 绘制旋转的页面
SlidePage newPage = slide.getPages().get(currentPageIndex);
gc.save();
// 移到中心,旋转,再移回
double centerX = offsetX + scaledWidth / 2;
double centerY = offsetY + scaledHeight / 2;
gc.translate(centerX, centerY);
gc.rotate(rotation);
gc.translate(-scaledWidth / 2, -scaledHeight / 2);
gc.scale(scale, scale);
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
}
/**
* 绘制当前页面
*/
private void drawCurrentPage(Animation animation) {
if (currentPageIndex < 0 || currentPageIndex >= slide.getPages().size()) {
return;
}
GraphicsContext gc = canvas.getGraphicsContext2D();
double canvasWidth = canvas.getWidth();
double canvasHeight = canvas.getHeight();
// 页面标准宽高比
final double PAGE_WIDTH = 1024;
final double PAGE_HEIGHT = 768;
// 计算缩放因子,保持宽高比
double scaleX = canvasWidth / PAGE_WIDTH;
double scaleY = canvasHeight / PAGE_HEIGHT;
double scale = Math.min(scaleX, scaleY);
// 计算内容区域的实际宽高
double scaledWidth = PAGE_WIDTH * scale;
double scaledHeight = PAGE_HEIGHT * scale;
// 计算居中偏移
double offsetX = (canvasWidth - scaledWidth) / 2;
double offsetY = (canvasHeight - scaledHeight) / 2;
// 清空背景(黑色)
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, canvasWidth, canvasHeight);
// 白色背景区域
gc.setFill(Color.WHITE);
gc.fillRect(offsetX, offsetY, scaledWidth, scaledHeight);
SlidePage page = slide.getPages().get(currentPageIndex);
// 保存绘图上下文
gc.save();
// 应用缩放和平移变换
gc.translate(offsetX, offsetY);
gc.scale(scale, scale);
// 绘制所有对象
for (DrawableObject obj : page.getPageContent().getDrawableObjects()) {
drawObject(gc, obj);
}
gc.restore();
// 绘制页码(不受缩放影响)
drawPageNumber(gc, canvasWidth, canvasHeight);
}
/**
* 绘制单个对象
*/
private void drawObject(GraphicsContext gc, DrawableObject obj) {
if (obj instanceof TextObject) {
drawTextObject(gc, (TextObject) obj);
} else if (obj instanceof ShapeObject) {
drawShapeObject(gc, (ShapeObject) obj);
} else if (obj instanceof ImageObject) {
drawImageObject(gc, (ImageObject) obj);
}
}
/**
* 绘制文本对象
*/
private void drawTextObject(GraphicsContext gc, TextObject textObj) {
gc.setFill(textObj.getTextColorAsColor());
gc.setFont(new javafx.scene.text.Font(textObj.getFontFamily(), textObj.getFontSize()));
double lineHeight = textObj.getFontSize() * 1.2;
double currentY = textObj.getY();
for (String line : textObj.getLayoutLines()) {
currentY += lineHeight;
gc.fillText(line, textObj.getX() + 5, currentY);
}
}
/**
* 绘制形状对象
*/
private void drawShapeObject(GraphicsContext gc, ShapeObject shapeObj) {
gc.setFill(Color.web("#" + shapeObj.getFillColor()));
gc.setStroke(Color.web("#" + shapeObj.getStrokeColor()));
gc.setLineWidth(shapeObj.getStrokeWidth());
switch (shapeObj.getShapeType()) {
case RECTANGLE:
gc.fillRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
gc.strokeRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
break;
case CIRCLE:
double radius = Math.min(shapeObj.getWidth(), shapeObj.getHeight()) / 2;
gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
break;
case ELLIPSE:
gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
break;
case LINE:
gc.strokeLine(shapeObj.getX(), shapeObj.getY(),
shapeObj.getX() + shapeObj.getWidth(), shapeObj.getY() + shapeObj.getHeight());
break;
}
}
/**
* 绘制图片对象
*/
private void drawImageObject(GraphicsContext gc, ImageObject imgObj) {
try {
javafx.scene.image.Image image = new javafx.scene.image.Image("file:" + imgObj.getImagePath());
gc.drawImage(image, imgObj.getX(), imgObj.getY(), imgObj.getWidth(), imgObj.getHeight());
} catch (Exception e) {
// 图片加载失败,显示占位符
gc.setFill(Color.LIGHTGRAY);
gc.fillRect(imgObj.getX(), imgObj.getY(), imgObj.getWidth(), imgObj.getHeight());
gc.setFill(Color.BLACK);
gc.fillText("图片加载失败", imgObj.getX() + 10, imgObj.getY() + 20);
}
}
/**
* 绘制页码(不受缩放影响)
*/
private void drawPageNumber(GraphicsContext gc, double canvasWidth, double canvasHeight) {
gc.setFill(Color.BLACK);
gc.setFont(new javafx.scene.text.Font(16));
String pageNum = String.format("%d / %d", currentPageIndex + 1, slide.getPages().size());
gc.fillText(pageNum, canvasWidth - 100, canvasHeight - 20);
}
/**
* 设置翻页动画
*/
public void setTransitionEffect(TransitionEffect effect) {
this.currentTransition = effect;
}
/**
* 退出演示
*/
private void exitPresentation() {
stage.close();
}
/**
* 获取舞台
*/
public Stage getStage() {
return stage;
}
}
@@ -0,0 +1,68 @@
package dev.bytevibe.hyperpoint;
/**
* 演示/播放模式下支持的翻页动画效果
*/
public enum TransitionEffect {
/**
* 无动画,直接切换
*/
NONE("无动画", 0),
/**
* 淡出/淡入效果
*/
FADE("淡出淡入", 500),
/**
* 从右向左推送效果
*/
PUSH_LEFT("从右推入", 400),
/**
* 从左向右推送效果
*/
PUSH_RIGHT("从左推入", 400),
/**
* 从上向下推送效果
*/
PUSH_DOWN("从上推入", 400),
/**
* 从下向上推送效果
*/
PUSH_UP("从下推入", 400),
/**
* 缩放效果 - 从小到大
*/
ZOOM_IN("缩放放大", 500),
/**
* 缩放效果 - 从大到小
*/
ZOOM_OUT("缩放缩小", 500),
/**
* 旋转效果
*/
ROTATE("旋转翻页", 600);
private final String displayName;
private final int duration; // 毫秒
TransitionEffect(String displayName, int duration) {
this.displayName = displayName;
this.duration = duration;
}
public String getDisplayName() {
return displayName;
}
public int getDuration() {
return duration;
}
}
@@ -47,6 +47,18 @@
</items> </items>
</MenuButton> </MenuButton>
<!-- 演示菜单 -->
<MenuButton mnemonicParsing="false" text="演示">
<items>
<MenuItem mnemonicParsing="false" onAction="#onStartPresentation" text="开始演示(F5)" />
<MenuItem mnemonicParsing="false" onAction="#onPresentationWithFade" text="淡出淡入效果演示" />
<MenuItem mnemonicParsing="false" onAction="#onPresentationWithPushLeft" text="从右推入效果演示" />
<MenuItem mnemonicParsing="false" onAction="#onPresentationWithPushRight" text="从左推入效果演示" />
<MenuItem mnemonicParsing="false" onAction="#onPresentationWithZoomIn" text="缩放放大效果演示" />
<MenuItem mnemonicParsing="false" onAction="#onPresentationWithRotate" text="旋转翻页效果演示" />
</items>
</MenuButton>
<Label text=" | " /> <Label text=" | " />
<!-- 退出菜单 --> <!-- 退出菜单 -->