Воскресенье, 2024-05-19, 6:56 AM
Статьи - Java
Приветствую Вас Гость | RSS
Главная страница Каталог статей Регистрация Вход
Меню сайта

Категории каталога
Java [29]
Статьи по Java

Наш опрос
Какой раздел нужно пополнить (создать) ?
Всего ответов: 100

Начало » Статьи » Java » Java

Java Q&A
Почему нужно добавлять компоненты приложения в контейнер content окна приложения JFrame? Почему нельзя добавлять их непосредственно в окно, как в библиотеке AWT?

Почему? - Потому, что так нужно.

В данном случае ответ действительно вполне исчерпывающий. Тем не менее, имеет смысл обсудить, как в библиотеке Swing реализованы контейнеры верхнего уровня, такие как JFrame. Все контейнеры верхнего уровня имеют единственную компоненту - объект класса JRootPane. Класс JRootPane, в свою очередь, содержит компоненту glassPane и класс JLayeredPane. Далее, класс JLayeredPane содержит меню и контейнер contentPane. Вложенность контейнеров предоставляет логическую структуру размещения компонент.

Требование добавлять компоненты в контейнер contentPane призывает придерживаться описанной структуры. Попытка поступить иначе будет противоречить принципам, заложенным разработчиками библиотека Swing.

Минуточку, но зачем используется такой дизайн?

Размещая компоненты приложения в одном месте (contentPane) вы значительно упрощаете себе жизнь. Такой подход позволяет, в частности, непосредственно использовать панель glassPane и располагать компоненты на разных слоях. Например, если бы вы разместили графическую компоненту над или рядом с glassPane, вы бы не смогли запретить передачу событий этой компоненте или нарисовать что-нибудь сверху так же просто, как с использованием glassPane. Кроме того, вы бы не смогли поместить слой (содержащий, например, выскакивающее меню) над всеми компонентами, так как часть из них может лежать вне контейнера layeredPane.

Следую общей идеологии, вы получаете все предусмотренные преимущества (частью которых вы, быть может, ни когда и не воспользуетесь). Если же вы захотите всех перехитрить, вам придется побеспокоиться о поддержке внешнего дизайна приложения (look and feel), самостоятельно реализовать возможность размещения компонент на разных слоях (уровнях), а так же, для полноты, реализовать функциональность glassPane. На этом пути вам придется переписать значительную часть библиотеки Swing.

Преобразование XML в HTML на сервере

Нужно, чтобы преобразование XML документа с использованием XSL происходило на сервере и чтобы клиент получал HTML документ вместо комбинации XML документа и описания стилей в формате XSL. Как лучше подойти к решению этой задачи?

Есть много способов преобразования из формата XML в HTML. Оптимально было бы оставить эту задачу клиенту, так как выполнение ее на сервере требует слишком много ресурсов. Заставляя клиента выполнять необходимые преобразования, можно снять часть нагрузки с сервера.

К сожалению, нельзя рассчитывать на клиента - не все броузеры поддерживают преобразование XML в HTML, и понадобится достаточно много времени, прежде чем все пользователи обновят свои броузеры. Приложение на сервере может определить тип броузера и, в случае если он поддерживает XSL преобразование, передавать клиенту XML и XSL. Но это не самый удачный подход, возникают значительные трудности при поддержке.

Как выполнить преобразование на сервере? Возможны два подхода: использование сервлетов и JSP. Для выполнения преобразования на основе XSL понадобится XSL парсер. К счастью, есть отличные свободно распространяемые парсеры. (Важно еще и то, что можно получить бесплатную поддержку, например, задавая вопросы в соответствующие списки рассылки. - Смирнов).(см. Ресурсы).

Обзаведясь парсером, легко можно реализовать преобразование из XML в HTML в сервлете или на JSP странице. Механизм преобразования для этих случаев во многом одинаков. Нужно передать XML и XSL файлы парсеру, а полученный HTML документ отправить пользователю в качестве ответа на запрос.

Если вы не знакомы с сервлетами и JSP, рекомендую вам обратить внимание на проект Tomcat - "эталонную" реализацию для этих технологий. Дистрибутив содержит документацию и примеры.(см. Ресурсы)

В зависимости от сложности XML документа вы можете решить полностью отказаться от применения XSL преобразования.

Можно создать многострочную кнопку!

Предположим, я хочу создать кнопку с меткой, как показано ниже:

"Ваше

Имя"

"Имя" должно быть во второй строке.

Я пытался написать:

new JButton("Ваше \\n Имя")

К сожалению, у меня ничего не получилось. У вас есть какие-нибудь советы?

