Одна из проблем, с которой мне пришлось столкнуться пару лет назад, заключалась в переносе настольного приложения Java с 32-разрядной на 64-разрядную архитектуру, и то, что могло быть таким простым, как использование правильного JDK, переключение на соответствующие версии внешних библиотек и избавление от устаревшего кода, на самом деле имело дополнительную проблему. Приложение встроило 32-разрядный PDF-ридер на панель, и это ограничение некоторое время останавливало эту миграцию.
Одна из проблем, с которой мне пришлось столкнуться пару лет назад, заключалась в переносе настольного приложения Java с 32-разрядной на 64-разрядную архитектуру, и то, что могло быть таким простым, как использование правильного JDK, переключение на соответствующие версии внешних библиотек и избавление от устаревшего кода, на самом деле имело дополнительную проблему. Приложение встроило 32-разрядный PDF-ридер на панель, и это ограничение некоторое время останавливало эту миграцию.
Переходя к самому коду, он использовал XULRunner, один из компонентов движка Firefox, так что на самом деле он делал “с использованием встроенного 32-разрядного браузера Firefox”. Он также использовал интерактивные формы, созданные Adobe Acrobat, которые фактически требовали правильного отображения самого Adobe Acrobat Reader, и для выполнения этой задачи Apache PDFBox не использовался.
Когда я изучил философию запуска встроенного браузера, я попытался использовать то, что произошло на моем ноутбуке: когда я занимался серфингом в Сети и открывал PDF-файл в своем 32-разрядном браузере Firefox, я не использовал какой-либо код браузера: я делегировал это в плагин Adobe Acrobat Reader X для браузера. Итак, почему бы нам не продвинуть эту идею еще на один шаг и не использовать тот же плагин через интеграцию? Сама Adobe предоставляет эту систему, поэтому проблем с несовместимостью не возникнет, мне просто нужно было настроить это с помощью конфигурации операционной системы, чтобы найти обходной путь и получить подходящую версию для архитектуры компьютера, в которой мы в настоящее время запускаем программу.
Итак, давайте познакомимся с DJNativeSwing, библиотекой, основанной на SWT (Standard Widget Toolkit), которая позволяет нам иметь наш собственный встроенный браузер в нашем коде. SWT – это настоятельно рекомендуемая библиотека из-за ее переносимости, поскольку она имеет доступ к графическим интерфейсам собственной операционной системы, и это именно то, что нам требуется для такого рода проблем. Это также следующий уровень упаковки для Java Swing, и на самом деле он легче и быстрее, и я уже использовал его в свое время, чтобы избежать проблем, когда мне приходилось иметь дело с интеграцией плагинов Macromedia Flash.
В качестве примера того, как это настроить, мы собираемся выполнить 2 основных шага:
- Настройте вкладку браузера в компоненте Java swing.
- Иметь возможность открывать PDF-файл на указанной вкладке браузера.
1. Предыдущая настройка: требуемые зависимости Maven
Давайте начнем с основ: прежде всего мы получим зависимости maven.
❕ Это была стабильная версия, когда сообщение было первоначально написано.
chrriis.dj.nativeswing DJNativeSwing 1.0.2
2. Создание базового интерфейса Swing
Сразу после этого мы определим базовую рамку окна с кнопкой выбора файла (через FileChooser) и панелью для отображения результатов.
❕ Настройка всех текстовых строк в качестве констант облегчает их поиск, чтобы при необходимости заменить. На самом деле в этом нет необходимости, но это улучшает возможность повторного использования.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Map;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
import nativeSwing.BrowserPanel;
import pdfHandler.PdfReader;
import xmlHandler.XMLHandler;
import chrriis.common.UIUtils;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;
public class DemoPDFRenderLauncher {
private static final String TITLE = "PDF Renderer demo";
private static final String NO_OUTPUT_MESSAGE = "No output available";
private static final String NO_DATA_MESSAGE = "There is no data available from form";
private static final int LENGTH = 800;
private static final int WIDTH = 600;
private static final String FILTER_FILES "PDF files";
private static final String FILE_EXTENSION "pdf";
/**
* The main app window
*/
private JFrame window;
/**
* The path of the file we will open
*/
private String path;
/**
* Button for open file function
*/
private JButton buttonOpen;
/**
* A browser panel
*/
private BrowserPanel browserPanel;
/**
* Constructor method, creates the GUI
*/
public Launcher() {
window = new JFrame(TITLE);
window.getContentPane().setLayout(new BorderLayout());
window.setSize(LENGTH, WIDTH);
window.add(createButtonsPanel(), BorderLayout.NORTH);
window.add(createContentPanel(), BorderLayout.CENTER);
window.setVisible(true);
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
NativeInterface.close();
System.exit(0);
}
});
}
/**
* Creates a button panel with the action button: open a file
* @return the buttons panel
*/
private Component createButtonsPanel() {
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
buttonOpen = new JButton("Open file");
buttonOpen.addActionListener(new ButtonOpenController());
panel.add(buttonOpen);
return panel;
}
/**
* Creates a panel to render the content
*
* @return the buttons panel
*/
private Component createContentPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JScrollPane scrollPaneText = new JScrollPane(textPanel);
panel.add(scrollPaneText);
//here we will insert the DJNativeSwing panle
browserPanel = new BrowserPanel();
JScrollPane scrollPaneBrowser = new JScrollPane(browserPanel);
panel.add(scrollPaneBrowser);
return panel;
}
/**
* Load button controller, which launches the FileChooser.
*/
private class ButtonOpenController implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
launchOpenSelectFile();
}
}
/**
* Launches the FileChooser window, and invokes the pdf opener window.
*/
private void launchOpenSelectFile() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setAcceptAllFileFilterUsed(false);
FileNameExtensionFilter filter = new FileNameExtensionFilter(
FILTER_FILES, FILE_EXTENSION);
fileChooser.addChoosableFileFilter(filter);
if (fileChooser.showOpenDialog(window) == JFileChooser.APPROVE_OPTION) {
path = fileChooser.getSelectedFile().getAbsolutePath();
browserPanel.navigate(path);
}
}
@SuppressWarnings("unused")
public static void main(String[] args) {
UIUtils.setPreferredLookAndFeel();
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Launcher demo = new Launcher();
}
});
}
}
3. Встраивание веб-браузера
Затем давайте перейдем к вкладке браузера: если бы мы просто хотели создать панель браузера, это было бы так же просто, как написать следующие строки:
import java.awt.BorderLayout;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;
public class BasicBrowserPanel extends JPanel {
private static final String TITLE = "";
/**
* The browser will be handled in this specific component
*/
private JWebBrowser webBrowser;
/**
* Constructor
*/
public BrowserPanel() {
super(new BorderLayout());
JPanel webBrowserPanel = new JPanel(new BorderLayout());
webBrowserPanel.setBorder(BorderFactory.createTitledBorder(TITLE));
webBrowser = new JWebBrowser();
webBrowser.setBarsVisible(false);
webBrowser.setStatusBarVisible(false);
webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
add(webBrowserPanel, BorderLayout.CENTER);
}
/**
* Initializes the browser and sets a value in the URL storage
* @param path the URL value o file path to open
*/
public void navigate(String path) {
webBrowser.setVisible(true);
webBrowser.navigate(path);
}
/**
* Makes the browser retrieve and render the content from the path previously stored
*/
public String getAddress(){
return webBrowser.getHTMLContent();
}
/**
* Hides the browser controls (forward, back, home buttons...)
*/
public void hideContent() {
webBrowser.setVisible(false);
}
}
Таким образом, мы получаем полнофункциональный веб-браузер, очень похожий на браузер в Eclipse IDE, но со слишком большим количеством ненужных функций для того, что мы пытаемся здесь сделать. Поскольку мы выполняем процесс рендеринга только путем делегирования его в Adobe, мы можем удалить дополнительные элементы графического интерфейса из всей этой пользовательской системы просмотра и оставить пустую панель.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;
/**
* Allows to launch a JFrame containing an embedded browser.
*/
public class BrowserFrameLauncher {
/**
* Renders the file content on a browser via DJ Native Swing
*
* @param path
* the file url if we pass as a parameter any webpage URL,
* the system would try to render it
* @return a JPanel with a native browser, to render the file content
*/
private Component createBrowserPanel(String path) {
JWebBrowser.useXULRunnerRuntime();
JPanel fileBrowserPanel = new JPanel(new BorderLayout());
final JWebBrowser fileBrowser = new JWebBrowser();
fileBrowser.setBarsVisible(false);
fileBrowser.setStatusBarVisible(false);
fileBrowser.navigate(path);
fileBrowserPanel.add(fileBrowser, BorderLayout.CENTER);
return fileBrowserPanel;
}
}
4. Установка последнего фрагмента головоломки: получение самого PDF-файла
Наконец, давайте внесем последние штрихи, чтобы открыть PDF-файл. Что мы на самом деле делаем, так это вводим путь к файлу PDF в браузер, так что в итоге у нас есть новый слой поверх нашего старого друга XULRunner, но это дает нам возможность интегрировать плагины с помощью библиотеки SWT “right architecture version”. Итак, в заключение мы можем подключиться к плагину “правильная версия архитектуры”, устраняя нашу проблему с рендерингом и делая нас независимыми от 32-битной plaform раз и навсегда.
// excerpt from BrowserFrameLauncherPDF.java
private static final String CLOSING_MESSAGE = "Do you really want to close the file?";
private static final String RENDERED_TITLE = "PDF Renderer demo - Embed Browser";
/**
* Opens a file and shows it content in a JFrame.
*
* @param path
* the url of the file to open in a JFrame
*/
public static void openPDF(final String path) {
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame frame = new JFrame(RENDERED_TITLE);
frame.setLocation(0, 0);
//we may set up a default size for this test
//frame.setSize(800, 600);
frame.setVisible(true);
frame.add(createBrowserPanel(path));
//a window listener would allow us to control the closing actions
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
int i = JOptionPane.showConfirmDialog(frame,CLOSING_MESSAGE);
if (i == 0) {
NativeInterface.close();
}
}
});
}
});
}
❗ ️ Пожалуйста, обратите внимание на строку NativeInterface.open(), чтобы убедиться в правильной загрузке компонентов, и потоковую обработку этого компонента, чтобы избежать вмешательства других процессов в рендеринг.
Оригинал: “https://dev.to/angelesbroullon/browser-integration-in-java-guis-2nnm”