En

JazzTeam Software Development Company

Agile Java Development

FAQ созданное в процессе разработки java-апплета

Как вызывать функции JavaScript из апплета?

Как вызывать методы апплета из JavaScript?

Как использовать параметры запуска апплета?

Как создать скриншот Swing/AWT компонента?

Как использовать одновременно 2 апплета в одном браузере, если в них присутствуют static поля?

Как в Swing можно сделать поле для ввода, которое динамически расширяется при переполнении, а так же имеет минимальный размер?

Как реализовать Drag&Drop в Swing?

Как подписать апплет сертификатом?

Как проигрывать MP3- и WAV-файлы в Java?

Как использовать HTML-форматирование в Swing компонентах?

Не отображаются компоненты при использовании цикла, что делать?

Как сделать плавный переход между фреймами в Swing?

Как запустить апплет?

Как можно разместить Swing компоненты на контейнере со случайными координатами?

Как кастомизировать кнопки в Swing?

Как автоматизировать сборку апплета с помощью Maven?

Как вызывать функции JavaScript из апплета?

Это делается с помощью следующего кода:

  1. applet.getAppletContext().
  2. showDocument(new URL("javascript:" + js));

Где applet объект класса JApplet, js - имя функции JavaScript, например show().

При этом апплет должен быть запущен из JavaScript.

Как вызывать методы апплета из JavaScript?

Для этого апплет должен быть запущен из JavaScript. Например

  1. <script src="https://www.java.com/js/deployJava.js"></script>
  2. <script>
  3. var attributes = { id: 'mainApplet', code:
  4. 'org.jazzteam.Example', archive: 'example.jar', width: 812, height:
  5. 635};
  6. var parameters = {};
  7. deployJava.runApplet(attributes, parameters, '1.7');
  8. function actionInApplet(url) {
  9. mainApplet.appletMethod(url);
  10. }
  11. </script>

В данном случае апплет запущен из JavaScript с id= 'mainApplet'. В апплете находится метод appletMethod(), который мы хотим вызвать. Для этого нужно у объекта JavaScript с именем id вызвать этот метод. Также можно передавать параметры в вызываемые методы, что продемонстрировано в данном примере.

Также стоит знать, что метод апплета, вызываемый из JavaScript должен быть привилегированным. Для этого нужно обернуть код метода в такую “обёртку”:

  1. AccessController.doPrivileged(new PrivilegedAction() {
  2. public Object run() {
  3. //method code
  4. return new Object();
  5. }
  6. });

Как использовать параметры запуска апплета?

В приведённом выше примере в конструкцию "var parameters = {};" необходимо добавить нужные параметры. Например,

  1. var parameters = {firstParameter:true, secondParameter:false};

В апплете параметры считываются следующим образом:

  1. String parameter=applet.getParameter(“firstParameter”);

Где applet - объект класса JApplet (или Applet).

Такой способ так же работает при запуске апплета с помощью тегов <object> и <applet>.

Как создать скриншот Swing/AWT компонента?

Это можно сделать 2-мя способами. В обоих случаях компонент должен быть видимым.

Без использования робота:

  1. BufferedImage image = new BufferedImage(component.getWidth(),
  2. component.getHeight(), BufferedImage.TYPE_INT_ARGB);
  3. Graphics g = image.getGraphics();
  4. component.paint(g);

С использованием робота:

В данном случае будет сделан скриншот области, в которой находится компонент. То есть если компонент перекрывает окно другого приложения, то в скриншот попадёт область стороннего окна.

  1. Point point = new Point(0, 0);
  2. SwingUtilities.convertPointToScreen(point, component);
  3. Rectangle region = component.getBounds();
  4. region.x = point.x;
  5. region.y = point.y;
  6. BufferedImage image= new Robot().createScreenCapture(region);

Как использовать одновременно 2 апплета в одном браузере, если в них присутствуют static поля?

Для этого нужно запускать апплеты в разных JVM. Чтобы запустить апплеты в разных JVM нужно запустить их с параметром separate_jvm=true.

Как в Swing можно сделать поле для ввода, которое динамически расширяется при переполнении, а так же имеет минимальный размер?