Короткий ответ: вы не сможете это сделать без значительных усилий. JButton не содержит внутренних возможностей для переноса длинных строк или начала новой строки, если текст содержит \n.

Все компоненты JFC отображаются с помощью соответствующего ComponentUI. Вместо того, чтобы помещать весь код отрисовки в метод paint JButton, JButton передает фунции отображения в ButtonUI (расширение ComponentUI). ComponentUI позволяет нам менять look and feel для Java Swing GUI на лету просто меняя рендереры ComponentUI в нашем JComponents.

Одна из реализаций ButtonUI, которую может использовать JButton -- это BasicButtonUI. Если вы достаточно храбры для того, чтобы заглянуть в код BasicButtonUI, вы обнаружите метод:

protected void paintText(Graphics g, JComponent c,
Rectangle textRect, String text)

paintText() выполняет всю грязную работу по отрисовке строки. Если мы копнем немного глубже, то обнаружим, что этот метод передает само отображение в метод drawString() в BasicGraphicsUtils:

public static void drawString(Graphics g,String
text,int underlinedChar,int x,int y)

drawString() выполняет небольшую обработку и далее просто вызывает метод drawString() из класса Graphics. Нам пришлось повозиться, но теперь достаточно очевидно, почему JButton не будет делать перенос строки.

Так что, для того чтобы сделать то, что вы хотите у вас есть несколько вариантов:

Вы можете создать свою собственную JButton, расширив JButton и перекрыв метод paint. В этом методе вы разобъете строку на основе \n, сделаете несколько вычислений размеров, отрисуете кнопку и затем выведете разбитый текст. Однако, если вы пойдете этим путем, ваша кнопка потеряет возможность подключать look and feel. Также вы можете утратить некоторые эффекты отображения в Swing.
Вы можете создать новый ButtonUI, который будет правильно форматировать ваш текст.
Вы можете использовать комбинацию из JLabels и JButton для получения того, что вам надо, вместо своей собственной кнопки. Попробуйте следующее:
JButton b = new JButton();

b.setLayout(new BorderLayout());
JLabel label1 = new JLabel("Ваше");
JLabel label2 = new JLabel("Имя");

b.add(BorderLayout.NORTH,label1);
b.add(BorderLayout.SOUTH,label2);

Если вы обнаружите, что вам приходится часто использовать многострочную кнопку, вы можете вложить вышеприведенное решение в новый класс, скажем MultiLineButton. Этот класс будет расширять JButton, содержать две копии JLabel и методы void setLabel1Text(String text) и void setLabel2Text(String text).

Swing могут отображать HTML!
Похоже, что мой превоначальный ответ о многострочных кнопках был неполным. Когда я писал свой ответ, я использовал Java 1.1.7 и Swing 1.0.3, для которых ответ остается правильным. Многие разработчики (включая меня) по-прежнему используют эти старые версии. Однако новые версии Swing способны отображать HTML.

Вот два совета, написанные двумя активными читателями JavaWorld:

Довольно много компонентов в Swing могут отрисовывать свое содержимое используя HTML. В результате, вы можете создать многострочную кнопку с помощью следующего кода: JButton b = new JButton("<html>Your<br>Name");

-- Sebastian Fernandez
И
Для решения проблемы с многострочной кнопкой просто напишите: JButton myButton = new JButton
("<html>Hello<p>World</html>");

Заметьте, что не все компоненты в Swing подерживают HTML.
-- Tarek Hammoud

Массивы массивов

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

В Java все объекты обрабатываются с помощью ссылок. Объект может иметь несколько ссылок и ссылка может указывать на разные объекты в разные моменты времени. В этом смысле ссылки напоминают указатели C/C++ (правда, они не поддерживают операции с указателями, которые заменены в Java семантикой массивов). Давайте посмотрим на пример:

String s = new String( "Привет, мир" );
// s является ссылкой типа String, указывающей
// на объект String со значением "Привет, мир" .

s= new String( "Guten Tag, Welt" );
// Та же ссылка типа String теперь указывает
// на другой объект String; то есть,
// одна и та же ссылка указывала на два
// разных объекта (последовательно).
// (Заметьте, что теперь у нас есть объект String
// со значением "Привет, мир" на который нет ссылок;
// теперь он подлежит удалению
// сборщиком мусора)

String t;
// t это ссылка типа String со значением null
// (не указывает ни на один объект).
// Если вы попробуете использовать t в этот момент, т.е.
// напишете int len = t.length; вы получите
// NullPointerException (лучше было бы сказать
// NullReferenceException).

