通过在 Lion 中拖动来重新排列表格行

发布于 2024-12-23 13:50:57 字数 706 浏览 1 评论 0原文

我在使用新的 Lion 功能重新排列应用程序中的行时遇到问题。我正在使用 outlineView:pasteboardWriterForItem: 来存储行索引,以便稍后在验证/接受放置时可以访问它们。我创建一个新的 NSPasteboardItem 来返回,并尝试按如下方式存储行号:

[pbItem setData: [NSKeyedArchiver archivedDataWithRootObject: [NSNumber numberWithInteger: [fTableView rowForItem: item]]]
                                                     forType: TABLE_VIEW_DATA_TYPE];

TABLE_VIEW_DATA_TYPE 是一个自定义字符串,我用来区分拖动粘贴板中的自定义数据。除了拖动这些行之外我不会使用它。

尝试拖动时,我在控制台中收到:'TableViewDataType' 不是有效的 UTI 字符串。无法为无效的 UTI 设置数据。

当然,我可以使用一些用于粘贴板的内置 UTI,但它们都不适用(并且使用它们会导致拖动接受除行之外的拖动,而它应该't)。我是否缺少一些东西,比如定义一个仅用于拖动的自定义 UTI 的方法(而不使其成为“真正的”UTI,因为我在内部拖动之外没有使用它,所以它不应该公开)。

感谢您的帮助!

I am having trouble using the new Lion functionality to rearrange rows in my app. I am using outlineView:pasteboardWriterForItem: to store the row indexes so that I can access them later when I validate/accept the drop. I create a new NSPasteboardItem to return, and am attempting to store the row number as so:

[pbItem setData: [NSKeyedArchiver archivedDataWithRootObject: [NSNumber numberWithInteger: [fTableView rowForItem: item]]]
                                                     forType: TABLE_VIEW_DATA_TYPE];

TABLE_VIEW_DATA_TYPE is a custom string I'm using to distinguish my custom data in the dragging pasteboard. I don't use it outside of dragging these rows.

When attempting the drag, I receive in Console: 'TableViewDataType' is not a valid UTI string. Cannot set data for an invalid UTI.

Of course I could use some of the built-in UTIs for pasteboards, but none of them apply (and using them causes the drag to accept drags other than the rows, which it shouldn't). Is there something I'm missing, like a way to define a custom UTI just for dragging (without making it a "real" UTI since I have no use for it outside of the internal dragging, so it shouldn't be public).

Thanks for any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

猫弦 2024-12-30 13:50:57

我有类似的要求,除了我有一个对象网格,我想通过将选定的对象拖动到新位置来重新排列。有多种方法可以做到这一点,包括创建自定义对象并实现 NSPasteboardWritingNSPasteboardReading 协议(以及 NSCoding 协议,如果您愿意)将数据读取为 NSPasteboardReadingAsKeyedArchive),但这对于拖动保留在应用程序内部的对象来说似乎有点过分了。

我所做的涉及使用 NSPasteboardItem 作为自定义 UTI 类型的包装器(它已经实现了 NSPasteboardWritingNSPasteboardReading 协议)。首先声明一个自定义 UTI 类型:

#define kUTIMyCustomType @“com.mycompany.MyApp.MyCustomType”

这需要以“com.domain.MyApp”格式定义,否则您将收到以下形式的错误: “XXX 不是有效的 UTI 字符串。无法为无效的 UTI 设置数据。”苹果在他们的文档中提到了这一点。

然后,您必须在将发生拖动的视图中注册此自定义 UTI 类型。这可以在运行时完成,并且不需要添加任何 .plist。在视图的 init 方法中添加以下内容:

[self registerForDraggedTypes:[NSArray arrayWithObjects:(NSString *)kUTIMyCustomType, nil]];

现在,确保为此视图设置了委托,并且委托对象实现了所需的 NSDraggingSourceNSDraggingDestination 协议方法。这将使您避免破坏 MVC 设计模式,允许指定的控制器对象处理将数据放置在粘贴板上,这可能涉及查询模型数据(即索引)。

具体来说,为了将拖动开始时要移动的对象的索引放置在拖动粘贴板上,作为索引数据的 NSPasteboardItem 包装器:

- (void) draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint
{
    NSPasteboard * pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    [pboard clearContents];

    NSMutableArray * selectedIndexes = [NSMutableArray array];

    // Add NSString indexes for dragged items to pasteboard in NSPasteboardItem wrappers.
    for (MyModel * myModel in [self selectedObjects])
    {
        NSPasteboardItem * pasteboardItem = [[[NSPasteboardItem alloc] init] autorelease];
        [pasteboardItem setString:[NSString stringWithFormat:@"%@", [myModel index]]
                        forType:kUTIMyCustomType];
        [selectedIndexes addObject:pasteboardItem];
    }

    [pboard writeObjects:selectedIndexes];
}

当拖动操作完成时,读取拖动的索引 NSPasteboardItem< /代码> 数据:

- (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
{
    NSPasteboard * pasteboard = [sender draggingPasteboard];

    // Check for custom NSPasteboardItem's which wrap our custom object indexes.
    NSArray * classArray = [NSArray arrayWithObject:[NSPasteboardItem class]];
    NSArray * items = [pasteboard readObjectsForClasses:classArray options:[NSDictionary dictionary]];

    if (items == nil)
        return NO;

    // Convert array of NSPasteboardItem's with NSString index reps. to array of NSNumber indexes.
    NSMutableArray * indexes = [NSMutableArray array];
    for (NSPasteboardItem * item in items)
        [indexes addObject:[NSNumber numberWithInteger:[[item stringForType:kUTIMyCustomType] integerValue]]];

    //
    // Handle dragged indexes…
    //

    return YES;
}

I had similar requirements except I had a grid of objects that I wanted to rearrange by dragging selected objects to a new location. There are several ways of doing this, including creating a custom object and implementing the NSPasteboardWriting and NSPasteboardReading protocols, (and NSCoding protocols if you will be reading data as NSPasteboardReadingAsKeyedArchive), but this seems to be overkill for dragging of objects that remain internal to the application.

What I did involves using the NSPasteboardItem as a wrapper with a custom UTI type (it already implements the NSPasteboardWriting and NSPasteboardReading protocols). First declare a custom UTI type:

#define kUTIMyCustomType @“com.mycompany.MyApp.MyCustomType”

This needs to be defined in the ‘com.domain.MyApp’ format otherwise you will get errors of the form: “XXX is not a valid UTI string. Cannot set data for an invalid UTI.” Apple mentions this in their documentation.

Then you must register this custom UTI type in the view in which your dragging will occur. This can be done at runtime, and does not require any .plist additions. In your view's init method add the following:

[self registerForDraggedTypes:[NSArray arrayWithObjects:(NSString *)kUTIMyCustomType, nil]];

Now, make sure that the delegate is set for this view, and the delegate object implements the required NSDraggingSource and NSDraggingDestination protocol methods. This will allow you to avoid breaking the MVC design pattern, by allowing the designated controller object to handle placing the data on the pasteboard which will likely involve querying model data (i.e., indexes).

Specifically, for placing on the dragging pasteboard the indexes of objects to be moved when dragging begins as NSPasteboardItem wrappers of your index data:

- (void) draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint
{
    NSPasteboard * pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    [pboard clearContents];

    NSMutableArray * selectedIndexes = [NSMutableArray array];

    // Add NSString indexes for dragged items to pasteboard in NSPasteboardItem wrappers.
    for (MyModel * myModel in [self selectedObjects])
    {
        NSPasteboardItem * pasteboardItem = [[[NSPasteboardItem alloc] init] autorelease];
        [pasteboardItem setString:[NSString stringWithFormat:@"%@", [myModel index]]
                        forType:kUTIMyCustomType];
        [selectedIndexes addObject:pasteboardItem];
    }

    [pboard writeObjects:selectedIndexes];
}

And when the dragging operation completes, to read the dragged index NSPasteboardItem data:

- (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
{
    NSPasteboard * pasteboard = [sender draggingPasteboard];

    // Check for custom NSPasteboardItem's which wrap our custom object indexes.
    NSArray * classArray = [NSArray arrayWithObject:[NSPasteboardItem class]];
    NSArray * items = [pasteboard readObjectsForClasses:classArray options:[NSDictionary dictionary]];

    if (items == nil)
        return NO;

    // Convert array of NSPasteboardItem's with NSString index reps. to array of NSNumber indexes.
    NSMutableArray * indexes = [NSMutableArray array];
    for (NSPasteboardItem * item in items)
        [indexes addObject:[NSNumber numberWithInteger:[[item stringForType:kUTIMyCustomType] integerValue]]];

    //
    // Handle dragged indexes…
    //

    return YES;
}
盛夏尉蓝 2024-12-30 13:50:57

您可以使用的另一种技术是将正在拖动的对象的索引存储在侧面的实例变量中。将所有内容都放在粘贴板上并不是绝对必要的,除非您从另一个应用程序接受项目,反之亦然。

  1. 在 awakeFromNib 中,注册 NSStringPboardType。
  2. 在…pasteboardWriterForRow 中,返回[NSString string]。
  3. 在 …draggingSession:willBegin… 中,将实例变量设置为要跟踪的索引。
  4. 在 validateDrop 中,如果您的实例变量为 nil 或视图不是您的,则返回 NSDragOperationNone。
  5. 在…draggingSession:ending…中,将实例变量清空。

希望有帮助......我正在使用表视图的技术,但它对于大纲视图应该几乎相同。

Another technique you can use is to just store the indices of the objects you're dragging in an instance variable on the side. Putting everything on the pasteboard isn't strictly necessary unless you're accepting items from another app or vice versa.

  1. In awakeFromNib, register for the NSStringPboardType.
  2. In …pasteboardWriterForRow, return [NSString string].
  3. In …draggingSession:willBegin…, set your instance variable to the indices you want to track.
  4. In validateDrop, return NSDragOperationNone if your instance variable is nil or the view is not yours.
  5. In …draggingSession:ended…, nil out your instance variable.

Hope that helps… I'm using the technique for a table view, but it should be virtually identical for an outline view.

忆梦 2024-12-30 13:50:57

您应该创建一个符合 NSPasteboardWriting 协议。

在您的自定义对象中,您可以实现 writableTypesForPasteboard: 以返回您的粘贴板项支持的自定义 UTI 列表。然后,您可以实现pasteboardPropertyListForType:,以便在粘贴板要求时返回相应自定义 UTI 对象的 plist 表示形式。

您可以使用 NSPropertyListSerialization+propertyListWithData:options:format:error: 方法从任意数据创建 plist。

然后,您可以在表视图数据源中重写 tableView:pasteboardWriterForRow: 以返回自定义对象的实例。

Instead of using a vanilla NSPasteboardItem, you should create a custom object that conforms to the NSPasteboardWriting protocol.

In your custom object, you can implement writableTypesForPasteboard: to return a list of custom UTIs that your pasteboard item supports. You then implement pasteboardPropertyListForType: to return a plist representation of your object for the appropriate custom UTI when the pasteboard asks for it.

You can create a plist from arbitrary data using the +propertyListWithData:options:format:error: method of NSPropertyListSerialization.

You would then override tableView:pasteboardWriterForRow: in your table view data source to return an instance of your custom object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文