Пример такого JTextField:

  1. public class TextField extends JTextField {
  2. public static final int TEXT_FIELD_PADDING = 4;
  3.  
  4. public TextField() {
  5. addAutoResize();
  6. init();
  7. }
  8.  
  9. public void init() {
  10. setStyleByParentStyle();
  11. this.setPreferredSize(new Dimension(Constant.
  12. TEXT_FIELD_MINIMAL_WIDTH, this.getPreferredSize().height));
  13. }
  14.  
  15. private void addAutoResize() {
  16. this.getDocument().addDocumentListener
  17. @Override
  18. public void insertUpdate(DocumentEvent e) {
  19. checkResize();
  20. }
  21.  
  22. @Override
  23. public void removeUpdate(DocumentEvent e) {
  24. checkResize();
  25. }
  26.  
  27. @Override
  28. public void changedUpdate(DocumentEvent e) {
  29. checkResize();
  30. }
  31. });
  32. }
  33.  
  34. private void checkResize() {
  35. FontMetrics fontMetrics = this.getFontMetrics(this.
  36. getFont());
  37.  
  38. if (fontMetrics.stringWidth(this.getText()) +
  39. TEXT_FIELD_PADDING * 2 < Constant.TEXT_FIELD_MINIMAL_WIDTH) {
  40. this.setPreferredSize(new
  41. Dimension(Constant.TEXT_FIELD_MINIMAL_WIDTH, this.getHeight()));
  42. this.getParent().revalidate();
  43. } else {
  44. //NOTE 2 - border width*2
  45. this.setPreferredSize(new
  46. Dimension(fontMetrics.stringWidth(this.getText()) + 2 +
  47. Constant.CARRET_WIDTH + TEXT_FIELD_PADDING * 2, this.getHeight()));
  48. this.getParent().revalidate();
  49. }
  50. }
  51. }

Как реализовать Drag&Drop в Swing?

В Java 6 появился довольно удобный механизм для реализации Drag&Drop, однако у него есть свои минусы. Например, необходимо явно указывать Drop Target, что не очень удобно, когда объект необходимо положить рядом с Drop Target’ом. Также в стандартной реализации нет гарантии порядка выполнения методов слушателей. Я расскажу концепцию реализации более расширяемого Drag&Drop.

Изначально на все перетягиваемые компоненты (Drag Source) необходимо назначить слушателей мыши (Mouse Listener и MouseMotionListener). Необходимо реализовать 3 метода: метод нажатия мыши на объект, метод перемещения мыши при зажатой кнопке мыши на объекте (mouseDragged в MouseMotionListener) и метод отпускания кнопки мыши.

Выглядит назначение слушателей так:

  1. component.addMouseListener(new MouseAdapter() {
  2. @Override
  3. public void mousePressed(MouseEvent e) {
  4. //block click right mouse button
  5. if (MouseEvent.BUTTON1 == e.getButton()) {
  6. startDrag(e);
  7. }
  8. }
  9.  
  10. @Override
  11. public void mouseReleased(MouseEvent e) {
  12. //block click right mouse button
  13. if (MouseEvent.BUTTON1 == e.getButton()) {
  14. endDrag(e);
  15. }
  16. }
  17. });
  18.  
  19. component.addMouseMotionListener(new MouseMotionAdapter() {
  20. @Override
  21. public void mouseDragged(MouseEvent e) {
  22. drag(e);
  23. }
  24. });

Соответственно при нажатии мыши на объект стартует Drag&Drop, при перемещении мыши объект должен перемещаться, при отпускании кнопки мыши объект должен изменить свои координаты и переместиться на новый контейнер. Если перемещение объекта будет происходить только в пределах одного контейнера, то можно реализовать лишь метод mouseDragged(), в котором будут изменяться координаты перетаскиваемого объекта:

  1. @Override
  2. public void mouseDragged(MouseEvent e) {
  3. Point mouseLocation = e.getLocationOnScreen();
  4. Component draggedComponent = (Component) e.getSource();
  5. SwingUtilities.convertPointFromScreen(mouseLocation,
  6. draggedComponent.getParent());
  7. draggedComponent.setLocation(mouseLocation);
  8. }

