Wie kann man den Inhalt einer JTable
zu
LibreOffice-Writer in das ODT-Format exportieren?
Vorbereitung
Um die Bibliothek nutzen zu können, muss sie zunächst unter https://odftoolkit.org/downloads.html heruntergeladen und dem Classpath hinzugefügt werden. Das Paket enthält eine Reihe *.jar-Archive, von denen für das vorliegende Beispiel die folgenden Verwendung finden und eingebunden werden müssen:
- odfdom-xxx.jar
- simpleodf-xxx.jar
- serializer.jar
- resolver.jar
- xercesImpl.jar
Das GUI
Die Beispielklasse zeigt ein
einfaches Fenster, in dem eine JTable
und darunter
ein JButton
zu sehen sind. Das GUI wird in der im
Konstruktor aufgerufenen Methode initGUI()
erzeugt.
Die Aktivität des Buttons ruft die Methode expToODT()
auf, die für den Export der gezeigten Tabelle in eine *.odt
-Datei
verantwortlich zeichnet.
In initGUI()
werden zunächst zwei
String-Arrays für die Bezeichnungen der Spaltenköpfe
und den Inhalt der Tabelle erzeugt. Sie werden dem Konstruktor
eines DefaultTableModel
übergeben, das
wiederum anschließend bei der Instanzierung der JTable
Verwendung findet.
Nach der Erzeugung wird die Tabelle etwas
formatiert, indem eine Hintergrundfarbe angegeben und die
Sichtbarkeit des Tabellenrasters gesetzt werden. Durch setAutoCreateRowSorter(true)
wird zudem sichergestellt, dass durch Klick auf die
Spaltenköpfe eine einfache Sortierung ermöglicht wird.
Nachdem
die Tabelle dem Frame hinzugefügt wurde, wird der Button
erzeugt, bei einem ActionListener
angemeldet und
ebenfalls unten in das GUI eingefügt. Wie oben erwähnt
wird bei seiner Betätigung expToODT()
aufgerufen. Der Methode wird der String
des Namens
der Datei übergeben, in die der Export erfolgen soll.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.DateFormat;
import java.util.GregorianCalendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import org.odftoolkit.simple.TextDocument;
import org.odftoolkit.simple.style.DefaultStyleHandler;
import org.odftoolkit.simple.style.Font;
import org.odftoolkit.simple.style.StyleTypeDefinitions.FontStyle;
import org.odftoolkit.simple.style.StyleTypeDefinitions.HorizontalAlignmentType;
import org.odftoolkit.simple.table.Cell;
import org.odftoolkit.simple.table.Table;
import org.odftoolkit.simple.text.Paragraph;
public class JTableToODT {
private JTable table;
private Object[] head;
private String exportFile = "Tabelle.odt";
public JTableToODT() {
initGUI();
}
private void initGUI() {
head = new Object[]{ "eins", "zwei", "drei", "vier", "f\u00FCnf" };
Object[][] content = new Object[20][5];
for (int i = 0; i < content.length; i++) {
for (int j = 0; j < content[i].length; j++) {
content[i][j] = (i + 1) + "." + (j + 1);
}
}
DefaultTableModel model = new DefaultTableModel(content, head);
table = new JTable(model);
table.setShowGrid(true);
table.setAutoCreateRowSorter(true);
table.setBackground(Color.LIGHT_GRAY);
JFrame frame = new JFrame("Tabelle zu ODT");
frame.add(new JScrollPane(table), BorderLayout.CENTER);
JButton butt = new JButton("Export");
butt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
expToODT(exportFile);
}
});
frame.add(butt, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void expToODT(final String fileName) {
final DefaultTableModel model = (DefaultTableModel) table.getModel();
final int clmCnt = table.getColumnCount();
final int rowCnt = table.getRowCount();
Thread t = new Thread() {
@Override
public void run() {
TextDocument outputOdt = null;
try {
outputOdt = TextDocument.newTextDocument();
// Header
Paragraph para = Paragraph.newParagraph(outputOdt);
para.applyHeading();
DateFormat df = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.SHORT);
para.setTextContent("Testtabelle - "
+ df.format(new GregorianCalendar().getTime()));
outputOdt.getParagraphByIndex(0, false).remove();
// Tabelle
Table table = outputOdt.addTable(rowCnt + 1, clmCnt);
Cell cell;
Object value;
DefaultStyleHandler styleHandler;
Font normal = new Font("Helvetica", FontStyle.REGULAR, 8);
Font header = new Font("Helvetica", FontStyle.BOLD, 9);
for (int i = 0; i <= rowCnt; i++) {
for (int j = 0; j < clmCnt; j++) {
cell = table.getCellByPosition(j, i);
styleHandler = cell.getStyleHandler();
if (i == 0) {
styleHandler.getTextPropertiesForWrite()
.setFont(header);
cell.setStringValue(head[j].toString());
} else {
value = model.getValueAt(
JTableToODT.this.table
.convertRowIndexToModel(i - 1),
j);
cell.setHorizontalAlignment(
HorizontalAlignmentType.LEFT);
styleHandler.getTextPropertiesForWrite()
.setFont(normal);
cell.setStringValue(
value == null ? "" : value.toString());
}
}
}
outputOdt.save(fileName);
String message = "";
if(new File(fileName).exists()) {
message = " wurde erstellt";
} else {
message = " konnte nicht erstellt werden";
}
JOptionPane.showMessageDialog(null, fileName + message);
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new JTableToODT());
}
}
Export im Open Document Format
Die Erzeugung eines Dokumentes im Open
Document Format, das Einfügen des Inhaltes und das
Abspeichern in einer *.odt
-Datei findet in der
Methode expToODT()
statt.
Hier wird
zunächst das TableModel geholt, sowie die Anzahl der
Spalten und Reihen der Tabelle ermittelt. Der eigentliche Export
findet dann in einem eigenen Thread statt, um ihn funktional vom
EDT zu entkoppeln. Zudem ist der gesamte Vorgang in einen
try-catch-Block eingeschlossen, um Fehler bei den Erzeugungs-
und Ausgabevorgängen abzufangen.
Als erstes wird nun ein neues Objekt vom Typ org.odftoolkit.simple.TextDocument
erzeugt und diesem ein neuer Absatz (Paragraph
)
angefügt. Er wird als Überschrift erster Ordnung
formatiert und mit Inhalt versehen.
In der Folge wird dann
der erste Absatz ermittelt und gelöscht. Hier muss
angemerkt werden, dass es eigenartigerweise nicht möglich
war, diesen ersten Absatz zu Beginn zu ermitteln und dann sofort
als Überschrift zu formatieren. Die Formatierung wurde bei
diesem Verfahren nicht angenommen.
Paragraph para = outputOdt.getParagraphByIndex(0, false); para.applyHeading(); // hier keine Header-Formatierung
Löscht man hingegen den ersten Absatz nicht, so bleibt ein leerer Absatz vor der Überschrift erhalten.
Um die Tabelle im Dokument zu erzeugen, werden einige Objekte
gebildet. Zentral sind hier die Klassen Table
und Cell
des Package org.odftoolkit.simple.table
sowie org.odftoolkit.simple.style.DefaultStyleHandler
zur Formatierung der Erscheinung des Zelleninhaltes.
Nach der
Erzeugung zweier Font
-Objekte zur Formatierung des
Tabelleninhaltes wird in einer geschachtelten Schleife dann die
Tablelle Zelle für Zelle durchlaufen, das jeweilige Cell
-Objekt
anhand seiner Position in der Tabelle über die Indices
ermittelt und dann bearbeitet. Hierzu wird auch der DefaultStyleHandler
der Zelle benötigt.
Die erste Zeile der Tabelle
enthält den Tabellenkopf. In dessen Zellen werden die
Überschriften der einzelnen Spalten gesetzt und diese mit
einer fetten Schrift formatiert. Alle anderen Zellen erhalten
den Inhalt des DefaultTableModel
.
An dieser Stelle ist ein zentraler Aspekt des Umgangs mit
Tabellen in Java zu erkennen: Da im Sinne des
Model-View-Controller-Patterns der Inhalt und die Erscheinung
einer Tabelle strikt getrennt sind, kann es z.B. nach einer
Sortierung des TabellenGUI vorkommen, dass die Reihenfolge der
Zeilen in der Tabellendarstellung nicht mehr jener im Modell
enspricht. Die Methode convertRowIndexToModel()
der
Klasse JTable
erhält als Parameter den
Zeilenindex der Tabellendarstellung und gibt den Index der
zugehörigen Modellzeile zurück. Dies ist notwendig, um
den der Tabellendarstellung entsprechenden Inhalt der Zelle aus
dem Tabellenmodell zu ermitteln und im Object value
zwischenzuspeichern. Geschähe dies nicht, so bezöge
sich die aktuell ausgelesene Position auf den ursprünglich
an dieser Position gespeicherten Inhalt des Modells.
Die Zelle wird dann linksbündig und mit dem erzeugten Font
-Objekt
formatiert und schließlich der oben aus dem Modell
ermittelte Zellenwert eingefügt.
Nach Durchlauf der
Schleife sind alle Werte übertragen und das Dokument wird
durch save()
gespeichert. Die Methode erzeugt die
benötigte Datei selbsttätig. Sie muss vorher nicht
existieren.
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.