Освоение Tiger: AWT взрослеет

Позиционирование мыши и z-порядок

AbstractWindow Toolkit является основой набора компонентов Swing. Джон Жуковски обсуждает аспекты AWT, которые изменились в 5.0 версии платформы Java™ 2. К ним относятся PointerInfo и MouseInfo, применяемые для восстановления позиции указателя и управления z-порядком на экране с перекрывающимися компонентами. Примите участие в дискуссионном форуме по этой статье. (На форум вы можете перейти по ссылке Discuss вверху и внизу статьи.)

John Zukowski, Президент, JZ Ventures, Inc.

Author photoДжон Жуковски (John Zukowski) руководит стратегией Java-консалтинга в JZ Ventures, Inc. и работает с SavaJe Technologies над разработкой платформы для мобильных телефонов следующего поколения. Последними его книгами являются "Полное руководство по Java Swing, 3-е издание" (Apress, июнь 2005) и "Освоение Java 2, J2SE 1.4" (Sybex, апрель 2002).



24.05.2005

При обсуждении пользовательских интерфейсов Java все внимание уделяется набору компонентов Swing. Но в GUI есть не только Swing. Как и в ранних версиях платформы Java, Swing построен поверх Abstract Window Toolkit (AWT).

Что означает "поверх"? В Swing ничего не происходит без поддержки в AWT. Например, оригинальная версия AWT имела так называемые равноправные компоненты; когда вы создавали компонент AWT Button – создавался "родной" компонент. На машинах с Microsoft Windows при этом создавался компонент кнопки Windows, а в системах Solaris создавалась кнопка Motif. Десять лет назад, когда был впервые представлен язык программирования Java, "родные" компоненты казались правильным выбором.

Версия 1.1 платформы Java изменила ситуацию. В ней была добавлена возможность создавать неравноправные или облегченные компоненты. До этих изменений Swing не мог существовать; методом создания специализированного компонента было использование подкласса Canvas, при этом создавался "родной" для платформы компонент.

Но я отклонился от темы. Совет этого месяца посвящен не истокам Swing или языка программирования Java, а тому, как расширен AWT в версии 5.0. Хотя самое заметное изменение – это Swing, оно, определенно, не единственное. Перейдем к улучшениям в AWT.

PointerInfo и MouseInfo

В Java 5.0 были добавлен два новых класса: PointerInfo и MouseInfo. Эти классы помогают найти мышку на рабочем столе. Начнем с класса MouseInfo. В нем есть два статических метода:

  • int getNumberOfButtons() информирует о количестве кнопок на вашей мышке. В зависимости от количества кнопок мыши вы, возможно, захотите настроить доступные варианты работы по-разному, как показано в листинге 1:
    Листинг 1. Подсчет количества кнопок мыши
    public class Mouse {
      public static void main(String args[]) {
        int count = MouseInfo.getNumberOfButtons();
        System.out.println("Mouse buttons = " + count);
      }
    }
  • PointerInfo getPointerInfo() возвращает объект PointerInfo.

Возвращенный объект PointerInfo имеет свой собственный набор из двух методов:

  • GraphicsDevice getDevice() сообщает об устройстве, на котором расположен указатель мыши, действительный объект GraphicsDevice. В системе с несколькими экранами вызовите этот метод и получите соответствующий объект GraphicsDevice, относящийся к расположению мыши.
  • Point getLocation() получает физическое местонахождение мышки на экране, как показано в листинге 2:
    Листинг 2. Получение позиции указателя мыши
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class Pos {
      public static void main(String args[]) {
        Runnable runnable = new Runnable() {
          public void run() {
            JFrame frame = new JFrame("Mouse Position");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          JLabel label = new JLabel();
            label.setHorizontalAlignment(JLabel.CENTER);
            MouseMotionListener mouseMotionListener = new MouseMotionListener() {
              public void mouseDragged(MouseEvent e) {
                showMousePos(e);
              }
    
              public void mouseMoved(MouseEvent e) {
                showMousePos(e);
              }
    
              private void showMousePos(MouseEvent e) {
                JLabel src = (JLabel)e.getComponent();
                PointerInfo pointerInfo = MouseInfo.getPointerInfo();
                Point point = pointerInfo.getLocation();
                src.setText(point.toString());
              }
            };
            label.addMouseMotionListener(mouseMotionListener);
            frame.add(label, BorderLayout.CENTER);
            frame.setSize(300, 300);
            frame.setVisible(true);
          }
        };
        EventQueue.invokeLater(runnable);
      }
    }

На рисунке 1 показан этот код в действии. Перемещение указателя мыши по окну меняет координаты позиции указателя.

Рисунок 1. Получение позиции указателя мыши
Получение позиции указателя мыши

Класс Component имеет также метод getMousePosition(), который возвращает объект Point. Возвращаемый методом getMousePosition() Point представляет собой позицию указателя мыши на координатной плоскости компонента. Метод getLocation() PointerInfo работает с координатной плоскостью всего графического устройства (то есть экрана) в системе с одним экраном.

Если вы не знакомы с классом java.awt.Robot, скажу, что класс Robot позволяет переместить указатель мыши. Этот класс существует, начиная с версии 1.3, и содержит метод mouseMove(), принимающий аргументы для координат x и y. Теперь вы не только можете перемещать указатель мыши, но и узнавать его позицию.


z-порядок и AlwaysOnTop

Концепция z-порядка описывает третье измерение, в котором размещаются компоненты и их окна. x и y определяют горизонтальную и вертикальную позиции соответственно с (0, 0) в левом верхнем углу экрана. Добавление z-порядка позволяет вам управлять размещением компонентов друг над другом.