Но у перетаскиваемого объекта можно устанавливать координаты относительно контейнера, на котором он находится. Соответственно при перемещении мыши на другой контейнер необходимо добавлять компонент на новый контейнер, высчитывать новые координаты и т.д. Данный способ не очень красивый и расширяемый, потому я предлагаю использовать GlassPane, для отображения перетаскиваемого объекта.

Алгоритм получается приблизительно такой:

При таком подходе у нас нет завязки на контейнер, в который должен попасть курсор, чтобы произошел Drop и соответственно объект можно “ронять” куда угодно.


GlassPane с эффектом прозрачности:

  1. public class GhostGlassPane extends JPanel {
  2. private final AlphaComposite composite;
  3. private BufferedImage ghostImage = null;
  4. private Point location = new Point(0, 0);
  5.  
  6. public GhostGlassPane() {
  7. setOpaque(false);
  8. composite = AlphaComposite.getInstance(AlphaComposite.
  9. SRC_OVER, 0.7f);
  10. }
  11. public void paintComponent(Graphics g) {
  12.  
  13. if (ghostImage == null)
  14. return;
  15.  
  16. g2.setComposite(composite);
  17. g2.drawImage(ghostImage, (int) (location.getX()),
  18. (int) (location.getY()), null);
  19.  
  20. }
  21. }

В данном ответе расписан лишь концепт реализации.

Как подписать апплет сертификатом?

Прочитайте нашу статью "Подписывание Java-апплетов".

Как проигрывать MP3- и WAV-файлы в Java?

Прочитайте нашу статью "Поддержка воспроизведения MP3 и WAV форматов в Java".

Как использовать HTML-форматирование в Swing компонентах?

Html форматирование поддерживают следующие Swing-компоненты: buttons, menu items, labels, tool tips, и tabbed panes. Для использования форматирования необходимо в начале текста поставить тег <html> (закрывать его в конце не обязательно). Например:

  1. <html><b><u>T</u>wo</b>

На компоненте будет отображен следующий текст: Two

Не отображаются компоненты при использовании цикла, что делать?

Скорее всего цикл используется в потоке отрисовки Swing. Для того, чтобы выполнить какие-то действие над UI и не заблокировать поток отрисовки можно использовать Swing Timer. Пример использования:

  1. Timer timer= new Timer(1000, new ActionListener() {
  2. @Override
  3. public void actionPerformed(ActionEvent e) {
  4. //actions
  5. }
  6. });
  7. timer.setRepeats(true);
  8. timer.start();

Данный код будет раз в секунду выполнять какие-то действия, не блокируя поток отрисовки.

Так же можно установить свойство repeats=false, для выполнения действия только 1 раз.

Для остановки таймера необходимо выполнить timer.stop()

Как сделать плавный переход между фреймами в Swing?

Предложу следующий эффект:

Плавно появляется белый фон на одном фрейме (можно вставить картинку или скриншот фрейма), затем белый фон плавно исчезает, а под ним появляется следующий фрейм.

Алгоритм таков:

Как запустить апплет?

Апплет на HTML-странице можно запустить 3 способами: с помощью тега <applet>, с помощью тега <object>, с помощью JavaScript.

Тег <applet> считается устаревшим, однако до сих пор большинство апплетов запускаются с помощью этого тега:

  1. <applet code="HelloWorldApplet.class" width="320" height="120">
  2. </applet>

Пример запуска апплета с помощью тега <object>:

  1. <object type="application/x-java-applet" name="previewersGraph"
  2. width="360" height="320">
  3. <param name="codebase" value="/applets" />
  4. <param name="code" value="my.full.class.Name" />
  5. <param name="archive" value="applets.jar" />
  6. </object>

Пример запуск апплета из JavaScript можно найти выше.

Как можно разместить Swing компоненты на контейнере со случайными координатами?

Могу предложить следующий алгоритм:

Реализация алгоритма:

  1. /**
  2.  * Class for adding components to container with random
  3.  * coordinates
  4.  */
  5. public class ComponentRandomizer {
  6.  
  7. /**
  8.   * Add all components to container with random
  9.   * coordinates
  10.   */
  11. public static void addComponentsToContainer(Container
  12. container, List<JComponent> components) {
  13. List<Rectangle> cells = getContainerCells(container,
  14. components);
  15. for (JComponent component : components) {
  16. Rectangle randomCell = cells.get(new Random().
  17. nextInt(cells.size()));
  18. cells.remove(randomCell);
  19. addComponentToContainer(container, component,
  20. randomCell);
  21. }
  22. }
  23.  
  24. /**
  25.   * Add one component to container by it cell
  26.   */
  27. private static void addComponentToContainer(Container
  28. container, JComponent component, Rectangle cell) {
  29. container.add(component);
  30. int xCoordinate = getRandomInt(cell.getX(),
  31. cell.getWidth() - component.getWidth());
  32. int yCoordinate = getRandomInt(cell.getY(),
  33. cell.getHeight() - component.getHeight());
  34. component.setLocation(xCoordinate, yCoordinate);
  35. }
  36.  
  37. /**
  38.   * Get random integer
  39.   */
  40. private static int getRandomInt(double minimal,
  41. double interval) {
  42. if (interval > 0) {
  43. return (int) (minimal +
  44. new Random().nextInt((int) interval));
  45. } else {
  46. return (int) minimal;
  47. }
  48. }
  49.  
  50. /**
  51.   * Create a cells that serves to adding component into it
  52.   */
  53. private static List<Rectangle> getContainerCells(Container
  54. container, List<JComponent> components) {
  55.  
  56. Pair<Integer, Integer> optimalCellsNumber =
  57. getOptimalNumberOfContainerCells(container, components);
  58. Dimension cellSize = getCellSize(container,
  59. optimalCellsNumber);
  60.  
  61. List<Rectangle> cells = new LinkedList<Rectangle>();
  62. for (int stringIndex = 0; stringIndex <
  63. optimalCellsNumber.getKey(); stringIndex++) {
  64. for (int columnIndex = 0; columnIndex <
  65. optimalCellsNumber.getValue(); columnIndex++) {
  66. cells.add(createCell(cellSize, stringIndex,
  67. columnIndex));
  68. }
  69. }
  70.  
  71. return cells;
  72. }
  73.  
  74. /**
  75.   * Create a cell that serves to adding component into it
  76.   */
  77. private static Rectangle createCell(Dimension cellSize,
  78. int stringIndex, int columnIndex) {
  79. int xCellCoordinate = (int) (columnIndex *
  80. cellSize.getWidth());
  81. int yCellCoordinate = (int) (stringIndex *
  82. cellSize.getHeight());
  83. return new Rectangle(xCellCoordinate, yCellCoordinate,
  84. (int) cellSize.getWidth(), (int) cellSize.getHeight());
  85. }
  86.  
  87. /**
  88.   * Create cell size
  89.   */
  90. private static Dimension getCellSize(Container container,
  91. Pair<Integer, Integer> optimalCellsNumber) {
  92. double cellWidth = container.getWidth() /
  93. optimalCellsNumber.getValue();
  94. double cellHeight = container.getHeight() /
  95. optimalCellsNumber.getKey();
  96. return new Dimension((int) Math.floor(cellWidth),
  97. (int) Math.floor(cellHeight));
  98. }
  99.  
  100. /**
  101.   * Get the optimal amount of cells that can fit all of the
  102.   * components
  103.   *
  104.   * @return count strings and columns
  105.   */
  106. private static Pair<Integer, Integer>
  107. getOptimalNumberOfContainerCells(Container container,
  108. List<JComponent> components) {
  109.  
  110. //<Strings count, Columns count>
  111. Pair<Integer, Integer> numberOfContainerCells =
  112. getNumberOfContainerCells(container, components);
  113.  
  114. //remove extra columns
  115. while (Math.ceil((double) components.size() /
  116. numberOfContainerCells.getKey()) <
  117. numberOfContainerCells.getValue()) {
  118. numberOfContainerCells = new Pair<Integer,
  119. Integer>(numberOfContainerCells.getKey(),
  120. numberOfContainerCells.getValue() - 1);
  121. }
  122. //remove extra strings
  123. while (Math.ceil((double) components.size() /
  124. numberOfContainerCells.getValue()) <
  125. numberOfContainerCells.getKey()) {
  126. numberOfContainerCells = new Pair<Integer,
  127. Integer>(numberOfContainerCells.getKey() - 1,
  128. numberOfContainerCells.getValue());
  129. }
  130.  
  131.  
  132. return numberOfContainerCells;
  133. }
  134.  
  135. /**
  136.   * Split container on the cells by largest component and get
  137.   * the number of cells of the container
  138.   *
  139.   * @return count strings and columns
  140.   */
  141. private static Pair<Integer, Integer>
  142. getNumberOfContainerCells(Container container,
  143. List<JComponent> components) {
  144. JComponent largestComponent = getLargestComponent(components);
  145. int stringsCount = (int) Math.floor(container.getHeight() /
  146. largestComponent.getHeight());
  147. int columnsCount = (int) Math.floor(container.getWidth() /
  148. largestComponent.getWidth());
  149. if (stringsCount * columnsCount < components.size()) {
  150. throw new IllegalArgumentException(Constant.
  151. MESSAGE_THE_COMPONENTS_CANNOT_BE_ACCOMMODATED_IN_THE_CONTAINER);
  152. }
  153. return new Pair<Integer, Integer>(stringsCount, columnsCount);
  154. }
  155.  
  156. /**
  157.   * Get component with largest square
  158.   */
  159. private static JComponent getLargestComponent(List<JComponent>
  160. components) {
  161. JComponent largestComponent = components.get(0);
  162. for (JComponent checkedComponent : components) {
  163. if (getComponentSquare(
  164. checkedComponent.getPreferredSize()) >
  165. getComponentSquare(largestComponent.getPreferredSize())) {
  166. largestComponent = checkedComponent;
  167. }
  168. }
  169. return largestComponent;
  170. }
  171.  
  172. /**
  173.   * Create component square
  174.   */
  175. private static double getComponentSquare(Dimension
  176. checkedComponentSize) {
  177. return checkedComponentSize.getHeight() *
  178. checkedComponentSize.getWidth();
  179. }
  180.  
  181. /**
  182.   * Class for saving pair values
  183.   */
  184. public static class Pair<K, V> {
  185. private K key;
  186. private V value;
  187.  
  188. public K getKey() {
  189. return key;
  190. }
  191.  
  192. public V getValue() {
  193. return value;
  194. }
  195. public Pair(K k, V v) {
  196. key = k;
  197. value = v;
  198. }
  199. }
  200. }

