Facebook google+ e-mail
Учимся программировать на JAVA
Практикум по программированию на языке Java

Занятие 7. Графические интерфейсы: импорт пакетов, наследование

Предуведомление

В отличие от предыдущих занятий, где мы в основном действовали по принципу «делай как я» и рассказывали о концепциях и технических деталях что называется «на пальцах», стиль изложения, начиная с этого занятия несколько изменится и будет более техническим.

Этого, увы, не избежать, т.к. рано или поздно мы должны будем прийти к такой точке, после которой подход «на пальцах» становится уже несостоятельным. Сейчас такой момент наступает. Так что давайте соберемся с духом, засучим рукава и приступим.

На предыдущем занятии (Занятие 6. Графические интерфейсы: первое окно) мы сформировали и вывели на экран монитора графическое окно и попутно решили некоторые задачи, касающиеся его внешнего вида и расположения. Теперь мы обсудим то, что осталось «за кадром».

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

import java.awt.*;

import javax.swing.*;

Здесь надо немного задержаться. Вспомним, что ранее мы упоминали о том, что среда программирования Java включает в себя множество библиотек, предназначенных для поддержки сети, графики, работы с базами данных, обмена сообщениями и т.д. Именно библиотеки доставляют Java всю мощь и универсальность.

В Java вместо термина «библиотека» используется понятие «пакет». Указанные выше строки как раз и подключают необходимые пакеты для формирования графического интерфейса. Позже вы увидите, что мы будем использовать и другие пакеты, но сейчас нам достаточно указанных двух.

Пакеты включают в себя необходимые классы и интерфейсы (об интерфейсах мы расскажем в свое время), обеспечивающие ту или иную функциональность будущего приложения. Наличие звездочки («*») указывает на то, что программист импортирует все содержимое пакета, без точного указания входящих в него классов или интерфейсов. Может показаться, что в случае больших пакетов, итоговый объектный код может оказаться чересчур большим, но беспокоиться не стоит: компилятор Java достаточно «умен», чтобы использовать только то, что действительно необходимо вашей программе; все, что программе не нужно, компилятор включать в объектный код попросту не станет. Если хотите, вы можете использовать несколько иную форму подключения пакетов, например,

import java.awt.Window;

import javax.swing.JFrame;

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

Импортирование (подключение) пакета к разрабатываемой программе производится ключевым словом import, после которого идет имя пакета. Каждый пакет должен импортироваться отдельно (т.е. нельзя написать import java.awt.*, javax.swing.*;). Конечно, объем исходного кода при этом несколько увеличивается, но очень незначительно. Все классы и интерфейсы, составляющие вашу программу, должны располагаться строго после конструкций import, иначе компилятор сгенерирует сообщение об ошибках компиляции.

Первый пакет (начинающийся с java.awt) обеспечивает прежде всего взаимодействие программ на Java с графической подсистемой операционной системы. Вспомните, что Java является кроссплатформенным языком программирования и генерирует единый объектный код вне зависимости от операционной системы, на которой этот код будет выполняться. Поэтому Java «вынуждена» обращаться к ресурсам, предоставляемым той операционной системой, которая установлена на компьютере пользователя. Один из таких ресурсов - графика (кроме графики Java обращается к «услугам» операционной системы для доступа к файловой системе и другим ресурсам). Так вот, пакет java.awt.* позволяет графическим интерфейсам, написанным на Java задействовать графические возможности операционной системы и отображаться графическим объектам, созданным в программах Java, на экране монитора. Здесь мы немного задержимся.

Все графические компоненты в Java подразделяются на две категории: легковесные (lightweight) и тяжеловесные (heavyweight). Подавляющее большинство графических компонентов (кнопки, списки, деревья, метки, таблицы и т.д.) являются легковесными. Это означает, что операционная система абсолютно ничего о них не знает и даже не «подозревает» об их существовании. Легковесные компоненты принадлежат окнам (подобных тому, что мы выводили на предыдущем занятии) и отображаются в этих окнах.

Если мы хотим отобразить в окне кнопку, то нам достаточно определить ее кодом, подобным следующему

...

JButton buttonPressMe = new JButton («Нажми меня»);

...

и разместить ее в указанном месте окна (соответствующие детали будут описаны позже). Кнопка – легковесный объект и операционная система не имеет о кнопке никаких сведений (для операционной системы кнопка вообще не существует). О кнопке «знает» только окно, в котором она размещена. Окно отрисовывает кнопку, перехватывает события, происходящие с кнопкой, перерисовывает кнопку если она была чем-либо заслонена и т.д. А вот само окно как таковое – о нем операционная система осведомлена и именно потому, что окно – тяжеловесный компонент. Только окно имеет доступ к ресурсам операционной системы (в частности – графическим).

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

Dimension sSize = Toolkit.getDefaultToolkit ().getScreenSize ()

Что может предоставить такую информацию? Операционная система и только она! Далее, мы использовали код

try {UIManager.setLookAndFeel

          (UIManager.getSystemLookAndFeelClassName ());

     }

catch (Exception lfe) {}

для того, чтобы внешний вид окна соответствовал стандарту, принятому в конкретной операционной системе. Что может предоставить такую информацию? Опять же – операционная система! Так что для создания графических интерфейсов без пакета java.awt.* нам не обойтись.

При выводе окна на экран операционная система выделяет окну необходимые ресурсы (прежде всего – память) и окно становится видимым. Дальше в дело вступают легковесные компоненты и вся дальнейшая работа осуществляется практически только с ними.

