В PowerPoint
презентации мастер назван так, как его тема. Мы можем получить все мастера, используя XMLSlideShow.getSlideMasters . XSLFSlideMaster
расширяется XSLFSheet
. Таким образом, мы можем получить тему каждого мастера, используя XSLFSheet.getTheme . Как только у нас есть XSLFTheme , для имени появляются геттеры и сеттеры.
Пример:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xslf.usermodel.*;
public class XSLFRenameMasterTheme {
public static void main(String[] args) throws Exception {
XMLSlideShow slideshow = new XMLSlideShow(new FileInputStream("Presentation.pptx"));
for (XSLFSlideMaster master : slideshow.getSlideMasters()) {
XSLFTheme theme = master.getTheme();
String name = theme.getName();
System.out.println(name);
theme.setName(name + " renamed");
System.out.println(theme.getName());
}
FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.pptx");
slideshow.write(out);
out.close();
slideshow.close();
}
}
Для HSLFSlideShow
кажется, что нет доступа к поддерживаемым именам мастеров. Можно получить HSLFSlideMaster с, но не их имена.
Так что, если, тем не менее, нужно это сделать, то нужно знать о внутренностях двоичной файловой системы *.ppt
. Это описано в [MS-PPT]: формат двоичных файлов PowerPoint (.ppt) . Имена листов находятся в SlideNameAtom . Обладая знаниями о внутренностях, можно создать класс для такой записи. Это может обеспечить методы для получения и установки имени.
Пример:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordAtom;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
public class HSLFRenameMaster {
// method for get SlideNameAtom out of the master
private static SlideNameAtom getSlideNameAtom(HSLFSlideMaster master) throws Exception {
SlideNameAtom slideNameAtomRecord = null;
Record record = master.getSheetContainer().findFirstOfType(0x0FBA);
if (record != null) { // SlideNameAtom exists
// get present data
ByteArrayOutputStream out = new ByteArrayOutputStream();
record.writeOut(out);
out.flush();
byte[] data = out.toByteArray();
out.close();
// create new SlideNameAtom from data
slideNameAtomRecord = new SlideNameAtom(data);
// replace old record with new SlideNameAtom
master.getSheetContainer().addChildBefore(
slideNameAtomRecord,
record
);
master.getSheetContainer().removeChild(record);
}
return slideNameAtomRecord;
}
public static void main(String[] args) throws Exception {
HSLFSlideShow slideshow = new HSLFSlideShow(new FileInputStream("Presentation.ppt"));
for (HSLFSlideMaster master : slideshow.getSlideMasters()) {
SlideNameAtom slideNameAtomRecord = getSlideNameAtom(master);
if (slideNameAtomRecord != null) {
String name = slideNameAtomRecord.getName();
System.out.println(name);
slideNameAtomRecord.setName(name + " renamed");
System.out.println(slideNameAtomRecord.getName());
}
}
FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.ppt");
slideshow.write(out);
out.close();
slideshow.close();
}
//class SlideNameAtom
//having methods for manipulating the [SlideNameAtom](https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx)
private static class SlideNameAtom extends RecordAtom {
private byte[] data;
private String name;
public SlideNameAtom() {
this.name = "Office";
setName(name);
}
public SlideNameAtom(byte[] data) {
this.data = data;
this.name = getName();
}
public void setName(String name) {
this.name = name;
int length = 8;
length += StringUtil.getToUnicodeLE(name).length;
this.data = new byte[length];
data[0] = (byte)0x20; data[1] = (byte)0x00;
data[2] = (byte)0xBA; data[3] = (byte)0x0F; //MUST be 0x0fba = RT_CString (little endian)
LittleEndian.putInt(data, 4, StringUtil.getToUnicodeLE(name).length);
StringUtil.putUnicodeLE(name, data, 8);
}
public String getName() {
return StringUtil.getFromUnicodeLE(this.data, 8, (this.data.length-8)/2);
}
@Override
public void writeOut(OutputStream out) throws IOException {
out.write(data);
}
@Override
public long getRecordType() { return 0x0FBA; }
}
}
Вопрос в том, стоит ли переименование мастера.
Проблема состоит в том, что Вашей новой Панелью Расположения является WrapPanel, и это не поддерживает Виртуализацию! Возможно создать Ваш собственный Виртуализированный WrapPanel... Читайте больше здесь
Также считайте больше о других проблемах как реализация IScrollInfo здесь
Я также настоятельно рекомендую, чтобы Ваш не создавали новый шаблон управления только для замены панели расположения... Скорее сделайте следующее:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
Преимущество выполнения этого состоит в том, что Вы не должны переносить свое поле списка в scrollviewer!
[ОБНОВЛЕНИЕ] Также прочитало эту статью Josh Smith! Чтобы заставить WrapPanel перенести... Вас также должны не забыть отключать горизонтальную прокрутку...
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
попытайтесь виртуализировать свой stackpael с VirtualizingStackPanel. IsVirtualizing = "Истинное" приложенное свойство. это должно увеличить производительность.
использование поля списка со многими объектами в scrollviewer является другой известной проблемой производительности в wpf., если Вы можете, попытаться избавиться от scrollviewer.
если Ваши itemtemplates являются видом комплекса, необходимо рассмотреть использование Переработки VirtualizationMode., это говорит полю списка снова использовать существующие объекты и не создавать новые все время.
Часть проблемы - то, что она загружает полный образ в каждом. Необходимо использовать IValueConverter
открыть каждое изображение в размере миниатюры путем установки любого DecodePixelWidth
или DecodePixelHeight
свойства на BitmapImage
. Вот пример, который я использую в одном из моих проектов...
class PathToThumbnailConverter : IValueConverter {
public int DecodeWidth {
get;
set;
}
public PathToThumbnailConverter() {
DecodeWidth = 200;
}
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
var path = value as string;
if ( !string.IsNullOrEmpty( path ) ) {
FileInfo info = new FileInfo( path );
if ( info.Exists && info.Length > 0 ) {
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = DecodeWidth;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri( info.FullName );
bi.EndInit();
return bi;
}
}
return null;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
throw new NotImplementedException();
}
}
Я рекомендовал бы не связать свойство Width/Height каждого отдельного изображения, а скорее Вы связываете LayoutTransform на ItemsPanel ListBox. Что-то как:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel>
<StackPanel.LayoutTransform>
<ScaleTransform
ScaleX="{Binding Path=Value, ElementName=ZoomSlider}"
ScaleY="{Binding Path=Value, ElementName=ZoomSlider}" />
</StackPanel.LayoutTransform>
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
На что похож Ваш стиль PhotoListBoxStyle? Если это изменяет ItemsPanelTemplate ListBox затем существует хороший шанс, Ваш ListBox не использует VirtualizingStackPanel в качестве своей базовой панели списка. Невиртуализированные ListBoxes намного медленнее со многими объектами.
Я не знаком с этим компонентом, но в целом там будет ограничениями на количество объектов, которые поле списка может отобразить когда-то.
Метод для решения этого вида проблемы должен сохранить количество изображений загруженным в управлении в числе, которое управление может отобразить на приемлемых уровнях производительности. Два метода, чтобы сделать это - подкачка страниц или динамическая загрузка.
В подкачке страниц Вы добавляете средства управления для переключения между дискретными блоками изображений, например, 100 за один раз, с вперед и стрелки назад, подобные перешедшим записям базы данных.
С динамической загрузкой Вы реализуете подкачку страниц негласно таким способом, которым, когда пользователь прокручивает в конец, приложение автоматически загружается в следующем пакете изображений и потенциально даже удаляет пакет старых для хранения скорости отклика разумной. Может быть маленькая пауза, поскольку это происходит и может быть некоторая работа, включенная для удержания контроль в надлежащей точке прокрутки, но это может быть приемлемым компромиссом.