Swing Library Многослойни панели и вложени Windows, PC World, Публикуване на отворени системи

Интерфейсът с множество прозорци (много документи) е познат на по-голямата част от потребителите на Windows. С помощта на MDI (Multi Document Interface) се правят добре познати програми като Microsoft Word, CorelDRAW!, Adobe Photoshop и кой знае какво още! технология

Интерфейсът с множество прозорци (много документи) е познат на по-голямата част от потребителите на Windows. С помощта на MDI (Multi Document Interface) се правят добре познати програми като Microsoft Word, CorelDRAW!, Adobe Photoshop и кой знае какво още!

Технологията Java първоначално избягва използването на MDI, но само докато се появи библиотеката Swing, където този интерфейс е представен от три класа: JLayeredPane, JDesktopPane и JInternalFrame. В разработката обаче най-често се използват само последните две. Факт е, че JDesktopPane е наследник на JLayeredPane, така че всички полета и методи на този клас са наследени, а неговите собствени разширяват функционалността. Например JDesktopPane рисува фона, но JLayeredPane не го прави.

Вътре в класа JInternalFrame има друг клас, JdesktopIcon, който представлява дъщерни прозорци на екрана, които са минимизирани до икона. Този клас представлява значителен интерес, но разработчиците на Swing препоръчват да не го използвате за момента, тъй като ще бъде радикално променен в много близко бъдеще. Въпреки това, за да овладеете създаването на MDI приложения, базирани на Swing, е достатъчно да разберете JDesktopPane и JInternalFrame.

Класът JDesktopPane може условно да бъде представен като прозорец, съставен от много "стъклени" слоеве. Страхотно е, че можете да поставите дъщерни прозорци между "панели", освен това на слоеве и дори както искате: всичко на един слой, всичко на различни слоеве или няколко прозореца на всекивсеки слой. Ако поставите дъщерни прозорци на същия слой, тогава всеки прозорец, върху който потребителят кликне, ще бъде изведен отпред. Прозорците, поставени на различни слоеве, никога не се разбъркват. Лежащ на слоя, който е най-близо до потребителя, той винаги ще бъде този, който е най-близо до потребителя, и единственият начин да го видите на отдалечен слой е да го преместите в област на екрана, която не е заета от най-горния прозорец. Това чудесно свойство на класовете JDesktopPane и JLayeredPane улеснява създаването на "плаващи" прозорци - палети с инструменти (които никога не се покриват от работещи прозорци), изскачащи модални ленти за съобщения и други прозорци, ако по естеството на тяхната дейност не трябва да бъдат покрити от нищо.

Когато добавя дъщерен прозорец към екземпляр на JDesktopPane (или JLayeredPane), програмистът указва номера на слоя. Най-отдалеченият слой е номериран с 0. Колкото по-висок е номерът на слоя, толкова по-близо е до потребителя. В този случай не е необходимо да номерирате слоевете, започвайки от 0 и не е необходимо да им присвоявате последователни номера. Достатъчно е да знаете, че прозорец на слой с по-висок номер ще припокрие прозорец, поставен на слой с по-нисък номер.

Друг начин за задаване на номера на слоя е използването на метода setLayer, чийто първи аргумент е препратка към поставения обект, а вторият аргумент е номера на слоя. Малка забележка: когато използвате метода setLayer, задайте номера на слоя като int число.

Многослойните панели имат няколко предварително дефинирани константи, които определят броя на слоевете, които обикновено се използват при разработването на слоеве:

DEFAULT_LAYER- към този слой трябва да се добавят нормални компоненти и прозорци;

PALETTE_LAYER- препоръчително е да поставите прозорци с палитри с инструменти и др. на този слой;

MODAL_LAYER- този слой е избран за показване на модални диалогови панели;

POPUP_LAYER- различни изскачащи прозорци (падащи списъци, подсказки и т.н.) са най-добре разположени тук;

DRAG_LAYER- най-горният слой е даден за елементи, плъзгани от място на място.

Ако използвате метода add, номерът на слоя трябва да бъде предаден като екземпляр на обект Integer. Това се дължи на факта, че базовият клас Container има метода, от който се нуждаем, има следния прототип:

Ако направите грешка и подадете аргумента не Integer, а int, тогава ще получите напълно различно извикване на метод:

В резултат на това вместо номера на слоя ще зададете поредния номер на прозореца във вашия слой. Между другото, това може да се направи и ако използвате метода add с три аргумента, за да добавите дъщерен прозорец към панела на класа JDesktopPane. Вече знаете първите два, а третият аргумент на метода е поредният номер в йерархията на прозореца на слоя, към който е добавен прозорецът. Присвояването на номера на позиции на добавени компоненти е лесно да се объркате. Въпреки че документацията съдържа полезна информация, там няма да намерите правилния начин за номериране на позиции. И така, компонент с по-висок сериен номер, за разлика от номер на слой, показва компонент, който е по-отдалечен от зрителя, т.е. компонент с номер 1 е разположен по-далеч от компонент с номер 0. Например добавяте четири прозореца и искате те да вървят в обратен ред. Следователно задавате числата 3, 2, 1, 0. На теория всичко трябва да е правилно. Но не! Всички добавени прозорци ще бъдат разбъркани. Оказва се, че номерирането на всеки нов прозорец трябва да се извърши, като се вземат предвид вече добавените компоненти. Следователно правилната последователност е 0, 0, 0, 0 (не забравяйте, че 0 е позицията, която е най-близо до зрителя). И така нататък.

Можете да използвате още няколко полезни метода: moveToFront и moveToBack. Първиятпремества избрания компонент до позицията, която е най-близо до потребителя на неговия слой, а вторият, напротив, скрива избрания компонент зад други компоненти на неговия слой.

