ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでドラッグ&ドロップを置き換える

 Xojo / Real Studio Trial and Error

CocoaのDeclareでドラッグ&ドロップを置き換える

目次
 はじめに

 以下は、Xojo Cocoaビルドについての話題です。

 ドラッグ&ドロップを、Xojoの機能を使わずに実現できるか試してみました。
 なお検証には、Xojo 2016 Release 3を用いています。(Mac mini mid 2010 + OS X 10.13.6 High Sierra)


 方針

 Xojoはドラッグ&ドロップに対応していて、本Trial and Errorでも、こちらこちらで利用しています。
 ですが、(その時は敢えて深入りしませんでしたが、)どうも意図した通りには動いていないようです。

 Xojo言語リファレンスの、ImageWellの項にあるサンプルをその通り再現しても、AcceptFileDropを記述すると、
 1. 指定したファイルタイプだけでなく、全てのファイル/フォルダが対象になる。(そもそも、ファイルタイプグループがなくても機能してしまう。)
 2. ピクチャークリッピングがファイルとしても読み込めてしまう。(AcceptPictureDropは機能しているので、obj.PictureAvailableをobj.FolderItemAvailableより前で判定すれば処理は可能。)
となってしまいます。

 同じことをReal Studio 2011 Release 3で試すと、期待通りの動作をすることから、おそらくXojoがCocoa対応した辺りで変わったものと思われます(詳細未調査)。
 この問題を解決しようとすると、純正コントロールのカスタマイズは難しそうなので、代替法はといえば、NSViewを使うことが考えられます。
 NSViewにおけるドラッグ&ドロップは、例えば以下のサイトが参考になります。(他にも沢山あります。)

 参考サイト(1):MacアプリTunacan開発の技術的メモ - Qiita

 情報を基に、前述のXojoサンプル相当機能を実装してみることにします。
 まずはXojoのAcceptFileDropに相当する(?)registerForDraggedTypes:ですが、public.file-url(注1)を指定して、全フォルダアイテムを対象とします。
注1)ググると、NSFilenamesPboardTypeを用いる例が多くヒットするが、既にDeprecatedになっている(とはいえ、10.14迄はOKなので暫くは大丈夫?)ので、代わりに用いることとした。ただしそうすると、propertyListForType:の戻り値はNSArrayではなく、(先頭の)NSStringになるようだ。
参考サイト(2):SSFlight: Swift 4に移行したらファイルのドラッグ時にパスが取り出せない?
 次にデリゲートメソッドですが、concludeDragOperationdraggingEnteredperformDragOperationprepareForDragOperationをオーバーライドします。
 prepareForDragOperationは、全てのインスタンスで常にtrueを返せばよさそうだったので、クラス側(共有メソッド)で処理することとしました。
 インスタンス側では、draggingEnteredでドラッグの可否判定(可の場合、カーソルに+印がつく)、performDragOperationでドロップの可否判定(否の場合、アイコンが元の場所に戻る)、concludeDragOperationでデータ処理を行います。

 NSViewは、Xojoのコントロールを完全に置き換えることも可能ですが、ここではドラッグ&ドロップのみをNSViewに任せ、残りはXojoのコントロール側で処理することとしました。
 NSViewをXojoのコントロールと同じ位置/サイズで置き、コントロール領域にドラッグされたものが処理対象となるようにします。

 以上を踏まえ、(残りの)仕様は以下の通りとしました。

 Xojoでの実装
【ソースコードのコピー&ペーストについて】
ソースコード(グレー背景部分の全文)をコピーし、指定のウィンドウ/クラスにペーストすると、(新規作成して名前等を個別にコピー&ペーストしなくても)復元されます。
ただし、この方法は、メソッドでは問題ないようですが、イベント/アクション/プロパティでは不安定?なので、ペーストできない場合は、各項目のカッコ内を適用して下さい。
  1. Xojoで新規プロジェクトを作成
  2. 新規クラス(名前は、ここでは「NSViewCanvas」)を作成し、Superを「Canvas」にする。
  3. 以下をNSViewCanvasにペースト(できなければ移譲に、デリゲート名:ActionDelegateC、引数:id As Ptr, SEL as CString, sender As Ptr、を追加)
    Private Sub ActionDelegateC(id As Ptr, SEL as CString, sender As Ptr)
    
  4. 以下をNSViewCanvasにペースト(できなければ移譲に、デリゲート名:ActionDelegateD、引数:id As Ptr, SEL as CString, sender As Ptr、戻り値型:Integer、を追加)
    Private Function ActionDelegateD(id As Ptr, SEL as CString, sender As Ptr) as Integer
    
  5. 以下をNSViewCanvasにペースト(できなければ移譲に、デリゲート名:ActionDelegateP、引数:id As Ptr, SEL as CString, sender As Ptr、戻り値型:Boolean、を追加)
    Private Function ActionDelegateP(id As Ptr, SEL as CString, sender As Ptr) as Boolean
    
  6. 以下をNSViewCanvasにペースト(できなければイベント定義に、イベント名:ConcludeDragOperation、引数:id As Ptr, SEL as CString, sender As Ptr、を追加)
    Event ConcludeDragOperation(id As Ptr, SEL as CString, sender As Ptr)
    
  7. 以下をNSViewCanvasにペースト(できなければイベント定義に、イベント名:DraggingEntered、引数:id As Ptr, SEL as CString, sender As Ptr、戻り値型:Integer、を追加)
    Event DraggingEntered(id As Ptr, SEL as CString, sender As Ptr) As Integer
    
  8. 以下をNSViewCanvasにペースト(できなければイベント定義に、イベント名:PerformDragOperation、引数:id As Ptr, SEL as CString, sender As Ptr、戻り値型:Boolean、を追加)
    Event PerformDragOperation(id As Ptr, SEL as CString, sender As Ptr) As Boolean
    
  9. 以下をNSViewCanvasにペースト
    Private Sub EventConcludeDrag(id As Ptr, SEL as CString, sender As Ptr)
      // イベントをレイズ
      RaiseEvent ConcludeDragOperation(id,SEL,sender)
    End Sub
    
  10. 以下をNSViewCanvasにペースト
    Private Function EventDragEntered(id As Ptr, SEL as CString, sender As Ptr) as Integer
      // イベントをレイズ
      return RaiseEvent DraggingEntered(id,SEL,sender)
    End Function
    
  11. 以下をNSViewCanvasにペースト
    Private Function EventPerformDrag(id As Ptr, SEL as CString, sender As Ptr) as Boolean
      // イベントをレイズ
      return RaiseEvent PerformDragOperation(id,SEL,sender)
    End Function
    
  12. 以下をNSViewCanvasにペースト
    Public Sub InitNSView(byRef inst As Ptr, win As Window, cnvs As Canvas)
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // NSViewを継承したカスタムクラスを作成。初回のみ
      makeClass()
      
      // インスタンスを作成
      Dim rect As NSRect = NSMakeRect(cnvs.Left, cnvs.Top, cnvs.Width, cnvs.Height)  // Canvasの位置/サイズに合わせる
      Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr
      Declare Function initWithFrame Lib "Cocoa" selector "initWithFrame:" (obj_id As Ptr, frame As NSRect) As Ptr
      Dim subclassId As Ptr = initWithFrame(alloc(NSVewClass), rect)
      
      // ドラッグ可能なタイプを指定
      Dim ary As Ptr = NSClassFromString("NSMutableArray")
      Declare Function getArray Lib "Cocoa" Selector "array" (receiver As Ptr) As Ptr
      ary = getArray(ary)
      Declare Sub addObjectStr Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As CFStringRef)
      addObjectStr(ary, "public.file-url")  // フォルダアイテム
      
      // ドラッグ可能なタイプをViewにセット
      Declare Sub registerForDraggedTypes Lib "Cocoa" Selector "registerForDraggedTypes:" (receiver As Ptr, obj As Ptr)
      registerForDraggedTypes(subclassId, ary)
      
      // ウィンドウのビューを取得
      Declare Function contentView Lib "Cocoa" selector "contentView" (class_id As Integer) As Ptr
      Dim pnt2 As Ptr = contentView(win.handle)
      
      // 生成したコントロールをビューに追加
      Declare Sub addSubview Lib "Cocoa" selector "addSubview:" (class_id As Ptr, view As Ptr)
      addSubview(pnt2, subclassId)
      
      // Canvasごとにイベントをレイズするメソッドを登録
      ActionHandlerC.Append AddressOf EventConcludeDrag
      ActionHandlerD.Append AddressOf EventDragEntered
      ActionHandlerP.Append AddressOf EventPerformDrag
        
      // インスタンスを保持
      inst = subclassId
      InstancePtr.Append subclassId
    End Sub
    
  13. 以下をNSViewCanvasにペースト(できなければプロパティに、名前:Inst、データ型:Ptr、を追加)
    Public Property Inst as Ptr
    
  14. 以下をNSViewCanvasにペースト
    Private Shared Function GetInstIdx(id As Ptr) as Integer
      // 登録したインスタンス数だけチェック
      for i As Integer = 0 to InstancePtr.Ubound
        
        // ポインタが一致したら
        if id=InstancePtr(i) then
          return i
        end if
        
      next
    End Function
    
  15. 以下をNSViewCanvasにペースト
    Private Shared Sub makeClass()
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      // Declare宣言
      Declare Function objc_allocateClassPair Lib "Cocoa" (superclass As Ptr, name As CString, extraBytes As Integer) as Ptr
      Declare Sub objc_registerClassPair Lib "Cocoa" (cls As Ptr)
      Declare Function class_addMethod Lib "Cocoa" (cls As Ptr, name As Ptr, imp As Ptr, types As CString) As Boolean
      
      // 既にクラス作成済なら戻る
      if NSVewClass <> nil then
        return
      end if
      
      // クラス名をmyNSView、メタクラス名をNSViewにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSView"), "myNSView", 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      // Delegateの対象となるメソッドを追加(drawRect:をXojo側で用意したmyDrawRectメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("drawRect:"), AddressOf myDrawRect, "v24@0:8@16") then
        msgBox "error6."
        return
      end if
      
      // Delegateの対象となるメソッドを追加(draggingEntered:をXojo側で用意したmyDraggingEnteredメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("draggingEntered:"), AddressOf myDraggingEntered, "v@0:@") then
        msgBox "error7."
        return
      end if
      // Delegateの対象となるメソッドを追加(prepareForDragOperation:をXojo側で用意したmyPrepareForDragOperationメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("prepareForDragOperation:"), AddressOf myPrepareForDragOperation, "v@0:@") then
        msgBox "error7."
        return
      end if
      // Delegateの対象となるメソッドを追加(performDragOperation:をXojo側で用意したmyPerformDragOperationtメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("performDragOperation:"), AddressOf myPerformDragOperation, "v@0:@") then
        msgBox "error7."
        return
      end if
      // Delegateの対象となるメソッドを追加(concludeDragOperation:をXojo側で用意したmyConcludeDragOperationメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("concludeDragOperation:"), AddressOf myConcludeDragOperation, "v@0:@") then
        msgBox "error7."
        return
      end if
      
      // クラスを保持
      NSVewClass = newClassId
    End Sub
    
  16. 以下をNSViewCanvasにペースト
    Private Shared Sub myConcludeDragOperation(id as Ptr, SEL as CString, sender As Ptr)
      // ドロップされたファイルを受け取って、処理する
      
      // idから、登録したインスタンスのインデックスを取得
      Dim idx As Integer = GetInstIdx(id)
      
      // 当該インスタンスの、Actionを受け取るメソッドを呼び出す
      ActionHandlerC(idx).Invoke(id,SEL,sender)
    End Sub
    
  17. 以下をNSViewCanvasにペースト
    Private Shared Function myDraggingEntered(id as Ptr, SEL as CString, sender As Ptr) as Integer
      // フォルダアイテムがビュー上にドラッグされた
      
      // idから、登録したインスタンスのインデックスを取得
      Dim idx As Integer = GetInstIdx(id)
      
      // 当該インスタンスの、Actionを受け取るメソッドを呼び出す
      return ActionHandlerD(idx).Invoke(id,SEL,sender)  // return = 0 : None , return = 1 : Copy
    End Function
    
  18. 以下をNSViewCanvasにペースト
    Private Shared Sub myDrawRect(id as Ptr, sel as CString, rect As NSRect)
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // 以下、デバッグ用。不要ならコメントアウトする --------------------
      
      // カラーの取得
      Dim clr As Ptr = NSClassFromString("NSColor")
      Declare Function colorWithRGBA Lib "Cocoa" Selector "colorWithRed:green:blue:alpha:" (receiver As Ptr, r As CGFloat, g As CGFloat, b As CGFloat, a As CGFloat) As Ptr
      clr = colorWithRGBA(clr, 1.0, 1.0, 1.0, 0.6)
      
      // 塗りつぶしカラーに指定
      Declare Sub mySet Lib "Cocoa" selector "set" (class_id As Ptr)
      mySet(clr)
      
      // rectを半透明で塗りつぶす
      Declare Sub NSRectFillUsingOperation Lib "AppKit" (aRect As NSRect, parm As Integer)
      NSRectFillUsingOperation(rect, 2)  // 2 = NSCompositeSourceOver
      
      // 以上、デバッグ用。不要ならコメントアウトする --------------------
      
      
      // superの取得
      dim sup As objc_super
      sup.receiver = id
      sup.pClass = NSClassFromString("NSView")
      
      // superに処理を渡す
      declare sub objc_msgSendSuper lib "Cocoa" (byref sup As objc_super, op As CString, rect As NSRect)
      objc_msgSendSuper(sup, sel, rect)
    End Sub
    
  19. 以下をNSViewCanvasにペースト
    Private Shared Function myPerformDragOperation(id as Ptr, SEL as CString, sender As Ptr) as Boolean
      // ドロップ処理を受け付けるかを返す
      
      // idから、登録したインスタンスのインデックスを取得
      Dim idx As Integer = GetInstIdx(id)
      
      // 当該インスタンスの、Actionを受け取るメソッドを呼び出す
      return ActionHandlerP(idx).Invoke(id,SEL,sender)
    End Function
    
  20. 以下をNSViewCanvasにペースト
    Private Shared Function myPrepareForDragOperation(id as Ptr, SEL as CString, sender As Ptr) as Boolean
      // ドロップの前処理
      
      return true  // 常にtrueを返せばよさそう
    End Function
    
  21. 以下をNSViewCanvasにペースト(できなければ共有プロパティに、名前:ActionHandlerC(-1)、データ型:ActionDelegateC、を追加)
    Private Shared Property ActionHandlerC(-1) as ActionDelegateC
    
  22. 以下をNSViewCanvasにペースト(できなければ共有プロパティに、名前:ActionHandlerD(-1)、データ型:ActionDelegateD、を追加)
    Private Shared Property ActionHandlerD(-1) as ActionDelegateD
    
  23. 以下をNSViewCanvasにペースト(できなければ共有プロパティに、名前:ActionHandlerP(-1)、データ型:ActionDelegateP、を追加)
    Private Shared Property ActionHandlerP(-1) as ActionDelegateP
    
  24. 以下をNSViewCanvasにペースト(できなければ共有プロパティに、名前:InstancePtr(-1)、データ型:Ptr、を追加)
    Private Shared Property InstancePtr(-1) as Ptr
    
  25. 以下をNSViewCanvasにペースト(できなければ共有プロパティに、名前:NSVewClass、データ型:Ptr、を追加)
    Private Shared Property NSVewClass as Ptr
    
  26. 以下をNSViewCanvasにペースト(できなければ構造体に、receiver As Ptr、pClass As Ptr、を追加)
    Private Structure objc_super
      receiver As Ptr
      pClass As Ptr
    End Structure
    
  27. Window1に、Canvas2個(Name:Canvas1, Super:NSViewCanvas、Name:Canvas2, Super:NSViewCanvas, Locking:右と下もロック)を追加
  28. 以下をCanvas1にペースト(できなければ、Sub - Endの間をConcludeDragOperationイベントに記述)
    Sub ConcludeDragOperation(id As Ptr, SEL as CString, sender As Ptr) Handles ConcludeDragOperation
      pic1 = GetPicture(id,SEL,sender,me.Inst)
      me.Refresh  // 描画
    End Sub
    
  29. 以下をCanvas1にペースト(できなければ、Sub - Endの間をDraggingEnteredイベントに記述)
    Function DraggingEntered(id As Ptr, SEL as CString, sender As Ptr) Handles DraggingEntered as Integer
      if ValidateDragCanvas(id,SEL,sender,"png") then
        return 1  // Copy
      else
        return 0  // None
      end if
    End Function
    
  30. 以下をCanvas1にペースト(できなければ、Sub - Endの間をOpenイベントに記述)
    Sub Open() Handles Open
      // NSView初期化。引数は順に、生成したインスタンス、配置するウィンドウ、自分自身
      Dim inst As Ptr
      me.InitNSView(inst,self,me)
      me.Inst=inst
      
      // NSViewのLockingの設定(8 = 下辺が可変(即ち、上辺を固定))
      Declare Sub setAutoresizingMask Lib "Cocoa" selector "setAutoresizingMask:" (class_id As Ptr, flg As Integer)
      setAutoresizingMask(inst, 8)
    End Sub
    
  31. 以下をCanvas1にペースト(できなければ、Sub - Endの間をPaintイベントに記述)
    Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint
      g.ForeColor=RGB(0,255,255)
      g.FillRect 0,0,me.Width,me.Height
      
      if pic1<>nil then
        g.DrawPicture pic1,0,0
      end if
    End Sub
    
  32. 以下をCanvas1にペースト(できなければ、Sub - Endの間をPerformDragOperationイベントに記述)
    Function PerformDragOperation(id As Ptr, SEL as CString, sender As Ptr) Handles PerformDragOperation as Boolean
      return ValidateDragCanvas(id,SEL,sender,"png")
    End Function
    
  33. 以下をCanvas2にペースト(できなければ、Sub - Endの間をConcludeDragOperationイベントに記述)
    Sub ConcludeDragOperation(id As Ptr, SEL as CString, sender As Ptr) Handles ConcludeDragOperation
      pic2 = GetPicture(id,SEL,sender,me.Inst)
      me.Refresh  // 描画
    End Sub
    
  34. 以下をCanvas2にペースト(できなければ、Sub - Endの間をDraggingEnteredイベントに記述)
    Function DraggingEntered(id As Ptr, SEL as CString, sender As Ptr) Handles DraggingEntered as Integer
      if ValidateDragCanvas(id,SEL,sender,"jpg") then
        return 1  // Copy
      else
        return 0  // None
      end if
    End Function
    
  35. 以下をCanvas2にペースト(できなければ、Sub - Endの間をOpenイベントに記述)
    Sub Open() Handles Open
      // NSView初期化。引数は順に、生成したインスタンス、配置するウィンドウ、自分自身
      Dim inst As Ptr
      me.InitNSView(inst,self,me)
      me.Inst=inst
      
      // NSViewのLockingの設定(2 = 幅が可変、16 = 高さが可変)
      Declare Sub setAutoresizingMask Lib "Cocoa" selector "setAutoresizingMask:" (class_id As Ptr, flg As Integer)
      setAutoresizingMask(inst, 2+16)
    End Sub
    
  36. 以下をCanvas2にペースト(できなければ、Sub - Endの間をPaintイベントに記述)
    Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint
      g.ForeColor=RGB(255,255,0)
      g.FillRect 0,0,me.Width,me.Height
      
      if pic2<>nil then
        g.DrawPicture pic2,0,0
      end if
    End Sub
    
  37. 以下をCanvas2にペースト(できなければ、Sub - Endの間をPerformDragOperationイベントに記述)
    Function PerformDragOperation(id As Ptr, SEL as CString, sender As Ptr) Handles PerformDragOperation as Boolean
      return ValidateDragCanvas(id,SEL,sender,"jpg")
    End Function
    
  38. 以下をWindow1にペースト
    Protected Function GetPicture(id As Ptr, SEL As Cstring, sender As Ptr, viewInst As Ptr) as Picture
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // ドラッグアイテムの取得
      Declare Function draggingPasteboard Lib "Cocoa" selector "draggingPasteboard" (class_id As Ptr) As Ptr
      Dim pBoard As Ptr = draggingPasteboard(sender)
      
      // zoneの取得
      Declare Function zone Lib "Cocoa" selector "zone" (class_id As Ptr) As Ptr
      Dim zn As Ptr = zone(viewInst)
      
      // ドラッグアイテムから画像の取得
      Dim img As Ptr = NSClassFromString("NSImage")
      Declare Function allocWithZone Lib "Cocoa" selector "allocWithZone:" (class_id As Ptr, zone As Ptr) As Ptr
      Declare Function initWithPasteboard Lib "Cocoa" selector "initWithPasteboard:" (class_id As Ptr, board As Ptr) As Ptr
      img = initWithPasteboard(allocWithZone(img, zn), pBoard)
      
      // NSImageをNSDataに変換する
      Declare Function TIFFRepresentation Lib "Cocoa" Selector "TIFFRepresentation" (receiver As Ptr) As Ptr
      Dim data As Ptr = TIFFRepresentation(img)
      
      // clean up
      Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
      release(img)
      
      // NSDataのデータ長を取得
      Declare Function length Lib "Cocoa" Selector "length" (receiver As Ptr) As Integer
      Dim lng As Integer = length(data)
      
      // NSDataからバイト列を抽出
      Declare Function bytes Lib "Cocoa" Selector "bytes" (receiver As Ptr) As Ptr
      Dim bstream As Ptr = bytes(data)
      
      // バイト列をXojo.Core.MemoryBlockに格納後、MemoryBlockに変換
      Dim xmb As new Xojo.Core.MemoryBlock(bstream, lng)
      Dim temp As MemoryBlock = xmb.Data
      Dim mb As New MemoryBlock(xmb.Size)
      mb.StringValue(0, mb.Size) = temp.StringValue(0, mb.Size)
      
      // MemoryBlockからPictureを生成して返す
      return Picture.FromData(mb)
    End Function
    
  39. 以下をWindow1にペースト
    Protected Function ValidateDragCanvas(id As Ptr, SEL As Cstring, sender As Ptr, extnRef As String) as Boolean
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // ドラッグされたオブジェクトの取得
      Declare Function draggingPasteboard Lib "Cocoa" selector "draggingPasteboard" (class_id As Ptr) As Ptr
      Dim pnt1 As Ptr = draggingPasteboard(sender)
      
      // ファイルパス(URL)の取得
      Declare Function propertyListForType Lib "Cocoa" selector "propertyListForType:" (class_id As Ptr, sender As CFStringRef) As CFStringRef
      Dim url As CFStringRef = propertyListForType(pnt1, "public.file-url")
      
      // 拡張子の取得
      Dim nsstr As Ptr = NSClassFromString("NSString")
      Declare Function stringWithString Lib "Cocoa" Selector "stringWithString:" (receiver As Ptr, string As CFStringRef) As Ptr
      Declare Function pathExtension Lib "Cocoa" Selector "pathExtension" (receiver As Ptr) As CFStringRef
      Dim extnF As String = pathExtension(stringWithString(nsstr, url))
        
      // ファイルの拡張子が指定されたものならtrue、それ以外はfalse
      if extnF=extnRef then
        return true
      else
        return false
      end if
    End Function
    
  40. 以下をWindow1にペースト(できなければプロパティに、名前:pic1、データ型:Picture、を追加)
    Protected Property pic1 as Picture
    
  41. 以下をWindow1にペースト(できなければプロパティに、名前:pic2、データ型:Picture、を追加)
    Protected Property pic2 as Picture
    
  42. 他に、NSMakeRect(メソッド)、NSRect(構造体)が必要ですが、それらはmacoslibからコピーさせて頂きました。(上記NSViewCanvasまたは別途モジュールを用意してコピーする。)
 実行してみたところ、ドラッグ&ドロップが機能することを確認しました。


 おわりに

 複数ファイルのドロップ対応とか、ファイル種別判定周りをもう少しきめ細かくする(注2)とか、手を加える箇所はありそうです。
注2)例えば「file」コマンドを使うと、ファイルの中身をチェックして種別を判定できるとのこと。
参考サイト(3):拡張子を偽るPNGファイルを見破るfileコマンド - Qiita
 とはいえ、純正のままでも、ドロップ受付後に判定して対象外はメッセージを出して受付ない、とかすれば実用上は問題ない(かもしれない)ので、置き換え自体、有用性が薄いかも。


 お世話になったサイト

 貴重な情報をご提供頂いている皆様に、お礼申し上げます。(以下、順不同)

 参考サイト(1):MacアプリTunacan開発の技術的メモ - Qiita
 参考サイト(2):SSFlight: Swift 4に移行したらファイルのドラッグ時にパスが取り出せない?
 参考サイト(3):拡張子を偽るPNGファイルを見破るfileコマンド - Qiita


 更新履歴

 2019.05.07 新規作成


[Home]  [MacSoft]  [Donation]  [History]  [Privacy Policy]  [Affiliate Policy]