- Интеграция браузера в Java GUI
- 1. Предыдущая настройка: требуемые зависимости Maven
- 2. Создание базового интерфейса Swing
- 3. Встраивание веб-браузера
- 4. Установка последнего фрагмента головоломки: получение самого PDF-файла
- Читайте ещё по теме:
- How to open a URL in the default browser
- Example Java program using the browse method
- But there are more actions
- Java 1.6 Desktop class related
- Also today
- Downloading (opening) a file in a browser
Интеграция браузера в Java GUI
Введение Одной из проблем, с которой мне пришлось столкнуться пару лет назад, была миграция aJa… С тегами java, интеграция, браузер, swt.
Одна из проблем, с которой мне пришлось столкнуться пару лет назад, заключалась в переносе настольного приложения 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(), чтобы убедиться в правильной загрузке компонентов, и потоковую обработку этого компонента, чтобы избежать вмешательства других процессов в рендеринг.
Читайте ещё по теме:
How to open a URL in the default browser
If you ever wondered if there is an easy way to open a URL from your Java program in the user-default browser, with Java SE 6 there is. Unless your platform doesn’t support this. The good news is that you can test if this is the case or not.
In Java SE 6 a new class has been added to the java.awt package: Desktop. This class has a public class method isDesktopSupported() which returns true if the class is supported on the current platform, and false otherwise.
If the class is supported, you can retrieve an instance using the class method getDesktop().
You can use the browse() method to display a URI in the default browser. If this browser is not able to handle the specified URI, the application registered for handling the URIs of the specified type is invoked. For example, the URI news:comp.lang.perl.misc might invoke a Usenet client.
However, before you call the browse() method make sure to check if this action is supported on the current platform by calling the isSupported() method with java.awt.Desktop.Action.BROWSE as the value of the first and only parameter.
Note that even though this method returns true, it’s still possible that the platform doesn’t support the URI — for example if there is no application registered for the given scheme. In this case the browse() method will throw an IOException.
Example Java program using the browse method
Below follows a small example program that can be invoked from the command line. It attempts to open each argument as a URI in the user-default browser, or if the browser can’t handle the URI, an attempt is made to pass the URI to the application registered for the URI’s scheme.
import java.net.URI; import java.awt.Desktop; public class OpenURI < public static void main(String [] args) < if( !java.awt.Desktop.isDesktopSupported() ) < System.err.println( "Desktop is not supported (fatal)" ); System.exit( 1 ); >if ( args.length == 0 ) < System.out.println( "Usage: OpenURI [URI [URI . ]]" ); System.exit( 0 ); >java.awt.Desktop desktop = java.awt.Desktop.getDesktop(); if( !desktop.isSupported( java.awt.Desktop.Action.BROWSE ) ) < System.err.println( "Desktop doesn't support the browse action (fatal)" ); System.exit( 1 ); >for ( String arg : args ) < try < java.net.URI uri = new java.net.URI( arg ); desktop.browse( uri ); >catch ( Exception e ) < System.err.println( e.getMessage() ); >> > >
But there are more actions
Besides the browse() method there are 5 more methods, providing support for the 4 following Desktop actions:
EDIT The edit() method launches the associated editor application and opens a file for editing. MAIL There are two mail() methods. The first one doesn’t take any parameters and launches the mail composing window of the user-default mail client. The second method takes a single parameter: a «mailto» URI. It also launces the mail composing window of the user-default mail client, but additionally fills in the message fields specified by the «mailto» URI (for example, to, subject, etc.). OPEN The open() method launches the associated application to open the file. If the specified file is a directory, the file manager of the current platform is launched to open it. PRINT Prints a file with the native desktop printing facility, using the associated application’s print command.
Java 1.6 Desktop class related
- Desktop — Class documentation, Java Platform SE 6
- Desktop.Action — Enum documentation, Java Platform SE6
- Using the Desktop API in Java SE 6
Also today
Downloading (opening) a file in a browser
posted 18 years ago
I have inherited a web application that has a sort of «sourcesafe» feature on it. For example, a person can upload a file (which is stored as a BLOB in an oracle 8i database) via a friendly web page. and can then at a later date come back in and «check out» the version, modify it, and add the new version back in. There is also an option to «Download» the file onto the user’s local machine. This is where the problem comes in. When clicking on the Download button the user is currently given the option to either «Open» or «Save» the file. If «Save» is selected, the user is prompted to save the file to his local disk and everything is wonderful when it is opened up later. This works for .doc, .ppt, .html, .gifs, etc. However, if the user selects the «Open» selection, the file is supposed to open up right there without saving. This isn’t working for ANY extensions or files.
Depending on what type of file the user is attempting to open, a different error message will ensue, but it basically comes down to the fact that the file can’t be found. For example, downloading a .pdf gives this error:
«There was an error opening the file. The file cannot be found.»
Here’s a snippet of the code that is actually doing the work in the Action class. I can offer more code if necessary.
BufferedOutputStream out = null;
try
out = new BufferedOutputStream(response.getOutputStream());
response.setContentType(fileBean.getContentType());
response.setHeader («Content-Disposition», «attachment; filename=\»» + fileBean.getName() + «\»»);
out.write(fileBean.getData());
out.flush();
>
finally
if (out != null)
out.close();
>
>
How come the save works and not the open? I have a feeling I’m missing something simple here.
Thanks for your help!
bryan
«. and the Truth will set you free.»