Първо трябва да импортирате необходимите класове:

Сега създаваме дъщерен клас от JInternalFrame. Това е необходимо, защото трябва да променим подложката по подразбиране на дъщерните прозорци, което може да стане чрез създаване на наш собствен клас ChildWindow:

Отличителна черта на класа ChildWindow е неговият конструктор, който в допълнение към параметъра title, който задава заглавието на създавания прозорец, има параметър type, който определя типа на прозореца, и параметъра iconFileName, който може да се използва за задаване на иконата за рамката на създавания прозорец:

Както можете да видите от този фрагмент, в конструктора се създава нов дъщерен прозорец и в зависимост от флаговете, предадени в параметъра тип, се извикват следните стандартни методи на класа JInternalFrame: setResizable, setMaximizable, setIconifiable и setClosable. Тези методи, при даден единствен параметър true, позволяват прозорецът да бъде преоразмерен, максимизиран, минимизиран до икона или съответно затворен. Съответните бутони ще се появят в заглавната лента на прозореца. Имайте предвид, че ако параметърът на конструктора iconFileName не е празен, тогава на рамката на прозореца ще се появи дефинирана от потребителя икона, за която се използва методът setFrameIcon на класа JInternalFrame.

Следващото нещо, което конструкторът прави, е да зададе произволен цвят на фона на прозореца, използвайки произволната математическа функция на Java:

За удобство при задаване на флагове в параметъра тип на конструктора ChildWindow, този клас дефинира няколко полезни, добре четени константи:

А ето и самата програма. В допълнение към описанието на примерния клас, ниесъздайте променлива - екземпляр на класа на слоест панел JdesktopPane:

След това елементите от менюто се създават и инициализират. За коректното възпроизвеждане на надписите на български език, всички те са направени в Unicode кодировка:

В конструктора на програмния клас най-напред се инициализират слушатели за събития от операции с менюта и прозорци. Последното е необходимо, за да следите кога потребителят иска да затвори прозореца:

За красота, нека настроим външния вид на програмата според предварително зададената настройка MetalLookAndFeel. И не забравяйте да добавите многослоен панел към прозореца:

В края на работата конструкторът сглобява менюто от отделни елементи и го свързва с главния прозорец на програмата:

По-голямата част от работата на нашия пример пада върху "раменете" на метода createChildWindows. Единственият му параметър е семафор, който определя дали дъщерните прозорци трябва да бъдат създадени на същия слой или на различни. Ако параметърът е верен, тогава се генерира масивът на слоевете от обекти Integer със стойности 0. Ако параметърът е false, тогава обектите Integer с различни стойности ще бъдат заредени в масива:

Стойностите на този масив по-късно ще определят към кой слой да добавите новия дъщерен прозорец. Обърнете внимание, че когато използвате различни слоеве, числата се генерират от израза i * 2. Това илюстрира факта, че номерата на слоевете могат да бъдат непоследователни.

Сега създаваме прозорец, за който разрешаваме операцията за преоразмеряване, ще му бъде присвоена собствена икона с червен светодиод. Името на файла се взема произволно. Основното е, че файлът с икони, чието име ще добавите към изходния текст, съществува:

Веднъж създаден, на дъщерен прозорец се присвоява конкретна позиция в рамките на прозореца със слоеве и специфични размери. Следвайки товапрозорецът се добавя към слоя, съответстващ на стойността на първия елемент от масива на слоевете, в най-отдалечената позиция от зрителя.

Следващият дъщерен прозорец може да бъде затворен по команда на потребителя и е по-близо до наблюдателя от предишния:

Третият прозорец може да бъде минимизиран до икона и заема позиция 1 (т.е. следващият след предишния):

И накрая, четвъртият, последен прозорец може да бъде отворен, като неговата позиция 0 означава, че той става най-близо до зрителя, избутвайки трите предишни прозореца.

Ето колко умно трябва да поставите прозорците, за да постигнете правилното им разположение. В резултат на това прозорците ще се издигнат в следния ред: 4, 2, 3, 1 (ако започнете от най-близкия до потребителя):

Разбира се, това позициониране има смисъл само ако прозорците са на един и същи слой. В противен случай стойностите на позицията просто се игнорират.

За да премахнете всички прозорци от многослоен панел, има следния метод:

Първо извиква стандартния метод removeAll, който премахва всички компоненти на всички слоеве на панела, след което преначертава.

Два вътрешни класа слушател са отговорни за затварянето на главния прозорец на програмата и работата с менюто:

Този фрагмент от списък показва анализиране на избрания елемент от менюто и изпълнение на метода createChildWindows със стойност на параметъра false или true. Изборът - да създадете прозорци на един и същ слой или на различни - става по следния начин:

Накрая виждате стандартната входна точка main, която задава размера на прозореца и неговото заглавие.

Може би вече сте забелязали, че основният прозорец на нашия пример наследява JFrame. Това е малък трик. Факт е, че прозорците-наследници на класа JFrame вече имат екземпляр на класа JLayeredPane в своя състав! Това означава, че не е нужно да създаватеобект на клас панел с слоеве. Можете да получите връзка към съществуваща, като извикате метода getLayeredPane. Поехме по по-сложен път, за да покажем техниката на програмиране на MDI приложения.

Менюто на програмата е показано на фиг. 1.
windows
Ако използвате менюто, работещата програма ще изглежда нещо подобно на показаното на фиг. 2.
Опитайте да минимизирате прозореца и вижте как изглежда иконата за дъщерния прозорец (Фигура 3).

За да разберете многослойната система, експериментирайте с нашия пример, като щракнете върху прозорците и техните икони. И разбира се, имате огромно поле за създаване на ваши собствени MDI примери, може би дори много по-добри от това, което сме създали.