|
Главная
Статьи
Ссылки
Скачать
Скриншоты
Юмор
Почитать
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