【问题标题】:MacOS: Cell-based NSTableView custom row height breaks renderingMacOS:基于单元格的 NSTableView 自定义行高中断渲染
【发布时间】:2022-03-10 05:29:50
【问题描述】:

我正在尝试将一些非常旧的、以前功能强大的 MacOS 代码(Objective C,pre-10.7)更新到现代 MacOS 和 XCode 13。我有一个基于 NSCell 的 NSTableView,它具有自定义行高,在编译 pre-10.7 时可以正常工作,而且还有更多最近已经停止工作。回想一下 10.7 是引入自动布局和修改 NSTableView 以适应基于 NSView 的单元格的时代,因此在这个以前的功能代码中的一些问题在那个时候被刷新是有道理的。

“停止工作”的症状是我的自定义 NSCell 的绘图方法 (drawWithFrame:inView) 从未被调用,并且 NSTableView 将每一行呈现为两个像素高的不透明矩形。 8年前有人举报a similar symptom in similar global circumstances,但这个问题一直没有解决,他们不再活跃。

在 Interface Builder 中,我设置了“行大小样式:自定义”和“内容模式:基于单元格”。我相信自动布局是不相关的,因为 NSCells 没有约束。

现在是奇怪的部分。如果我删除我的 NSTableViewDelegate 的 heightOfRow 方法,表格渲染效果很好,并且自定义行渲染虽然都在一个恒定的高度。

但是,如果我重新添加一个简单的实现:

- (float)tableView:(NSTableView *)tableView heightOfRow:(int)row
{
    return 30.0;
}

然后我可以看到这个方法被调用,每行一次,以累积它们的大小,但之后 NSCell 的 draw 方法永远不会被调用。

万一我完全误解了 heightOfRow 的文档,我也尝试返回比 30.0 大得多和小得多的数字。没运气。表格在未实现的 heightOfRow 下完美呈现的事实让我相信我的 dataSource 架构甚至我的自定义 NSCell 架构都可以正常工作,并且这个问题在某种程度上与 NSTableView 如何解释我的表格行有关。

这是 Interface Builder 中表的配置:

和这里的面板(一个模态对话框)的(玩弄的)ViewController的源代码,它既包含tableView又充当它的代表:

/* A customCell, installed in our nib, allows us to do our custom rendering */
@interface CustomCell : NSCell
{
}
@end

@implementation CustomCell
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    CGContextRef quartz = [NSGraphicsContext currentContext].CGContext;
    CGContextSaveGState(quartz);
    CGContextSetRGBFillColor(quartz, 1.0, 0.0, 0.0, 1.0);
    CGContextFillEllipseInRect(quartz, cellFrame);
    CGContextRestoreGState(quartz);
}
@end

@implementation GSPRDBBrowseDialogController

#undef SHOW_THE_BUG
#ifdef SHOW_THE_BUG

/*
   SHOW THE BUG: Explicitly including any definition of the
   following delegate method, even one that returns a constant row
   height of 30, causes our [cell drawWithFrame] method to never be called,
   and all table rows appear as black rectangles 2 pixels high.
 */
- (float)tableView:(NSTableView *)tableView heightOfRow:(int)row
{ 
    return 30;
}

#else
/* with no implementation of heightOfRow, Cocoa calls our renderer using
   some the constant row height value (24 pixels) specified in the nib.
 */
#endif

- (IBAction) openButtonPressed: (id) sender
{
    [NSApp stopModal];
}


- (id) initWithContext: (const RDB_Context*) iContext
        helpContext: (int) iHelpContext
{
    rdbContext = *iContext;
    return( self = [super initWithNibNamed: @\"rdbbrowse_dlg\"
                                dialogData: NULL
                                changeProc: NULL
                                 backTrack: false
                               helpContext: iHelpContext]);
}

- (int) numberOfRowsInTableView: (NSTableView*) iTableView
{
    return 20;
}

- (id) tableView: (NSTableView*) iTableView
objectValueForTableColumn: (NSTableColumn*) iColumn
             row: (int) iRow
{
    return nil; // doesn\'t matter. real code returns more here.
}

@end

使用 SHOW_THE_BUG #UNDEFined 运行此代码会产生以下正确(但不希望出现的)结果:20 行红色圆圈,每行 24 像素高:

但是更改为#DEFINE SHOW_THE_BUG,从而包括一个玩具实现的heightOfRow,它应该将所有行设置为30像素高,相反我们得到这个......细长的矩形(仔细查看表格的顶部)和实际的单元格渲染器(drawWithFrame)是从来没有打电话

关于我的代码可能会出现什么疯狂扭曲的任何想法,定义一个有效恒定的自定​​义行高会完全中断渲染但未定义行高会产生近乎完美的结果?

谢谢, 缺口

  • 没有看到它,我们无法判断您的代码有什么问题。基于单元的NSTableView 已被弃用并且越来越多。转换为基于视图的NSTableView 是一种选择吗?
  • 谢谢@Willeke。我想尝试基于视图的表格是我的终极选择;我没有意识到 NSCells 已被正式弃用。当这么多 NSTableView 配置在 Interface Builder 中时,尝试显示代码非常令人沮丧!将尝试使用程序分配进行复制,然后发布。
  • @Willeke 我添加了源代码(IB 部分的屏幕截图)。有吸烟枪吗?
  • 我尝试了您的代码(在 macOS 10.15 上),但没有发现任何问题。我无法将控件大小设置为大。 tableView.usesAutomaticRowHeights 的值是多少?

标签: macos cocoa nstableview


【解决方案1】:

这最终是我自己的错。我作为 NSTableViewDelegate 实例化的对象,我的对话框 NSWindowController,原来是从一个长期被遗忘的基类继承而来的,该基类为这个应用程序中的其他对话框提供了一些通用实用程序。反过来,该基类实现了一些 NSTableViewDelegate 契约,因此一个委托实例化的那些部分是通过继承与我在这里实现的委托契约的各个部分混合的,从 NSTableView 的角度来看,这导致了一个损坏的契约。由于基类不在我的控制范围内,这里的解决方案是将这个表的委托实现防火墙到它自己的对象中,由这个 NSWindowController 拥有但不是从这个 NSWindowController 下降,所以它完全控制有多少(可选)NSTableViewDelegate 实例化呈现给表.

我对@Willeke 坚持认为本地实现本身是连贯的感到羞愧和感激,这让我想知道有效的委托实现是否在某种程度上“超过”本地实现......

【讨论】:

    猜你喜欢
    • 2017-10-15
    • 1970-01-01
    • 2013-11-04
    • 2013-07-22
    • 2010-10-28
    • 1970-01-01
    • 2015-03-22
    • 2017-10-25
    • 2021-02-15
    相关资源
    最近更新 更多