MacRuby + Interface Builder: как отобразить, затем закрыть, а затем снова отобразить окно

Я полный ноль с MacRuby и Cocoa, так что имейте это в виду при ответе - мне нужно много деталей и объяснений. :)

Я создал простой проект, в котором есть 2 окна, оба из которых созданы с помощью Interface Builder. Первое окно представляет собой простой список учетных записей в виде таблицы. Под таблицей есть кнопка «+». Когда я нажимаю кнопку +, я хочу показать окно «Добавить новую учетную запись».

У меня также есть классы AccountsController < NSWindowController и AddNewAccountController < NSWindowController, настроенные как делегаты для этих окон, с подключенными соответствующими методами нажатия кнопок и выходами для ссылки на необходимые окна.

Когда я нажимаю кнопку «+» в окне «Учетные записи», у меня срабатывает этот код:

    @add_account.center
    @add_account.display
    @add_account.makeKeyAndOrderFront(nil)
    @add_account.orderFrontRegardless

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

если я настрою окно добавления новой учетной записи на выпуск при закрытии, то во второй раз, когда я нажму кнопку +, окно все равно появится, но оно заморожено. Я не могу нажимать кнопки, вводить какие-либо данные или даже закрывать форму. я предполагаю, что это связано с тем, что код формы был выпущен, поэтому нет цикла обработки сообщений, обрабатывающего форму... но я не совсем уверен в этом.

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

Что я делаю неправильно? как правильно создать новый экземпляр формы «Добавить новую учетную запись», создать новую модель учетной записи, привязать эту модель к форме и показать форму, когда я нажимаю кнопку «+» в форме «Учетные записи»?

... все это делается на OSX 10.6.6, 64bit, с XCode 3.2.4


person Derick Bailey    schedule 30.01.2011    source источник
comment
Подключили ли вы другие элементы к контроллеру (кнопки/текстовые области)? У меня возникли проблемы с выполнением руководств, которые показывают раскрывающееся меню nsobjects для сообщений контроллера.   -  person Mark Essel    schedule 27.02.2011


Ответы (1)


Проблема в том, что он не создает окно каждый раз. Освобождение при закрытии немного раздражает и обычно используется только в том случае, если вы знаете, что оконный контроллер также освобождается при закрытии окна. (Обратите внимание, что я никогда не использовал MacRuby, поэтому я буду давать код на Obj-C, поскольку знаю, что он правильный, надеюсь, вы сможете его преобразовать. Я предполагаю, что GC включен, как и должно быть с MacRuby).

Теперь есть два способа сделать это. Я не совсем уверен, как настроены ваши NIB/классы, поскольку это может быть одним из двух способов.

--

Первый способ решить эту проблему — использовать выходы, которые вы используете для ссылки на элементы формы, чтобы скрыть их при повторном отображении окна, например [myTextField setStringValue:@""]. Если вы используете привязки какао, то это немного сложнее, но в основном вы должны убедиться, что связанный объект скрыт. Я бы рекомендовал не привязываться, если вы новичок в Cocoa.

--

Второй способ — сделать класс AddNewAccountController подклассом NSWindowController. Когда вы нажмете кнопку +, вы создадите новый экземпляр и отобразите его (не забудьте сохранить его в ivar). Лучший способ сделать это будет так:

if (!addAccountController) {
    addAccountController = [[AddNewAccountController alloc] initWithWindowNibName:@"AddNewAccountController"];
    [[addAccountController window] setDelegate:self];
}
[addAccountController showWindow:self];

Это предотвращает создание нового экземпляра, если окно уже видно. Затем вам нужно реализовать делегат:

- (void)windowWillClose:(NSNotification *)notification {
    //If you don't create the account in the AddNewAccountController then do it here
    addAccountController = nil;
}

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

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

--

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

person Martin Pilkington    schedule 30.01.2011
comment
ничего не очевидно со мной, в xcode. :) Итак, файл .xib — это NIB, верно? я должен организовать все свои элементы интерфейса, которые связаны друг с другом, в отдельных NIB - окно и меню, контроллеры и другие объекты - а не в 1, как я делаю сейчас? это дало бы мне лучший контроль над тем, что загружается, когда... и все элементы пользовательского интерфейса в NIB создаются при загрузке NIB... и я мог бы использовать awakeFromNib для создания экземпляра моей модели и привязки ее к .datasource окна. это звучит правильно? - person Derick Bailey; 30.01.2011
comment
также - уведомление windowWillClose ... должно ли оно быть в контроллере добавления новой учетной записи? или контроллер счетов? я думаю, в контроллере учетных записей, потому что именно там я использую переменную addNewAccountcontroller. но я не понимаю, как я могу получить уведомление windowWillClose из окна AddNewAccount здесь. - person Derick Bailey; 30.01.2011
comment
интересное примечание... теперь я понимаю, что вы имеете в виду, говоря об использовании ivar (экземпляр var или @var в ruby ​​talk). если я использую стандартную переменную, объявленную в методе, который создает экземпляр контроллера, окно будет жить до тех пор, пока оно имеет фокус. как только окно теряет фокус, оно выпадает из области видимости, и сборщику мусора разрешается вернуть его, потому что на него больше нет ссылки в области видимости, и пуф — окно закрывается. :П - person Derick Bailey; 30.01.2011
comment
Да, xib — это просто новый формат файла для перьев при редактировании. Вы должны попытаться разделить вещи, где вы можете. Лучшие линии расположены вдоль контроллеров окон и представлений, у каждого должен быть свой собственный наконечник. Что касается создания экземпляра вашей модели, это зависит от того, как структурировано ваше приложение. Я не могу сказать, не видя всего проекта Xcode. В идеале вы должны создавать модель только тогда, когда пользователь подтвердит добавление. - person Martin Pilkington; 30.01.2011
comment
И метод делегата windowWillClose входит в контроллер учетных записей. Он вызывается там из-за строки [[addNewAccountController window] setDelegate:self], которая указывает окну поместить контроллер учетных записей в качестве делегата. - person Martin Pilkington; 30.01.2011
comment
Re: создание экземпляра модели. я не использую основные данные на данный момент. это строго модель представления, поведение которой связано только с представлением. как только я проверю несколько битов в этой модели, я передам их основной модели данных для сохранения - person Derick Bailey; 30.01.2011
comment
re: окно будет закрыто. Хорошо, я думаю, что я что-то упускаю здесь. куда идет тот первый фрагмент кода, который вы разместили? у меня есть это внутри метода add_new_clicked (метод, который обрабатывает нажатие кнопки + на контроллере учетных записей). как AddNewAccountController будет иметь доступ к этой переменной? - person Derick Bailey; 30.01.2011
comment
Оба фрагмента кода относятся к одному и тому же классу. Первый фрагмент входит в действие, как у вас сейчас, а второй фрагмент — это другой метод где-то еще в том же классе. - person Martin Pilkington; 31.01.2011