【问题标题】:MacRuby + Interface Builder: How to display, then close, then display a window againMacRuby + Interface Builder:如何显示,然后关闭,然后再次显示一个窗口
【发布时间】:2011-01-30 13:40:28
【问题描述】:

我是 MacRuby 和 Cocoa 的完全 n00b,所以在回答时请记住这一点 - 我需要很多细节和解释。 :)

我建立了一个简单的项目,其中有 2 个窗口,这两个窗口都是使用 Interface Builder 构建的。第一个窗口是使用表格视图的简单帐户列表。它在表格下方有一个“+”按钮。当我点击 + 按钮时,我想显示一个“添加新帐户”窗口。

我还有一个AccountsController < NSWindowController 和一个AddNewAccountController < NSWindowController 类,设置为这些窗口的代表,连接适当的按钮单击方法,以及引用所需窗口的插座。

当我点击“帐户”窗口中的“+”按钮时,我会触发以下代码:

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

这在我第一次单击 + 按钮时效果很好。一切都出现了,我可以输入我的数据并将其绑定到我的模型。但是,当我关闭添加新帐户表单时,事情开始变得糟糕。

如果我将添加新帐户窗口设置为关闭时释放,那么我第二次单击 + 按钮时,该窗口仍会弹出但它被冻结。我无法单击任何按钮、输入任何数据,甚至无法关闭表单。我认为这是因为表单的代码已经发布,所以没有消息循环处理表单......但我对此并不完全确定。

如果我将添加新帐户窗口设置为关闭时不释放,那么我第二次单击 + 按钮时,该窗口显示正常并且可用 - 但它仍然包含我之前输入的所有数据。 .. 它仍然绑定到我之前的 Account 类实例。

我做错了什么?当我点击 Accounts 表单上的 + 按钮时,创建 Add New Account 表单的新实例、创建新 Account 模型、将该模型绑定到表单并显示表单的正确方法是什么?

...这一切都在 OSX 10.6.6、64 位和 XCode 3.2.4 上完成

【问题讨论】:

  • 您是否将其他元素连接到控制器(按钮/文本区域)?我在学习向控制器消息显示 nsobjects 下拉菜单的教程时遇到了麻烦

标签: xcode data-binding interface-builder macruby window-management


【解决方案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;
}

显然,您需要将窗口移动到名为“AddNewAccountController”的单独 NIB。在这个 NIB 中,确保将 File's Owner 的类设置为 AddNewAccountController,然后将 File's Owner 的窗口出口连接到窗口。

设置完所有这些后,您每次都会获得一个新的控制器/窗口。它还具有将笔尖和控制器分成更集中的单元的好处。

--

最后一件事。虽然可以在窗口中执行此类操作,但您可能希望最终通过工作表查看执行此操作,因为这样可以防止添加帐户窗口隐藏在其他窗口后面的可能性。

【讨论】:

  • 在 xcode 中对我来说没有什么是显而易见的。 :) 所以,.xib 文件是一个 NIB,对吧?我应该在单独的 NIB 中组织所有相互关联的界面元素——一个窗口和一个菜单、控制器和其他对象——而不是像我现在正在做的那样在 1 中?这将使我能够更好地控制加载的内容、时间……以及在加载 NIB 时创建 NIB 中的所有 UI 元素……我可以使用 awakeFromNib 实例化我的模型并将其绑定到窗口的 .datasource。听起来对吗?
  • 还有 - windowWillClose 通知...应该在添加新帐户控制器中吗?或帐户控制器?我会在帐户控制器中考虑,因为那是我使用 addNewAccountcontroller 变量的地方。但我看不到如何从此处的 AddNewAccount 窗口获取 windowWillClose 通知。
  • 有趣的注释...我明白你现在使用 ivar 是什么意思了(实例 var,或 ruby​​ talk 中的 @var)。如果我使用在实例化控制器的方法中声明的标准变量,则窗口将一直存在,只要它具有焦点。一旦窗口失去焦点,它就会超出范围,并且允许垃圾收集回收它,因为不再有对它的范围内引用,并且噗——窗口关闭。 :P
  • 是的,xib 只是 nib 在编辑时的新文件格式。你应该尽量把事情分开。最好的线路是窗口和视图控制器,每个控制器都应该有自己的 nib。至于实例化您的模型,这取决于您的应用程序的结构。如果没有看到整个 Xcode 项目,我真的不能说。理想情况下,您应该只在用户确认添加时创建模型。
  • 并且 windowWillClose 委托方法进入帐户控制器。由于 [[addNewAccountController window] setDelegate:self] 行,它在那里被调用,它告诉窗口将帐户控制器作为委托。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-06
相关资源
最近更新 更多