Как кастомизировать кнопки в Swing?

В Swing все компоненты можно кастомизировать. Вот пример использования красивых кнопок.

Как автоматизировать сборку апплета с помощью Maven?

Для этого необходимо иметь 2 проекта: проект апплета, который будет собираться как Jar-файл, и проект веб-приложения, которые нужно будет деплоить (на выходе получим War-файл).

Соответственно создадим многомодульный проект, в котором модулями будут 2 вышеуказанных проекта:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  4. http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>org.jazzteam</groupId>
  7. <artifactId>applet-project</artifactId>
  8. <packaging>pom</packaging>
  9. <modules>
  10. <module>applet</module>
  11. <module>applet-web</module>
  12. </modules>
  13. <version>1.0-SNAPSHOT</version>
  14. </project>

После сборки модуля апплета, необходимо скопировать получившийся JAR-файл в веб-приложение.

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <artifactId>maven-antrun-plugin</artifactId>
  5. <version>1.4</version>
  6. <executions>
  7. <execution>
  8. <id>copy</id>
  9. <phase>site</phase>
  10. <configuration>
  11. <tasks>
  12. <copy file="target\applet-eugliajar"
  13. tofile="..\euglia-applet\src\main\webapp\applet-euglia.jar"/>
  14. </tasks>
  15. </configuration>
  16. <goals>
  17. <goal>run</goal>
  18. </goals>
  19. </execution>
  20. </executions>
  21. </plugin>
  22. </plugins>
  23. </build>

В данном случае общий проект нужно собирать командой “clean package site”, потому как на фазе site начинается копирование файлов.

При таком подходе в веб-приложении должна быть HTML-страница, запускающая апплет.

, , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *