如何使用子视图使用自定义单元格设置NSTableView [英] How to setup a NSTableView with a custom cell using a subview

查看:202
本文介绍了如何使用子视图使用自定义单元格设置NSTableView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ArrayController Bindings 使用自定义单元格设置 NSTableView .为此,我向自定义单元格添加了一个子视图.数据连接似乎有些正常.虽然,似乎有一个重画问题,我无法解决.当我加载应用程序时,仅呈现某些单元格.当我滚动浏览各行或选择其中的一行时,渲染会发生变化.

I am trying to setup a NSTableView with a custom cell using an ArrayController and Bindings. To accomplish this I added a subview to the custom cell. The data connection seems to work somewhat. Though, there seems to be a redraw problem which I cannot fix. When I load the application only some of the cells are rendered. When I scroll through the rows or select one the rendering changes.

我在github上创建了示例项目,以说明问题所在.

I created an example project on github to illustrate what the problem is.

可以在此处找到用于单元格渲染的实际源代码. >:

The actual source code for the cell rendering can be found here:

// CustomCell.m
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {

  if (![m_view superview]) {
    [controlView addSubview:m_view];
  }

  // The array controller only gets wrapped data items pack by the NSObjectTransformer.
  // Therefore, objectValue returns a NSObjectWrapper.
  // Unpack the wrapper to retreive the data item.
  DataItem* dataItem = [(NSObjectWrapper*)[self objectValue] original];
  [[m_view name] setStringValue:dataItem.name];
  [[m_view occupation] setStringValue:dataItem.occupation];
  [m_view setFrame:cellFrame];
}

似乎父级controlView没有重绘.我能以某种方式强迫它吗?

It seems as if the parent controlView does not redraw. Can I force it somehow?

推荐答案

这几乎肯定不是实现此目的的最佳实践方法,此后我将解释原因:但是,它确实有效.用以下内容替换您的单元格类的drawInteriorWithFrame:inView:方法:

This is almost certainly not a best practice way of doing this, and I'll explain why afterwards: however, it does seem to work. Replace your cell class's drawInteriorWithFrame:inView: method with the following:

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
    DataItem* dataItem = [(NSObjectWrapper*)[self objectValue] original];
    [[m_view name] setStringValue:dataItem.name];
    [[m_view occupation] setStringValue:dataItem.occupation];
    [m_view setFrame:cellFrame];

    NSData *d = [m_view dataWithPDFInsideRect:[m_view bounds]];
    NSImage *i = [[NSImage alloc] initWithData:d];
    [i setFlipped:YES];

    [i drawInRect:cellFrame fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}

问题是整个表只创建了一个NSCell.这就是单元格工作的方式:表视图创建一个单元格,并调用setObject…,然后依次调用drawInterior…,以使该单元格绘制整个表.从效率的角度来看,这是很棒的(NSCell类是在25mhz是一台快速计算机时才设计的,因此其目的是最大程度地减少对象分配的数量),但在这里会引起问题.

The problem is that only one NSCell is created for the entire table. That's how cells are meant to work: the table view creates a cell, and calls setObject… followed by drawInterior… over and over again to get the cell to draw the whole table. That's great from an efficiency perspective (the NSCell class was designed back when 25mhz was a fast computer, so it aimed to minimise the number of object allocations), but causes problems here.

在代码中,使用值填充视图,并设置其框架,并在需要时将其添加为表视图的子视图.但是,由于您只有一个NSCell实例,因此只能有一个视图:您拥有了一个视图,只是将其向下移动到表的行中.

In your code, you populate a view with values, and set its frame, adding it as a subview of the table view if needed. However, since you've only got one instance of NSCell, there can only be one view: you took the single view that you had and merely moved it down the rows of the table.

要正确执行此操作,您需要一些数据结构来跟踪作为NSTableView子视图添加的所有视图,并且当单元格在drawInterior…方法中更新一个视图时,您需要查找哪个正确一个是,并更新它.您还需要在代码中分配所有这些视图(或至少将视图移动到一个单独的笔尖,您可以加载该笔尖的多个副本),因为那样的话,您的笔尖中只有一个,并且复制视图是痛苦.

To do this properly, you'd need some data structure to track all the views you added as subviews of your NSTableView, and when the cell is updating one in the drawInterior… method you'd need to look up which the correct one was and update that. You'd also need to allocate all these views in code (or at least move the view to a separate nib which you could load multiple copies of), because as it is you've only got one in your nib and copying a view is a pain.

我写的代码太笨拙了,因为它实际上效率很低.我要做的是每次需要绘制视图时,都将视图绘制到屏幕外图像缓冲区中,然后将缓冲区绘制到表视图中的正确位置.这样,我避免了仅具有一个视图的问题,因为该代码仅在需要时提取并绘制其内容的新副本.

The code I wrote is a kludge, since it's really inefficient. What I did was each time the view needs to draw, I drew the view into an off screen image buffer, and then drew the buffer into the correct place in the table view. In doing so, I avoided the problem of only having one view, since the code just takes and draws a new copy of its contents whenever it is needed.

这篇关于如何使用子视图使用自定义单元格设置NSTableView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