t = s;
// Теперь ссылка типа String t указывает на тот же
// объект, что и String ссылка s,
// то есть объект со значением "Guten Tag, Welt".
// Таким образом, мы получили две ссылки
// на один объект (одновременно).

Массивы в Java это своеобразные объекты, хранят ли они примитивы (int, char, boolean, и т.д) или другие объекты. Это означает, что на массивы ссылаются, как на любые другие объекты с добавлением [] семантики агрегирование/разыменования. Например:

String [] sa;
// sa это ссылка null
// попытка доступа к sa.length приведет к NullPointerException.

sa = new String [2];
// sa уже не null, а указывает на определенный объект-
// массив из двух ссылок null String.
// sa.length теперь равна 2
// (sa[0] и sa[1] это две ссылки null String).

sa[0] = "Hello, World";
sa[1] = "Guten Tag, Welt";
// теперь sa указывает на массив из двух непустых ссылок типа String.

sa = new String[1];
// sa.length equals 1
// Та же ссылка sa тперь указывает на другой
// (и более короткий) массив.
// sa[0] это null ссылка типа String.
// Попытка обратится к sa[1] вызовет
// ArrayIndexOutOfBoundsException.

sa[0] = "Hello, World";
// sa[0] теперь непуста.

Вам также необходимо учитывать, что

String [] [] saa;
saa [0] [0] = "Help";

приведет к NullPointerException, так как saa это пустая ссылка -- saa не ссылается ни на один объект. Для того, чтобы присвоить значение первому элементу первого массива saa должна ссылаться на массив с ненулевой длиной и saa[0] должна ссылаться на непустой массив строк также с ненулевой длиной. Теперь мы можем написать:

String [] [] saa;
// saa это null ссылка на массив массивов, содержащих String
// Попытка вызвать saa.length сразу же приведет к NullPointerException,
// так же как и вызов saa[0].

saa = new String [1][];
// saa теперь ссылается на массив, содержащий 1 null ссылку на String[].
// saa.length равна 1.
// saa[0] пуст.

saa[0] = new String[2];
// saa теперь ссылается на массив, содержащий одну непустую ссылку
// на String[] с длиной 2.
// saa.length по-прежнему равна 1.
// saa[0].length равна 2 (но saa[0][0] и
// saa[0][1] обе null).

saa[0][0] = "Hello, World";
saa[0][1] = "Guten Tag, Welt";
// Теперь saa[0][0] и saa[0][1] обе непусты.

Заметье, что вы не можете ссылаться на saa[0][0] пока saa[0] непуст, и вы не можете сделать saa[0] непустым пока вы не сделаете saa непустым также. В принципе вам прийдется создавать сво массив массивов в возрастающем порядке.

Вот упрощенный способ для инициализации ссылок в массивах:

