【问题标题】:NSSegmentedControl action not firingNSSegmentedControl 操作未触发
【发布时间】:2018-02-02 21:32:55
【问题描述】:

我没有使用任何 Storyboard/NIB,而是以编程方式创建所有 UI。

这是主窗口控制器:

class MainWindowController: NSWindowController, NSToolbarDelegate {

    var toolbar: NSToolbar!
    var segmentedControl: NSSegmentedControl!

    override func loadWindow() {
        self.window = NSWindow(contentRect: .init(origin: .zero, size: .init(width: 640, height: 480)),
                               styleMask: NSWindow.StyleMask(rawValue: (NSWindow.StyleMask.closable.rawValue | NSWindow.StyleMask.titled.rawValue | NSWindow.StyleMask.miniaturizable.rawValue | NSWindow.StyleMask.resizable.rawValue)),
                               backing: .buffered, defer: true)
    }

    override init(window: NSWindow?) {
        super.init(window: window)
        loadWindow()

        self.window?.center()

        self.segmentedControl = NSSegmentedControl(labels: ["1", "2", "3"], trackingMode: NSSegmentedControl.SwitchTracking.selectOne, target: self, action: #selector(switchTabs))
        self.segmentedControl.setSelected(true, forSegment: 0)

        self.toolbar = NSToolbar(identifier: .init("MainToolbar"))
        self.toolbar.delegate = self
        self.toolbar.displayMode = .iconOnly
        self.window?.toolbar = self.toolbar

        self.window?.contentViewController = MainSplitViewController()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // MARK: - Selectors

    @objc func switchTabs(sender: Any) {
        let segmentedControl = sender as! NSSegmentedControl
        let tabVC = (self.window!.contentViewController as! MainSplitViewController!).tabViewController
        tabVC.tabView.selectTabViewItem(at: segmentedControl.selectedSegment)
    }

    // MARK: - NSToolbarDelegate

    func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        return [
            NSToolbarItem.Identifier.init("Add"),
            NSToolbarItem.Identifier.flexibleSpace,
            NSToolbarItem.Identifier.init("NSSegmentedControl"),
            NSToolbarItem.Identifier.flexibleSpace,
            NSToolbarItem.Identifier.init("Search")
        ]
    }

    func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        return [
            NSToolbarItem.Identifier.flexibleSpace,
            NSToolbarItem.Identifier.init("NSSegmentedControl"),
            NSToolbarItem.Identifier.init("Search"),
            NSToolbarItem.Identifier.init("Add")
        ]
    }

    func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
        switch itemIdentifier {
        case NSToolbarItem.Identifier.flexibleSpace:
            return NSToolbarItem(itemIdentifier: itemIdentifier)
        case NSToolbarItem.Identifier.init("NSSegmentedControl"):
            let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
            toolbarItem.view = self.segmentedControl
            return toolbarItem
        case NSToolbarItem.Identifier.init("Search"):
            let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
            let searchField = NSSearchField(frame: NSRect(origin: .zero, size: CGSize(width: 64, height: 64 )))
            toolbarItem.view = searchField
            return toolbarItem
        case NSToolbarItem.Identifier.init("Add"):
            let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
            let addButton = NSButton(title: "Add", target: self, action: nil)
            toolbarItem.view = addButton
            return toolbarItem
        default:
            return nil
        }
    }

}

我的窗口中嵌入了三个NSViewControllers 中的NSTabViewController。我希望能够将它们连接到我的NSToolbar 中的NSSegmentedControl 选择。

但是,action 永远不会被解雇。 switchTabs 方法永远不会被调用。如果我直接调用该函数,那么它可以工作!但是当我选择 NSSegmentedCell 时什么也没有发生。

这里出了什么问题?

我是否正确地实例化了窗口?我对loadWindow 的用法正确吗?

【问题讨论】:

  • 我是一个 Obj-C 人——所以这可能是完全错误的——但我首先想到的是 #selector(switchTabs)(无参数)和 func switchTabs(sender: Any)(一个参数)。
  • 我也是这么想的。当我使用#selector(switchTabs) 并打印动作时(就像print(segmentedControl.action!),它产生:switchTabsWithSender:。当我使用#selector(switchTabs(sender:)) 时,它产生:switchTabsWithSenderWithSender:。我不知道这是否是问题所在,因为它们都不起作用。

标签: swift macos cocoa selector appkit


【解决方案1】:

我已经用一个简单的 NSViewController 子类替换了您的 MainSplitViewController 和它自己的 nib(因为只有这么多的“在代码中创建界面”我愿意做),它运行得很好 - 工具栏被创建,段触发他们的动作, selectedSegment 报告正确的标签。

这使您的 contentViewController 及其关联视图成为最有可能的罪魁祸首:您的工具栏代码运行良好。

【讨论】:

  • 这真是令人困惑。如果我引用嵌入在我的NSSplitViewController 中的NSTabViewController 内的窗口工具栏,那么我可以将targetaction 重置为NSTabViewController 内的选择器,它工作得很好。我担心以这种方式实现它会是糟糕的设计。
  • 鉴于 NSTabViewController 符合 NSToolbarDelegate 并且您的主要目的是选项卡切换,(NSTabView 有一个 'takeSelectedTabViewFromSender' 方法),我看不出有什么问题;取决于您的“添加”功能是关于什么的。我想知道更多关于为什么你觉得你需要在代码中创建你的界面,而不是使用 nib 或故事板,我会看看像 let segmentedControl = sender as! NSSegmentedControl 而不是简单地将 sender 声明为 NSSegmentedControl(如果可以避免,请不要强制解包。)
  • 我只是更喜欢用代码做所有事情。感觉这样我就有了更多的控制权。这是我的第一个 Cocoa 应用程序,我有 Cocoa Touch 背景。其中很多都非常不同,几乎所有文档和教程都已过时。所以我总是担心做错事。
  • 我听说过时的文档。我在 www.extelligentcocoa.org 上放了很多东西,但即使这样也很难跟上。 (例如,我现在还在使用 10.12。)至于代码中的界面,我觉得我对故事板有更多的控制权,因为我可以很容易地看到事物是如何连接的以及它们的外观,而不是需要花费脑力弄清楚他们。我觉得有一个通用的指导方针:如果 Apple 强烈暗示他们希望你适应一项技术,那么当你这样做时,生活会变得更轻松。
【解决方案2】:

我无法在其当前设置中使其正常工作,因此我将 targetaction 设置为我的 NSTabViewController 和该课程中的 selector

【讨论】:

    猜你喜欢
    • 2014-09-18
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    相关资源
    最近更新 更多