Второй импортируемый пакет (начинающийся с javax.swing) отвечает за формирование легковесных графических интерфейсов (есть и другие пакеты, но этот – самый важный и практически всегда используемый). Изучать и осваивать этот пакет мы будем постепенно, т.к. он весьма большой и достаточно сложный. Этим мы начнем заниматься на следующем занятии, а пока обратимся к следующей строке исходного кода:

...

public class MoneyForNothing extends JFrame {

...

Здесь новыми являются два элемента: ключевое слово extends и слово JFrame.

Ключевое слово extends (в переводе означает «расширить», но по смыслу близко к слову «наследует» или к словосочетанию «заимствовать свойства и поведение») выражает фундаментальную концепцию объектно-ориентированного программирования (или проще говоря, программирования, основанного на классах). Эта концепция носит название «наследование». С этим надо хорошенько разобраться.

Помните, на одном из первых занятий (Занятие 4. Начинаем вникать (начало)) мы обсуждали концепцию классов и в качестве примера использовали двигатель автомобиля. При всем разнообразии двигателей и их конструкций (речь, разумеется, идет о двигателях внутреннего сгорания), почти все эти двигатели похожи друг на друга: в каждом из них есть цилиндры, поршни, коленвалы, клапаны и т.д.

Конечно, громадный дизель для танкера не сравнить с крошечным спиртовым двигателем для авиамодели, но они (если так можно выразиться) – пусть и дальние, но родственники. У них общий предок – некий абстрактный двигатель, а сами двигатели – его потомки (пусть даже очень и очень дальние).

В программировании такой предок обычно называется «родитель» или «суперкласс», т.е. класс, от которого произошли другие классы. Имя суперкласса указывается непосредственно после extends. Таким образом, в переводе на обычный язык, вышеприведенный фрагмент кода можно прочитать так: «класс ... расширяет класс JFrame», «класс ... наследует класс JFrame» или «класс ... заимствует свойства и поведение класса JFrame». В классе JFrame определены основные свойства и поведение «стандартных» графических окон. Сам класс JFrame находится в пакете javax.swing.* и именно его мы и импортировали в начале программы.

JFrame – это родитель (в терминологии Java – суперкласс) графических окон (есть еще и другие окна, например, диалоговые, но о них мы поговорим в свое время). Если обратиться к документации по Java , то в ней вы обнаружите, что в классе JFrame имеются несколько конструкторов, полей и около двух десятков методов, которые определяют поведение некоего «стандартного» окна. Таким образом, наш класс с именем MoneyForNothing является наследником класса JFrame (обычно говорят не о наследниках, а о потомках или о дочерних классах).

Обратите внимание, что класс JFrame сам в свою очередь является наследником нескольких классов (большая часть которых принадлежит уже знакомому нам пакету java.awt.*):

Программируем на Java. Графические интерфейсы (импорт пакетов, наследование)

Чтобы уже не возвращаться к этому вопросу, обращаем ваше внимание на то, что в вершине иерархии наследования Java лежат классы из пакета java.lang.*. Это единственный пакет из JDK, который не нужно явно импортировать – он всегда импортируется автоматически. Судя по этой «лесенке», класс JFrame является пра-пра-правнуком java.lang.Object (картинка, приведенная выше по-научному называется иерархией классов).

Все компоненты графического пользовательского интерфейса (сокращенно GUI, от Graphical User Interface), которые, напомним, являются легковесными элементами, должны быть размещены внутри основного окна – наследника JFrame. Сейчас у нас никаких компонентов нет, но скоро они появятся – обещаем.

А теперь «пробежимся» напоследок по нашему исходному коду, который выглядит так:

    ...

    // Конструктор

    public MoneyForNothing () {

        setTitle ("Добро пожаловать в Money for Nothing");

        setSize (new Dimension (600, 400));

        Dimension sSize = Toolkit.getDefaultToolkit ().getScreenSize (),

                      fSize = getSize ();

        if (fSize.height > sSize.height) {fSize.height = sSize.height;}

        if (fSize.width > sSize.width) {fSize.width = sSize.width;}

        setLocation ((sSize.width - fSize.width)/2,

                         (sSize.height - fSize.height)/2);

        setDefaultCloseOperation (EXIT_ON_CLOSE);

        setVisible (true);

    }

    ...

Прежде всего, мы задаем заголовок окна (метод setTitle («...»)). Затем задаются размеры окна по горизонтали и вертикали (метод setSize (...)). После определения разрешения экрана монитора расчитываются координаты верхнего левого угла нашего окна и окно выводится (метод setLocation (...)) в указанном месте экрана.

После этого мы определяем что нужно делать при закрытии окна в системном меню; в данном случае видно, что приложение должно завершить свою работу (EXIT_ON_CLOSE). За этой короткой и простой строчкой на самом деле скрывается удивительно интересный и интригующий мир обработки событий. Скажем сразу: понимание механизма обработки событий в Java – ключевой момент в разработке графических приложений и начиная со следующего занятия мы займемся как раз именно этим.

Наконец, последняя строка (метод setVisible (true)) делает окно видимым.

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

На этом наше занятие подходит к концу. Самое важное, что вы должны извлечь из него – концепция наследования (заимствования). Это, действительно, основополагающая концепция. Без нее в Java нельзя создать сколько нибудь сложную и полезную программу, так что не торопитесь двигаться дальше, а еще раз внимательно просмотрите и обдумайте все, что мы к этому моменту изучили.

Удачи и до скорой встречи!

 

Занятие 6. Графические интерфейсы: первое окно

 

Занятие 8. Схема «Модель/Вид/Контроллер» (MVC)

 

Автор: Alex Tuesday

 

Все уроки ... 17.02.2014