我有NSOpenPanel
accessoryView
;在此视图中,用户选择几个单选按钮来更改允许的类型。面板打开时,右侧文件被启用,另一个被禁用。好的,好的。
现在,用户更改单选按钮,附件视图的viewController
会观察单选按钮矩阵中的更改,从而更改NSOpenPanel的allowedTypes
。
之后,在Apple文档之后,它会调用-validateVisibleColumns
,但面板中没有任何可见的更改。那就是:正确的文件似乎已禁用:我可以选择它们,但它们是灰色的!
另一个错误的效果:我选择一个文件(启用),更改文件类型,(现在错误)文件保持选中状态,启用确定按钮:但这是错误的文件类型!似乎发生了变化,但界面并不知道!
我的代码是(选中绑定到单选按钮矩阵):
- (void)observeValueForKeyPath.....
{
NSString *extension = (self.selected==0) ? @"txt" : @"xml";
[thePanel setAllowedFileTypes:@[extension, [extension uppercaseString]]];
[thePanel validateVisibleColumns];
}
我首先尝试插入一个电话
[thePanel displayIfNeeded]
然后我尝试了
[thePanel contentView] setNeedsDisplay]
没有结果。我还试图实现面板委托方法panel:shouldEnableURL:
,它应该由validateVisibleColumns
调用:我刚刚发现它只在NSOpenPanel的开头被调用了一次。
有人知道为什么会这样吗?我用沙盒和非沙盒应用程序尝试了所有这些,没有区别。我用10.8 sdk开发了ML。
修改
到目前为止,避免此问题的唯一方法是实施panel:validateURL:error
,但在用户点击“打开”后会调用此方法。而且非常糟糕。
答案 0 :(得分:4)
我有完全相同的问题,10.9以下,非沙盒,并且花了很多时间来寻找解决方案!
经过大量的修补和深入研究组成NSOpenPanel
的各个类(确实是NSSavePanel
)后,我确实找到了一种方法来强制基础表刷新自己:
id table = [[[[[[[[[[[[_openPanel contentView] subviews][4] subviews][0] subviews][0] subviews][0] subviews][7] subviews][0] subviews][1] subviews][0] subviews][0] subviews][0] subviews][2];
[table reloadData];
当然,编写此hack的最佳方法是沿着子视图列表走,确保找到正确的类,并最终缓存后续reloadData
调用的结束表视图。
我知道,我知道,这是一个非常难看的kludge,但是,除了“提交错误报告”之外,我似乎无法找到解决问题的任何其他答案。其中,从我可以看到的网上人们自1.8以来一直在做! :(
修改强> 这是我现在用来使我的NSOpenPanel在10.9下正确运行的代码:
- (id) openPanelFindTable: (NSArray*)subviews;
{
id table = nil;
for (id view in subviews) {
if ([[view className] isEqualToString: @"FI_TListView"]) {
table = view;
break;
} else {
table = [self openPanelFindTable: [view subviews]];
if (table != nil) break;
}
}
return table;
}
- (void) refreshOpenPanel
{
if (_openPanelTableHack == nil)
_openPanelTableHack = [self openPanelFindTable: [[_openPanel contentView] subviews]];
[_openPanelTableHack reloadData];
[_openPanel validateVisibleColumns];
}
此代码需要声明两个实例变量_openPanel
和_openPanelTableHack
才能工作。我将_openPanel
声明为NSOpenPanel*
,将_openPanelTableHack
声明为id
。
现在,我没有调用[_openPanel validateVisibleColumns]
而是调用[self refreshOpenPanel]
来强制面板按预期更新文件名。我在创建NSOpenPanel时尝试缓存表视图,但是,一旦你“运行”面板,表视图就会改变,所以我必须将它缓存在第一次更新上。
同样,这是一个GIANT hack,但是,我不知道Apple需要多长时间才能解决附件视图和文件面板的问题,所以现在,这是有效的。
如果有人有任何其他解决方案不是巨大的kludges请分享! ;)
答案 1 :(得分:1)
Eidola解决方案的快速实施。 最大的区别是我搜索NSBrowser(子)类而不是特定的类名。测试10.10(不是沙盒)。
private weak var panelBrowser : NSBrowser? //avoid strong reference cycle
func reloadBrowser()
{
if let assumedBrowser = panelBrowser
{
assumedBrowser.reloadColumn(assumedBrowser.lastColumn)
}
else if let searchResult = self.locateBrowser(self.panel?.contentView as! NSView)
{
searchResult.reloadColumn(searchResult.lastColumn)
self.panelBrowser = searchResult //hang on to result
}
else
{
assertionFailure("browser not found")
}
}
//recursive search function
private func locateBrowser(view: NSView) -> NSBrowser?
{
for subview in view.subviews as! [NSView]
{
if subview is NSBrowser
{
return subview as? NSBrowser
}
else if let result = locateBrowser(subview)
{
return result
}
}
return nil
}
修改强>
好的,所以上面的代码不会一直有效。如果它不起作用并且选择了文件(您可以看到详细信息/预览),则必须重新加载最后一列而不是最后一列。重新加载最后两列(确保至少有2列)或重新加载所有列。
第二个问题:如果重新加载列,则会丢失选择。是的,所选文件/目录仍将突出显示,但面板不会返回正确的URL。
现在我正在使用这个功能:
func reloadBrowser()
{
//obtain browser
if self.panelBrowser == nil
{
self.panelBrowser = self.locateBrowser(self.panel?.contentView as! NSView)
}
assert(panelBrowser != nil, "browser not found")
//reload browser
let panelSelectionPatch = panelBrowser.selectionIndexPaths //otherwise the panel return the wrong urls
if panelBrowser.lastColumn > 0
{
panelBrowser.reloadColumn(panelBrowser.lastColumn-1)
}
panelBrowser.reloadColumn(panelBrowser.lastColumn)
panelBrowser.selectionIndexPaths = panelSelectionPatch
}
答案 2 :(得分:1)
只需升级到xcode 6.3(在Yosemite 10.10.3上)即可。 Apple修复了这个bug(不再需要Eidola Hack)。