String [][] saa = {
{ { "Hello, World }, { "Guten Tag, Welt"} } };
// создаем объект String[][], как и ранее
// и присваиваем ему saa.
// Пробел подчеркивает, что созданный объект
// это массив из одного String[],
// содержащий две строки.

Используя такой прием, перепишем наш пример:

String [][] saa = { { { "Help" } } };

Однако saa теперь указывает на последовательный массив строк. Заметьте, что приведенный синтаксис работает только при инициализации ссылки на массив (инициализация это специальный тип присваивания во время объявления). Более общий способ создания нового массива и присваивания ему ссылки на новый или существующий массив выглядит так (в этом случае для уже существующей ссылки):

saa = new String [][] {
// заметьте пустые [][] -- компилятор сам
// установит размер (пустые [][] должны быть обязательно).
{ { "Hello" }, { "World" } }
// это saa[0]
,
// заметьте запятую, разделяющую
// saa[0] и saa[1]
{ { "Guten Tag" }, { "Welt"} }
// это is saa[1]
};
// теперь saa.length = 2, и длина saa[0] и saa[1] также 2

Firewall tunneling

Как мне соединиться с моим Java сервером через HTTP когда клиент находится за proxy/firewall? Я пробовал такое с апплетом, но он выдает в числе прочих исключение "host unreachable".

Вы не можете соединится, потому что proxy/firewall клиента предотвращает большинство соединений через сокеты. Большинство файрволов перекрывают любой обмен информацией, кроме HTTP. Это делается для того, чтобы защитить внутренюю инфраструктуру; пользователи по-прежнему могут использовать Веб, но не могут соединится с другими сетевыми приложениями.

Однако, есть способы для соединения ваших Java приложений и серверов через HTTP. Иногда такой прием называют firewall tunneling. Для того, чтобы облегчить себе жизнь, напишите сервлеты для сервера и оберните все клиентские сообщения в HTTP запросы.

На стороне клиента ваш код должен использовать URLConnection для отправки данных на сервер:

//соединится
URL url = new URL("http://www.myserver.com/
servlets/myservlet");

URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Content-Type", "application/octet-stream");

//Открываем output stream и посылаем данные.
OutputStream out = conn.getOutputStream();
//В данном случае ничего не выдается в поток, но вы можете это сделать.

out.flush();
out.close();

//Открываем input stream и загружаем данные.
InputStream in = conn.getInputStream();

//Здесь вы будете загружать свои данные.

in.close()

На стороне сервера, когда клиент выдает openConnection(), вызывается метод сервлета doPost(). В этом методе вы можете читать данные и отсылать их клиенту.

Семафоры

Java использует ключевое слово synchronized и методы wait() и notify() класса java.lang.Object для синхронизации. Существуют ли другие способы, например семафоры, в Java?

Единственные механизмы синхронизации, встроенные в Java-- это мониторы (monitors) и наборы задержек (wait sets), о которых большинство программистов даже не слышало, так как они скрыты в synchronized, wait() и notify(). К счастью, Java позволяет вам реализовать все знакомые схемы синхронизации на основе мониторов и наборов задержек. В конце этой заметки мы узнаем, как написать наш собственный класс Semaphore.

Однако перед этим давайте посмотрим немного на теоретические основы. Каждый многопотоковый (multithreaded) язык программирования должен иметь механизм для синхронизации нитей. Возьмем, например, программу с нитью, которая создает объекты, и нитью, которая использует их, как в этом примере кода:

Object data = null;

public void push(Object d) {
data = d;
}

public Object pop() {
Object d = data;
data = null;
return d;
}

class Producer implements Runnable {
public void run() {
while (true) {
Object o =
createNewObject();
push(o);
}
}
}

class Consumer implements Runnable {
public void run() {
while (true) {
Object o = pop();
doSomethingWith(o);
}
}
}

public static void main(String args[]) {
(new Thread(new Producer())).start();
(new Thread(new Consumer())).start();
}

Проблема с этими примитивными классами Producer и Consumer заключается в том, что они не содержат никаких способов для взаимодействия друг с другом. Если одна нить работает быстрее, чем другая, она должна периодически ждать, пока медленная нить сделает свою работу. Мы можем изменить методы push() и pop() так, чтобы они работали поочередно и не обгоняли друг-друга.

public void push(Object d) {
while (data != null)
{ /* Пустой цикл задержки. */ }
data = d;
}

public Object pop() {
while (data == null)
{ /* Пусто. */ }
Object d = data;
data = null;
/* Выход из цикла для push().*/
return d;
}

Когда одна нить выполняет push(), а другая pop(), они взаимодействуют, используя значение поля data. push() ожидает окончания работы pop(), непрерывно проверяя поле data. Когда data становится null, push() может присвоить ему новый объект. pop() использует тот же прием, сидя в цикле и ожидая, пока data изменится. Как только data становится непустым, pop() выходит из цикла и устанавливает его опять в null.

Этот прием называется циклом задержки и содержит массу недостатков. Один из самых серьезных это то, что он может использовать все свободные ресурсы процессора. Если нить consume() имеет одинаковый или более высокий приоритет, чем produce(), цикл задержки в consume() может не дать produce() работать!

Java обходит необходимость в циклах задержки используя мониторы и наборы задержек. Монитор- это структура данных, которая может содержать одну-единственную нить. Если другая нить пытается занять монитор, содержащий нить, она будет заблокирована, пока монитор не освободится. У каждого объекта есть монитор: нить занимает его, вызывая метод synchronized для этого объекта, или входя в участок кода, который помечен как synchronized. Каждый объект Java содержит набор задержек -- набор нитей которые находятся в спящем режиме, пока другая нить не активирует одну из них. Нить запускает набор задержек объекта, вызывая его метод wait(). Она может покинуть набор задержек, когда другая нить вызывает метод notify() этого объекта.

Вот реализация push() и pop(), использующая мониторы и наборы задержек:

Object full = new Object();
Object empty = new Object();

public void push(Object d) {
synchronized(full) {
if (data != null) full.wait();
}

data = d;

synchronized(empty) {
if (data != null) empty.notify();
}
}

public Object pop() {
synchronized(empty) {
if (data == null) empty.wait();
}

Object o = data;
data = null;

synchronized(full) {
if (data == null) full.notify();
}

return o;
}

Если data непуст, push() ждет, пока pop() сообщит ему, что data более не заполнен. Затем push() присваивает свой параметр data и сообщает pop(), что data заполнен. Такое решение гораздо менее нагружает процессор, чем цикл задержки. Оно также легко расширяется для поддержки нескольких производителей и потребителей объектов, вместо одного на каждый: достаточно только объявить push() и pop() как synchronized!

Мониторы Java и наборы задержек достаточно надежны для решения большинства проблем синхронизации и достаточно безопасны для того, чтобы большинство программистов не испытывали проблем. А для тех, кто любит рискованные приемы, мы приводим обещанную реализацию класса Semaphore:

/**
* Semaphore-
* это простая реализация хорошо известного
* примитива синхронизации.
* Его счетчик может быть установлен в любое
* неотрицательное значение или 0 по-умолчанию.
*/
package com.randomwalk.library.sync;

public class Semaphore {
private int counter;

public Semaphore() {
this(0);
}

public Semaphore(int i) {
if (i < 0) throw
new IllegalArgumentException(i + " < 0");
counter = i;
}

/**
* Увеличивает внутренний счетчик,
* возможно активирует нить
* wait()ing in acquire().
*/
public synchronized void release() {
if (counter == 0) {
this.notify();
}
counter++;
}

/**
* Уменьшает счетчик или блокирует,
* если тот равен 0
*
* @exception InterruptedException
* передается из this.wait().
*/
public synchronized void acquire()
throws InterruptedException {
while (counter == 0) {
this.wait();
}
counter--;
}
}

Небылицы?

Я видел веб-сайт, на котором курсор мыши превратился в рыбу с 5-ю слоями. Это вдохновило меня на то, чтобы превратить курсор на моей домашней страничке в музыкальную ноту с использованием 3-х слоев. Как мне это сделать?

В Java есть возможность создания курсоров мыши из любого изображения. Для этого нужно встроить Java апплет с измененным курсором в ваш HTML.

Создание курсора выполняется методом в java.awt.Toolkit из API:

public Cursor createCustomCursor
(Image cursor, Point hotSpot, String name)
throws IndexOutOfBoundsException

Toolkit-- это абстрактный класс, поэтому сначала нужно получить нативную реализацию:

Toolkit tk = panel.getToolkit();

Потом создать курсор: Cursor cursor =
tk.createCustomCursor
(img, hotSpot, name);

И установить курсор для панели: panel.setCursor(cursor);

(Полный код апплета показан ниже.)
К сожалению, создание курсоров возможно только в JDK 1.2 и выше. Это означает, что большинство веб-броузеров не будет их поддерживать, так как они используют только JDK 1.1. Один из выходов -- это использование Java Plug-in для JDK 1.2, который работает, как и любой другой plug-in броузера. Тут вы можете найти дополнительную информацию: http://www.javasoft.com/ products/plugin/index.html

Ну а теперь, как и обещано, полный код апплета:

import java.awt.*;
import java.applet.*;

public class CursorApplet
extends Applet {

public void init() {

//загрузить изображение через Media Tracker
MediaTracker tracker = new MediaTracker(this);
Image cursor = getImage
(getCodeBase(), "music_note.gif");
tracker.addImage(cursor, 0);

try
{
tracker.waitForID(0);
} catch
(InterruptedException ie)
{
ie.printStackTrace();
}

Cursor cr = null;
//получить toolkit
Toolkit tk = getToolkit();

try
{
//это x,y координаты изображения
//которые действительно "щелкают"
Point hotSpot = new Point(1, 1);
//создаем наш курсор
cr = tk.createCustomCursor(
cursor, hotSpot, "music_note");
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
//устанавливаем курсор для апплета
setCursor(cr);
}
}

Категория: Java | Добавил: webmaster (2006-12-14)
Просмотров: 420 | Рейтинг: 0.0 |

Всего комментариев: 0
Имя *:
Email *:
Код *:
Форма входа

Сервисы

Поиск по каталогу

Друзья сайта

| Ссылки 1 | Ссылки 2 | Ссылки 3 |
www.webmaster.clan.su Каталог+поисковая система be number one Bakililar.az Top Sites Сервис авто регистрации в
каталогах, статьи про раскрутку сайтов, web дизайн, flash, 
photoshop, хостинг, рассылки; форум, баннерная сеть, каталог 
сайтов, услуги продвижения и рекламы сайтов Скрипт для определения тиц (Яндекс CY: индекс цитирования). Определение pr (Google Pagerank). Проверить тиц pr сайта.
Copyright WebMaster.Clan © 2006 Бесплатный хостинг uCoz