На уровне контейнера вы получаете два метода setComponentZOrder(Component c, int layer) и getComponentZOrder(Component c). Переданный в метод setComponentZOrder() layer начинается с 0 как самый верхний уровень, рисуемый последним, поверх всего остального; далее номера уровней увеличиваются.

Демонстрационная программа, приведенная в листинге 3, создает три компонента и размещает их друг над другом. Работа с z-порядком включает несколько этапов. Во-первых, вам необходимо запретить менеджер размещения для контейнера setLayout(null). Если этого не сделать и добавить компоненты в z-порядке, этот порядок не будет иметь значения, поскольку перекрывающихся компонентов не будет. Естественно, при использовании специализированного менеджера размещения, который перекрывает компоненты, все будет работать.

Затем вы добавляете компоненты в контейнер без каких-либо схемных ограничений. Далее, установите z-порядок при помощи вызова setComponentZOrder() для каждого компонента в контейнере. В качестве дополнительного шага для корректного рисования перекрывающихся компонентов, содержащий перекрывающиеся компоненты контейнер должен запретить оптимизацию их вывода, возвращая в их методе isOptimizedDrawingEnabled() значение false. Этот последний штрих производится созданием подкласса JPanel, поскольку нет метода setOptimizedDrawingEnabled().

Листинг 3. z-порядок и AlwaysOnTop
import java.awt.*;
import javax.swing.*;

public class Zs {

  public static void main(String args[]) {
    Runnable runnable = new Runnable() {
      public void run() {
        JFrame frame = new JFrame("Z-Ordering");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton top = new JButton("Top");
        JButton middle = new JButton("Middle");
        JButton bottom = new JButton("Bottom");

        int x=25;
        int y=75;
        int width=100;
        int height=50;
        int overlap = 25;
        int widthDelta = width - overlap;
        int heightDelta = height - overlap;

        top.setBounds(x, y, width, height);
        middle.setBounds(x + widthDelta, y - heightDelta,
          width, height);
        bottom.setBounds(x + (widthDelta) * 2, y - (heightDelta) * 2,
          width, height);

        JPanel contentPane = new JPanel() {
          public boolean isOptimizedDrawingEnabled() {
            return false;
          }
        };
        contentPane.setLayout(null);
        contentPane.add(top);
        contentPane.add(middle);
        contentPane.add(bottom);
        contentPane.setComponentZOrder(top, 0);
        contentPane.setComponentZOrder(middle, 1);
        contentPane.setComponentZOrder(bottom, 2);
        frame.setContentPane(contentPane);
        frame.setSize(300, 200);
        frame.setVisible(true);
      }
    };
    EventQueue.invokeLater(runnable);
  }
}

На рисунке 2 показаны результаты выполнения кода, приведенного в листинге 3.

Рисунок 2. z-порядок
z-порядок

Вы не только можете управлять z-порядком индивидуальных компонентов внутри контейнера, но и управлять z-порядком окон, или по крайней мере указать, какое из них должно быть верхним. Конечно, вы можете вызвать метод toFront() для перемещения конкретного окна наверх, но сейчас, используя платформу Java 5.0, можно вызвать новый метод setAlwaysOnTop() класса Window. Если свойство alwaysOnTop окна установлено в true, то оно всегда показывается поверх других окон. В других окнах могут все еще иметься выбранные компоненты, но эти окна с установленным в false свойством alwaysOnTop (по умолчанию) остаются в фоновом режиме.

Время летит

С десятилетием вас, пользователи Java! Да здравствует AWT, и пусть улучшения не заканчиваются!

В листинге 4 продемонстрировано это поведение:

Листинг 4. z-порядок и AlwaysOnTop
import java.awt.*;
import javax.swing.*;

public class Top {

  public static void main(String args[]) {
    Runnable runnable = new Runnable() {
      public void run() {
        JFrame frame = new JFrame("Topper");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JDialog one = new JDialog(frame, "One");
        one.add(new JButton("One"), BorderLayout.CENTER);
        one.setSize(100, 100);
        one.setLocation(25, 25);
        one.setVisible(true);

        JDialog two = new JDialog(frame, "Two");
        two.add(new JButton("Two"), BorderLayout.CENTER);
        two.setSize(100, 100);
        two.setLocation(50, 50);
        two.setVisible(true);

        JDialog three = new JDialog(frame, "Three");
        three.add(new JButton("Three"), BorderLayout.CENTER);
        three.setSize(100, 100);
        three.setLocation(75, 75);
        three.setVisible(true);

        two.setAlwaysOnTop(true);

        frame.setSize(300, 200);
        frame.setVisible(true);
      }
    };
    EventQueue.invokeLater(runnable);
  }
}

На рисунке 3 показан результат работы программы, приведенной в листинге 4.

Рисунок 3. Перекрывающиеся окна
Перекрывающиеся окна

Для недоверенных приложений необходимо в их файле политики устанавливать AWTPermission равным названию, указываемому в setWindowAlwaysOnTop. Это не даст злоумышленникам перекрыть весь экран рабочего стола, делая его кажущимся реальным, в то время пока фоновое приложение будет выуживать информацию.

Только одно активное окно должно иметь свойство alwaysOnTop, установленное в значение true. Если в true установлены несколько окон, то поведение не определено и зависит от платформы.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=96634
ArticleTitle=Освоение Tiger: AWT взрослеет
publish-date=05242005