首页 文章

在OSX 10.8 SDK / objective-c中拖动一个按钮

提问于
浏览
5

我今天开始使用objective-c来开发OSX(山狮)的应用程序 . 我有一堆按钮,我想将它们拖动到其他对象中,例如文本字段 . 我按照苹果's dev site, but I wans'上的教程来使拖动部件工作(拖放部分工作,例如,我可以将文件从finder拖到文本文件中并显示其路径) .

我首先创建了一个NSButton子类: @interface mp3OCDDraggableButton : NSButton

并实施如下所述的方法:https://developer.apple.com/library/mac/#samplecode/CocoaDragAndDrop/Introduction/Intro.html

但事情是最好的!

我在mouseDown:中放了一些日志消息,我可以看到,但是如果我用mouseDragged替换它,那就不行了: - 这会告诉我什么吗?

有人能用这个功能发布一个简单的例子吗?我找不到有用的东西:\

提前谢谢了!

这是我到目前为止可拖动按钮的代码 . 与教程中的几乎相同 .

//myDraggableButton.h

@interface myDraggableButton : NSButton <NSDraggingSource, NSPasteboardItemDataProvider>
@end

//myDraggableButton.m

#import "myDraggableButton.h"

@implementation myDraggableButton

- (void)mouseDown:(NSEvent *)theEvent:(NSEvent*)event
{

    NSLog(@"mouseDown");

    NSPasteboardItem *pbItem = [NSPasteboardItem new];
    [pbItem setDataProvider:self forTypes:[NSArray arrayWithObjects:NSPasteboardTypeString, nil]];
    NSDraggingItem *dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
    NSRect draggingRect = self.bounds;
    [dragItem setDraggingFrame:draggingRect contents:[self image]];
    NSDraggingSession *draggingSession = [self beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem] event:event source:self];
    draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
    draggingSession.draggingFormation = NSDraggingFormationNone;
}

- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
{
    switch (context) {
        case NSDraggingContextOutsideApplication:
            return NSDragOperationCopy;
        case NSDraggingContextWithinApplication:
        default:
            return NSDragOperationCopy;
            break;
    }
}

- (BOOL)acceptsFirstMouse:(NSEvent *)event
{
    return YES;
}

- (void)pasteboard:(NSPasteboard *)sender item:(NSPasteboardItem *)item provideDataForType:(NSString *)type
{
    if ( [type compare: NSPasteboardTypeTIFF] == NSOrderedSame ) {
        [sender setData:[[self image] TIFFRepresentation] forType:NSPasteboardTypeTIFF];
    } else if ( [type compare: NSPasteboardTypePDF] == NSOrderedSame ) {
        [sender setData:[self dataWithPDFInsideRect:[self bounds]] forType:NSPasteboardTypePDF];
    }

}

@end

