Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Проекты Обо мне Гостевая |
Многие наверное обращали внимание как изящно сделана в Mac OS X System Preferences работа с настройками - выбор одной из иконок приводит к плавному изменению размеров окна и содержимое окна изменяется на настройки для данного раздела.
Рис 1. System Preferences.
На самом деле подобная функциональность достигается очень легко и красиво. В этой статье мы рассмотрим простейший пример - окно в начальном состоянии содержит три кнопки (см. рис 2) и нажатие каждой из них привод к изменение как размера, так и содержимого окна.
Рис 2.
Создадим новый проект Resizer типа Cocoa Application и сразу же перейдем к редактированию ресурсов (файла - MainMenu.nib) - основная работа будет именно там.
Первое, что нам необходимо сделать - это создать объект-контроллер, который и будет отвечать за переходы кона из одного состояние в другое.
Для этого в окне MainMenu.nib откроем закладку Classes, выберем класс NSObject и нажатием Enter создадим новый класс, унаследованный от NSView. Сразу же переименуем его в MyController.
Следующим шагом будет добавление этому классу outlet'ов и методов (action'ов).
Для этого откроем панель инспектора (при помощи Shift-Command-I), перейдем в нем к разделу Attributes и добавим outlet'ы, показанные на следующем рисунке.
Рис 3. Набор outlet'ов для контроллера.
Аналогичным образом добавим контроллеру три метода - setContent:, setContentToView: и restoreContent.
Рис 4. Методы контроллера.
После этого при помощи команды меню Classes/Create Files For MyController создадим файлы MyController.h и MyController.m (и сразу же добавим их к проекту) и инстанциируем объект этого класса - после этого у нас в закладке Instances появится объект MyController.
Далее приведем главное окно к виду, показанному на следующем рисунке, т.е. изменим его размер, уберем признак Zoom (and resize) и разместим в нем кнопки с надписями "1", "2" И "3". Для каждой из этих кнопок установим соответствующее значение тега (1, 2 и 3).
Рис 5. Главное окно.
Далее как раз и начинается самое интересное - перетащим компоненту CustomView с палитры компонент прямо в раздел Instances.
Повторим эту операцию еще два раза, в результате чего у нас в разделе Instances будут три перетащенных объекта View1, View2 и View3.
Рис 6.
Обратите внимание, что каждому такому перетащенному объекту будет соответствовать свое окно в Interface Builder'е, с заголовком соответствующему имени объекта (т.е. View1, View2 и View3) - компонента, т.е. объект, унаследованный от NSView должна содержаться внутри какого-то окна.
Собственно эти компоненты и представляют собой содержимое главного окна для каждого из трех состояний. Мы можем произвольно менять из размеры, добавлять в них другие компоненты и т.п.
Пока мы ограничимся только изменением размера и добавлением кнопки "Back" в правый нижний угол.
Рис 7. Вид Interface Builder'а со всеми окнами.
После всего этого нам осталось установить связи для кнопок и контроллера.
Каждую из трех кнопок на главном окне подключим к методу контроллера setContent:.
Для каждой из компонент View1, View2 и View3 подключим кнопку "Back" к методу контроллера restoreContent:.
После этого подключим outlet'ы (выходы) контроллера view1, view2, view3, btn1, btn2 и btn3 к соответствующим объектам. Также подключим outlet window к главному окну.
Сохраним наши изменения в nib-файле и вернемся обратно в XCode. Откроем файлы MyController.h и MyController.m.
Добавим классу MyController две instance-переменные - contentView (типа NSView *) и saveFrame (типа NSRect). Ниже приводится листинг окончательного варианта файла MyController.h.
#import <Cocoa/Cocoa.h> @interface MyController : NSObject { IBOutlet NSButton * btn1; IBOutlet NSButton * btn2; IBOutlet NSButton * btn3; IBOutlet NSView * view1; IBOutlet NSView * view2; IBOutlet NSView * view3; IBOutlet NSWindow * window; NSView * contentView; NSRect saveFrame; } - (IBAction) setContent:(id)sender; - (IBAction) setContentToView: (NSView *) view; - (IBAction) restoreContent: (id) sender; @end
После этого осталось только реализовать методы класса MyController. Основным методом является setContentToView:.
Данный метод основан на том, что каждое окно содержит т.н. contentView - визуальную компоненту, соответствующую клиентской части окна. Любая добавляемая в окно компонента на самом деле добавляется именно в contentView.
Класс NSWindow предоставляет два метода для работы с contentView - contentView setContentView:. Первый из них возвращает указатель на текущий contentView, а второй позволяет задать окну другой contentView.
Таким образом, все что должен делать метод контроллера setContentToView: это задать для окна новый contentView (в его качестве будут выступать view1, view2 и view3) и изменить размеры окна чтобы они соответствовали размерам нового contentView.
Для изменения размера окна удобно воспользоваться методом setFrame:display:animate: класса NSWindow. При этом если в качестве последнего параметра задать YES, то изменение размера произойдет в виде плавной анимации.
Ниже приводится реализация данного метода контроллера.
- (IBAction) setContentToView: (NSView *) view { NSRect frame = [view frame]; NSRect winFrame = [window frame]; NSRect newFrame = NSMakeRect ( winFrame.origin.x, winFrame.origin.y-frame.size.height+winFrame.size.height, frame.size.width, frame.size.height ); [window setContentView: view]; [window setFrame: newFrame display: YES animate: YES]; }
Задачей метода setContent: (а именно он будет вызываться при нажатии кнопок переключения) является определение того, какая именно кнопка послала данное сообщение (что делается анализом ее тега), определения в какое состояние нам нужно перейти и вызов метода setContentToView: с соответствующим аргументом.
Поскольку мы хотим предоставить возможность возврата в исходное состояние (при помощи кнопки "Back"), то нам необходимо также запомнить первоначальный contentView и текущий размер окна.
- (IBAction) setContent: (id)sender { if ( contentView == nil ) contentView = [[window contentView] retain]; saveFrame = [window frame]; int tag = [sender tag]; if ( tag == 1 ) [self setContentToView: view1]; else if ( tag == 2 ) [self setContentToView: view2]; else if ( tag == 3 ) [self setContentToView: view3]; }
Задачей метода restoreContent: является восстановление исходного размера и contentView окна.
- (IBAction) restoreContent: (id) sender { [window setContentView: contentView]; [window setFrame: saveFrame display: YES animate: YES]; }
Ниже приводится полный текст файла MyController.m.
#import "MyController.h" @implementation MyController - (IBAction) setContent: (id)sender { if ( contentView == nil ) contentView = [[window contentView] retain]; saveFrame = [window frame]; int tag = [sender tag]; if ( tag == 1 ) [self setContentToView: view1]; else if ( tag == 2 ) [self setContentToView: view2]; else if ( tag == 3 ) [self setContentToView: view3]; } - (IBAction) setContentToView: (NSView *) view { NSRect frame = [view frame]; NSRect winFrame = [window frame]; NSRect newFrame = NSMakeRect ( winFrame.origin.x, winFrame.origin.y-frame.size.height+winFrame.size.height, frame.size.width, frame.size.height ); [window setContentView: view]; [window setFrame: newFrame display: YES animate: YES]; } - (IBAction) restoreContent: (id) sender { [window setContentView: contentView]; [window setFrame: saveFrame display: YES animate: YES]; } @end