2 回答

  • 4

    我为死灵法术道歉,但我在试图自己实现这个问题时偶然发现了这个问题,并希望分享答案,因为它可能对其他人有用 .

    此解决方案使用 NSActionCellNSControl 上的类别,因为我需要能够拖动多个控件类型,而不仅仅是按钮 . 您可以根据自己的需求/课程进行调整 .

    在隐藏/取消隐藏控件时,我已经注释了与不希望的淡入淡出动画的变通方法有关的代码 . 我摆弄着隐含的动画等,但无法想出更好的方法 . 黑客确实运行良好,但我离开了窗口实现代码 .

    @implementation NSControl (DragControl)
    
    - (NSDraggingSession*)beginDraggingSessionWithDraggingCell:(NSActionCell <NSDraggingSource> *)cell event:(NSEvent*) theEvent
    {
        NSImage* image = [self imageForCell:cell];
        NSDraggingItem* di = [[NSDraggingItem alloc] initWithPasteboardWriter:image];
        NSRect dragFrame = [self frameForCell:cell];
        dragFrame.size = image.size;
        [di setDraggingFrame:dragFrame contents:image];
    
        NSArray* items = [NSArray arrayWithObject:di];
    
        [self setHidden:YES];
        return [self beginDraggingSessionWithItems:items event:theEvent source:cell];
    }
    
    - (NSRect)frameForCell:(NSCell*)cell
    {
        // override in multi-cell cubclasses!
        return self.bounds;
    }
    
    - (NSImage*)imageForCell:(NSCell*)cell
    {
        return [self imageForCell:cell highlighted:[cell isHighlighted]];
    }
    
    - (NSImage*)imageForCell:(NSCell*)cell highlighted:(BOOL) highlight
    {
        // override in multicell cubclasses to just get an image of the dragged cell.
        // for any single cell control we can just make sure that cell is the controls cell
    
        if (cell == self.cell || cell == nil) { // nil signifies entire control
                                                // basically a bitmap of the control
                                                // NOTE: the cell is irrelevant when dealing with a single cell control
            BOOL isHighlighted = [cell isHighlighted];
            [cell setHighlighted:highlight];
    
            NSRect cellFrame = [self frameForCell:cell];
    
            // We COULD just draw the cell, to an NSImage, but button cells draw their content
            // in a special way that would complicate that implementation (ex text alignment).
            // subclasses that have multiple cells may wish to override this to only draw the cell
            NSBitmapImageRep* rep = [self bitmapImageRepForCachingDisplayInRect:cellFrame];
            NSImage* image = [[NSImage alloc] initWithSize:rep.size];
    
            [self cacheDisplayInRect:cellFrame toBitmapImageRep:rep];
            [image addRepresentation:rep];
            // reset the original cell state
            [cell setHighlighted:isHighlighted];
            return image;
        }
        // cell doesnt belong to this control!
        return nil;
    }
    
    #pragma mark NSDraggingDestination
    // message forwarding doesnt work for NSDraggingDestination methods
    // because NSView implements empty methods for the protocol
    /*
    - (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
    {
        return [self.cell draggingEntered:sender];
    }
    
    - (void)draggingExited:(id < NSDraggingInfo >)sender
    {
        [self.cell draggingExited:sender];
    }
    
    - (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
    {
        return [self.cell prepareForDragOperation:sender];
    }
    
    - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
    {
        return [self.cell performDragOperation:sender];
    }
    
    - (void)concludeDragOperation:(id < NSDraggingInfo >)sender
    {
        return [self.cell concludeDragOperation:sender];
    }
    */
    - (void)draggingEnded:(id < NSDraggingInfo >)sender
    {
        // implement whatever you want to do here.
        [self setHidden:NO];
    }
    
    @end
    
    
    static NSPoint _dragImageOffset;
    @implementation NSActionCell (DragCell)
    
    - (void)setControlView:(NSView *)view
    {
        // this is a bit of a hack, but the easiest way to make the control dragging work.
        // force the control to accept image drags.
        // the control will forward us the drag destination events via our DragControl category
    
        [view registerForDraggedTypes:[NSImage imagePasteboardTypes]];
        [super setControlView:view];
    }
    
    - (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
    {
        BOOL result = NO;
        NSPoint currentPoint = theEvent.locationInWindow;
        BOOL done = NO;
        BOOL trackContinously = [self startTrackingAt:currentPoint inView:controlView];
    
        BOOL mouseIsUp = NO;
        NSEvent *event = nil;
        while (!done)
        {
            NSPoint lastPoint = currentPoint;
    
            event = [NSApp nextEventMatchingMask:(NSLeftMouseUpMask|NSLeftMouseDraggedMask)
                                       untilDate:[NSDate distantFuture]
                                          inMode:NSEventTrackingRunLoopMode
                                         dequeue:YES];
    
            if (event)
            {
                currentPoint = event.locationInWindow;
    
                // Send continueTracking.../stopTracking...
                if (trackContinously)
                {
                    if (![self continueTracking:lastPoint
                                             at:currentPoint
                                         inView:controlView])
                    {
                        done = YES;
                        [self stopTracking:lastPoint
                                        at:currentPoint
                                    inView:controlView
                                 mouseIsUp:mouseIsUp];
                    }
                    if (self.isContinuous)
                    {
                        [NSApp sendAction:self.action
                                       to:self.target
                                     from:controlView];
                    }
                }
    
                mouseIsUp = (event.type == NSLeftMouseUp);
                done = done || mouseIsUp;
    
                if (untilMouseUp)
                {
                    result = mouseIsUp;
                } else {
                    // Check if the mouse left our cell rect
                    result = NSPointInRect([controlView
                                            convertPoint:currentPoint
                                            fromView:nil], cellFrame);
                    if (!result)
                        done = YES;
                }
    
                if (done && result && ![self isContinuous])
                    [NSApp sendAction:self.action
                                   to:self.target
                                 from:controlView];
                else {
                    done = YES;
                    result = YES;
    
                    // this initiates the control drag event using NSDragging protocols
                    NSControl* cv = (NSControl*)self.controlView;
                    NSDraggingSession* session = [cv beginDraggingSessionWithDraggingCell:self
                                                                                    event:theEvent];
                    // _dragImageOffset = [cv convertPoint:[theEvent locationInWindow] fromView:nil];
                    // Note that you will get an ugly flash effect when the image returns if this is set to yes
                    // you can work around it by setting NO and faking the release by animating an NSWindowSubclass with the image as the content
                    // create the window in the drag ended method for NSDragOperationNone
                    // there is [probably a better and easier way around this behavior by playing with view animation properties.
                    session.animatesToStartingPositionsOnCancelOrFail = YES;
                }
    
            }
        }
        return result;
    }
    
    #pragma mark - NSDraggingSource Methods
    - (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
    {
        switch(context) {
            case NSDraggingContextOutsideApplication:
                return NSDragOperationNone;
                break;
    
            case NSDraggingContextWithinApplication:
            default:
                return NSDragOperationPrivate;
                break;
        }
    }
    /*
    - (void)draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint
    {
        DragAnimationWindow* dw = [DragAnimationWindow sharedAnimationWindow];
        NSControl* cv = (NSControl*)self.controlView;
    
        NSImage* image = [[NSImage alloc] initWithPasteboard:session.draggingPasteboard];
        [dw setupDragAnimationWith:cv usingDragImage:image];
        [image release];
        NSRect frame = [cv frameForCell:self];
        frame = [cv convertRect:frame toView:nil];
        [dw setFrame:[cv.window convertRectToScreen:frame] display:NO];
    }
    */
    - (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
    {
        /*
        if (operation == NSDragOperationNone) {
            DragAnimationWindow* dw = [DragAnimationWindow sharedAnimationWindow];
            NSRect frame = dw.frame;
    
            NSPoint start = screenPoint;
            start.y += _dragImageOffset.y;
            start.x -= _dragImageOffset.x;
    
            [dw setFrameTopLeftPoint:start];
            [dw animateToFrame:frame];
        }*/
        // now tell the control view the drag ended so it can do any cleanup it needs
        // this is somewhat hackish
        [self.controlView draggingEnded:nil];
    }
    
    @end
    
  • 2

    可能问题是你用 NSPasteboardTypeString 调用 -setDataProvider:forTypes: 但是你的 -pasteboard:item:provideDataForType: 在传递那种类型时什么都不做?

相关问题