ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでツールバーを実装する・OS標準っぽくしてみる

 Xojo / Real Studio Trial and Error

CocoaのDeclareでツールバーを実装する・OS標準っぽくしてみる

目次
 はじめに

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

 OS標準添付のアプリやFinderのツールバーっぽくできるのか、試してみました。

 なお検証には、Xojo 2016 Release 3を用いています。(Mac mini mid 2010 + OS X 10.11.6 El Capitan)


 方針

 例えばFinderのツールバーは、以下の通りです。
S Shot1
 (離れてはいますが)左の二つはセグメンテッドコントロールだろうなぁ、と想像できますが、(サーチフィールドを除いた)残りは何なのかが判然としません。
 特にメニューを表示するものは、メニューがあることを示す「下向きの山型」があることから、ポップアップメニューの可能性もあります。

 ということで、試しに通常のボタン(NSButton)とポップアップメニュー(NSPopupButton)をツールバーに配置してみました。
S Shot2
 が、ちょっと違います。
 各コントロールの高さは全て24 pixelに統一してありますが、Finderのようには揃いません。
(ちなみに、5 pixel足してやるとコントロールの高さは一致するものの、今度はツールバーの高さが2 pixel増えてしまいます。)
 何かパラメータをいじればいいのかもしれませんが、見つけられませんでした。

 一方、セグメンテッドコントロールはセグメントを1個にすると、通常のボタンのように見えます。また、メニューを付加することもできます。
 なので、(サーチフィールド以外を)全てセグメンテッドコントロールで実装してみたところ、以下の通りとなりました。
S Shot3
注:「アイコンのみ」の表示にしてあります。「並び順序」と「タグ」は当該アイコンが見つからなかったので、別アイコンを割り当てています。

 したがって、今回はボタン類を全てセグメンテッドコントロールで実装することにしました。

 ただし、セグメンテッドコントロールは、(デフォルトでは)ボタンを押すと押しっぱなしの状態になるため、そうならないようにしてやる必要が生じます。
 何かパラメータがあるかと思って探したのですが、見当たらなかったので、今回は、ボタンが押された後に自分で戻すようにしました。
 ボタンの有効/無効は、通常のツールバーボタンであればデリゲートメソッドで対応できるのですが、コントロール類の場合は対象外(注1)のため、今回は直接Enabledをいじることとしました。
注1)validateVisibleItemsを使う方法はあるようですが、今回は試していません。
参考サイト(1):cocoa - How to force NSToolBar validation? - Stack Overflow
 また、メニュー選択時のアクションは、ボタンと同じアクションで拾うことにし、メニューの判別は、こちらもタグを使うこととしました。(コントロール種別が異なるので、タグの数値は同じアクションを使うメニュー内で固有であればよい。)
 メニューの有効/無効は、デリゲートメソッドでの対応となります(この辺は、通常のメニューと同様)。

 次にアイコンですが、今回はOS標準アイコンを利用することにしました。
 利用にあたっては、参考サイト(2)を参考にさせて頂きました。
 また、アイコンは名前がTemplateで終わっているものを使いましたが、理由は参考サイト(3)に記されています。

 参考サイト(2):Fucking NSImage Syntax
 参考サイト(3):OS Xステータスバーアプリケーションの作り方 — Genji App Blog(ステータス項目を表示する、の5.項)

 残りの(主な)方針は、以下の通りとしました。

 Xojoでの実装
【ソースコードのコピー&ペーストについて】
ソースコード(グレー背景部分の全文)をコピーし、指定のウィンドウ/クラスにペーストすると、(新規作成して名前等を個別にコピー&ペーストしなくても)復元されます。
ただし、この方法は、メソッドでは問題ないようですが、イベント/アクション/プロパティでは不安定?なので、ペーストできない場合は、各項目のカッコ内を適用して下さい。
  1. Xojoで新規プロジェクトを作成
  2. Window1にListBox(名前はListBox1)、PushButton2個(名前はPushButton1とPushButton2)を追加(注:動作確認用であり、必須ではない。)
  3. 以下をPushButton1にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      SetButtonEnable(601,not GetButtonEnable(601))
    End Sub
    
  4. 以下をPushButton2にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      EnableNewWin = not EnableNewWin
    End Sub
    
  5. 以下をWindow1にペースト(できなければ、Sub - Endの間をOpenイベントに記述)
    Sub Open() Handles Open
      // ツールバー生成
      Dim t As NSToolbar = new NSToolbar(self, AddressOf ToolbarItemClicked, AddressOf MenuItemClicked)
    End Sub
    
  6. 以下をWindow1にペースト
    Protected Function GetButtonEnable(tagNo As Integer) as Boolean
      // 指定されたタグ番号を持つアイテムを取得
      Dim pnt As Ptr = GetToolItem(tagNo)
      
      // 現在の有効/無効値を取得して返す
      Declare Function isEnabled Lib "Cocoa" Selector "isEnabled" (receiver As Ptr) As Boolean
      return isEnabled(pnt)
    End Function
    
  7. 以下をWindow1にペースト
    Protected Function GetToolItem(tagNo As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSStringFromClass Lib "Cocoa" (aClass As Ptr) As CFStringRef
      
      Declare Function myClass Lib "Cocoa" Selector "class" (receiver As Ptr) As Ptr
      Declare Function objectAtIndex Lib "Cocoa" Selector "objectAtIndex:" (receiver As Ptr, info As Integer) As Ptr
      Declare Function view Lib "Cocoa" Selector "view" (receiver As Ptr) As Ptr
      Declare Function itemIdentifier Lib "Cocoa" Selector "itemIdentifier" (receiver As Ptr) As Ptr
      Declare Function tagForSegment Lib "Cocoa" Selector "tagForSegment:" (receiver As Ptr, seg As Integer) As Integer
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      
      // ツールバーの取得
      declare function toolbar lib "Cocoa" selector "toolbar" (obj_id as Integer) as Ptr
      Dim pnt1 As Ptr = toolbar(Window1.Handle)
      
      // ツールバーアイテム(配列)の取得
      declare function visibleItems lib "Cocoa" selector "visibleItems" (receiver As Ptr) as Ptr
      Dim pnt2 As Ptr = visibleItems(pnt1)
      
      // 配列の個数の取得
      declare function count lib "Cocoa" selector "count" (receiver As Ptr) as Integer
      Dim cnt As Integer = count(pnt2)
      
      Dim i, tag As Integer
      Dim pnt3, ident, pnt4, cls1 As Ptr
      for i=0 to cnt-1
        
        // ツールバーアイテムを順番に取得
        pnt3 = objectAtIndex(pnt2, i)
        
        // 渡ってきたツールバーアイテムからアイデンティファイアを取得
        ident = itemIdentifier(pnt3)
        
        // viewの取得(コントロール類はviewで取得できる)
        pnt4 = view(pnt3)
        
        // コントロールのクラス名を文字列で取得
        cls1 = myClass(pnt4)
        
        if NSStringFromClass(cls1)="NSSegmentedControl" then  // セグメンテッドコントロール
          
          tag = tagForSegment(cell(pnt4),0)
          if tag=tagNo then  // 指定されたタグなら
            return pnt3  // 現在の値を取得
          end if
          
        end if
        
      next
    End Function
    
  8. 以下をWindow1にペースト
    Protected Function MenuItemClicked(sender As Ptr) as Boolean
      // このメソッドはメニューが表示される度に呼ばれる(?)ので、戻り値を指定すれば反映される。
      
      // デフォルトはEnable
      Dim enable As Boolean = true
      
      // 渡ってきたメニューアイテムからタグを取得
      Declare Function tag Lib "Cocoa" Selector "tag" (receiver As Ptr) As Integer
      Dim tagno As Integer = tag(sender)
      
      // メニューアイテム(タグ)ごとの処理
      select case tagno
      case 101  // 名前
        
      case 102  // 種類
        
      case 201  // 新規フォルダ
        
      case 202  // 新規ウィンドウで開く
        
        // フラグが無効ならDisableに
        if EnableNewWin then
          enable = false
        end if
        
      end select
      
      return enable
    End Function
    
  9. 以下をWindow1にペースト
    Protected Sub SetButtonEnable(tagNo As Integer, flg As Boolean)
      // 指定されたタグ番号を持つアイテムを取得
      Dim pnt As Ptr = GetToolItem(tagNo)
      
      // 値をセット
      Declare Sub setEnabled Lib "Cocoa" Selector "setEnabled:" (receiver As Ptr, selected As Boolean)
      setEnabled(pnt, flg)
    End Sub
    
  10. 以下をWindow1にペースト
    Protected Sub ToolbarItemClicked(sender As Ptr)
      Declare Function description Lib "Cocoa" Selector "description" (receiver As Ptr) As CFStringRef
      
      Dim name As String = description(sender)
      if InStrB(name,"NSSegmentedControl")>0 then  // セグメンテッドコントロール(ボタン型やメニュー型を含む)
        
        Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
        Declare Function tagForSegment Lib "Cocoa" Selector "tagForSegment:" (receiver As Ptr, seg As Integer) As Integer
        Declare Function selectedSegment Lib "Cocoa" Selector "selectedSegment" (receiver As Ptr) As Integer
        Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
        Dim tagno As Integer = tagForSegment(cell(sender), selectedSegment(sender))
        select case tagno
        case 501
          Listbox1.AddRow "Selected Segment = Icon View"
        case 502
          Listbox1.AddRow "Selected Segment = List View"
        case 503
          Listbox1.AddRow "Selected Segment = Column View"
        case 504
          Listbox1.AddRow "Selected Segment = Flow View"
          
        case 601
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Share"
          
        case 611
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Edit Tag"
          
        case 621
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Quick Look"
          
        case 701
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Go Left"
        case 702
          setSelected(sender, false, 1)
          Listbox1.AddRow "Selected Button = Go Right"
          
        end select
        
      elseif InStrB(name,"NSMenuItem")>0 then  // ボタンのメニュー
        
        Declare Function tag Lib "Cocoa" Selector "tag" (receiver As Ptr) As Integer
        Dim tagno As Integer = tag(sender)
        select case tagno
        case 101  // 名前
          Listbox1.AddRow "Selected Menu = 名前"
        case 102  // 種類
          Listbox1.AddRow "Selected Menu = 種類"
        case 104  // なし
          Listbox1.AddRow "Selected Menu = なし"
          
        case 201  // 新規フォルダ
          Listbox1.AddRow "Selected Menu = 新規フォルダ"
        case 202  // 新規ウィンドウで開く
          Listbox1.AddRow "Selected Menu = 新規ウィンドウで開く"
        case 901  // 開く 1
          Listbox1.AddRow "Selected Menu = 開く 1"
        case 902  // 開く 2
          Listbox1.AddRow "Selected Menu = 開く 2"
        end select
        
      elseif InStrB(name,"NSSearchField")>0 then  // サーチフィールド
        
        Declare Function stringValue Lib "Cocoa" Selector "stringValue" (receiver As Ptr) As CFStringRef
        Listbox1.AddRow "Search Word = "+stringValue(sender)  // 検索文字列
        
      else
        msgBox "No Define :"+name
      end if
      
    End Sub
    
  11. 以下をWindow1にペースト(できなければプロパティに、名前:EnableNewWin、データ型:Boolean、を追加)
    Private Property EnableNewWin as Boolean
    
  12. 新規クラスを作成(名前は、ここでは「NSToolbar」とした。)
  13. 以下をNSToolbarにペースト(できなければ移譲に、名前:ActionDelegate、引数:sender As Ptr、を追加)
    Private Sub ActionDelegate(sender As Ptr)
    
  14. 以下をNSToolbarにペースト(できなければ移譲に、名前:ActionDelegate1、引数:sender As Ptr、戻り値型:Booleanを追加)
    Private Function ActionDelegate1(sender As Ptr) as Boolean
    
  15. 以下をNSToolbarにペースト
    Public Sub Constructor(win As Window, action As ActionDelegate, action1 As ActionDelegate1)
      
      // NSToolbarを継承したインスタンスを作成して、ウィンドウに貼り付ける
      makeToolbarInstance(win)
      
      // 外部指定されたパラメータを保持
      ActionHandler = action  // クラス生成元でActionを受け取るメソッドを登録
      ActionHandler1 = action1  // クラス生成元でActionを受け取るメソッドを登録
    End Sub
    
  16. 以下をNSToolbarにペースト
    Private Shared Sub actionEvent(id As Ptr, SEL As CString, sender As Ptr)
      // インスタンスメソッドに渡す
      ActionHandler.Invoke(sender)  // クラス生成元でActionを受け取るメソッドを呼び出す
    End Sub
    
    注)SELの型をPtrとしていたが、CStringの方が相応しいので変更した。(未使用なので変更しなくても実害はなし。)(2018.07.30)
  17. 以下をNSToolbarにペースト
    Private Shared Function makeDelegate() as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      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
      
      // クラス名をmyNSToolbarDelegate(名前は任意。少なくとも今回のケースでは参照されない。)、メタクラス名をNSObjectにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), "myNSToolbarDelegate", 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      // Delegateの対象となるメソッドを追加(toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:をXojo側で用意したtoolbarItemForItemIdentifierWillBeInsertedIntoToolbarメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:"), AddressOf toolbarItemForItemIdentifierWillBeInsertedIntoToolbar, "@@:@@c") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッドを追加(toolbarAllowedItemIdentifiers:をXojo側で用意したtoolbarAllowedItemIdentifiersメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbarAllowedItemIdentifiers:"), AddressOf toolbarAllowedItemIdentifiers, "@@:@") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッドを追加(toolbarDefaultItemIdentifiers:をXojo側で用意したtoolbarDefaultItemIdentifiersメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbarDefaultItemIdentifiers:"), AddressOf toolbarDefaultItemIdentifiers, "@@:@") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッドを追加(toolbarSelectableItemIdentifiers:をXojo側で用意したtoolbarSelectableItemIdentifiersメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbarSelectableItemIdentifiers:"), AddressOf toolbarSelectableItemIdentifiers, "@@:@") then
        msgBox "error."
        return nil
      end if
      
      // 上記で生成したクラスのインスタンスを作成
      Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr
      Declare Function init Lib "Cocoa" selector "init" (obj_id As Ptr) As Ptr
      Dim delegateId As Ptr = init(alloc(newClassId))
      
      // インスタンスを返す
      return delegateId
    End Function
    
  18. 以下をNSToolbarにペースト
    Private Shared Function makeMenu(itemIdentifier As String, list() As String, tag0 As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      Declare Function init Lib "Cocoa" Selector "init" (receiver As Ptr) As Ptr
      Declare Function initWithTitleActKey Lib "Cocoa" Selector "initWithTitle:action:keyEquivalent:" (receiver As Ptr, title As CFStringRef, act As Ptr, key As CFStringRef) As Ptr
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      Declare Sub setTitle Lib "Cocoa" Selector "setTitle:" (receiver As Ptr, title As CFStringRef)
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      Declare Sub setTag Lib "Cocoa" Selector "setTag:" (receiver As Ptr, tag As Integer)
      Declare Sub setSubmenu Lib "Cocoa" Selector "setSubmenu:" (receiver As Ptr, item As Ptr)
      Declare Sub addItem Lib "Cocoa" Selector "addItem:" (receiver As Ptr, item As Ptr)
      Declare Function separatorItem Lib "Cocoa" Selector "separatorItem" (receiver As Ptr) As Ptr
      Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
      
      // メニューの生成と初期化
      Dim menu1 As Ptr = NSClassFromString("NSMenu")
      menu1 = alloc(menu1)
      menu1 = init(menu1)
      
      // メニュー項目
      Dim menu2, menu20, menu21 As Ptr
      Dim pos, j, cnt As Integer
      pos=0
      do
        
        // メニュー項目クラスの取得
        menu2 = NSClassFromString("NSMenuItem")
        
        if list(pos)="---" then  // セパレータ
          
          menu2 = separatorItem(menu2)
          
        elseif Left(list(pos),4)="sub:" then  // サブメニューを持ったメニュー
          
          // メニュー項目の生成と初期化
          menu2 = alloc(menu2)
          menu2 = init(menu2)
          setTitle(menu2, NthField(list(pos),":",3))
          // Target/Actionを設定
          setTarget(menu2, makeTarget(itemIdentifier))
          setAction(menu2, NSSelectorFromString("action:"))
          // メニューの生成と初期化(サブメニューはメニューに付加する)
          menu20 = NSClassFromString("NSMenu")
          menu20 = alloc(menu20)
          menu20 = init(menu20)
          
          cnt=Val(NthField(list(pos),":",2))
          for j=1 to cnt
            
            // サブメニューを生成
            menu21 = NSClassFromString("NSMenuItem")
            menu21 = alloc(menu21)
            menu21 = initWithTitleActKey(menu21, list(pos+j), NSSelectorFromString("action:"), "")  // ここでActionも設定
            // Targetを設定
            setTarget(menu21, makeTarget(itemIdentifier))
            // タグ
            setTag(menu21, 900+j)  // タグだけ判別するので、同じActionメソッドを使用するメニュー間で固有の数値にする(今回の例では一つしかないので決め打ちしているが、複数ある場合は工夫が必要)
            // メニューにサブメニューを追加
            addItem(menu20, menu21)
            // 解放
            release(menu21)
            
          next
          pos=pos+cnt
          
          // メニュー項目にメニュー(サブメニューを持っている)をセット
          setSubmenu(menu2, menu20)
          // 解放
          release(menu20)
          
        else  // 通常のメニュー
          
          // メニュー項目の生成と初期化
          menu2 = alloc(menu2)
          menu2 = initWithTitleActKey(menu2, list(pos), NSSelectorFromString("action:"), "")  // ここでActionも設定
          // Targetを設定
          setTarget(menu2, makeTarget(itemIdentifier))
          // タグ
          setTag(menu2, tag0+pos)  // タグだけ判別するので、同じActionメソッドを使用するメニュー間で固有の数値にする
          
        end if
        
        // メニューにメニュー項目を追加
        addItem(menu1, menu2)
        
        // リストが終了したら抜ける
        pos=pos+1
        if pos>list.Ubound then
          exit
        end if
        
      loop
      
      // メニューを返す
      return menu1
    End Function
    
  19. 以下をNSToolbarにペースト
    Private Shared Function makeMenuAction(itemIdentifier As String) as Ptr
      Dim list(-1) As String
      
      // サブメニューとセパレータの仕様は独自のものです。必要なら適宜変更して下さい。
      list.Append "新規フォルダ"
      list.Append "新規ウィンドウで開く"
      list.Append "sub:2:開く"  // sub = サブメニューあり, 2 = サブメニュー個数
      list.Append "開く 1"  // サブメニュー1個目
      list.Append "開く 2"  // サブメニュー2個目
      list.Append "閉じる"
      
      return makeMenu(itemIdentifier,list,201)
    End Function
    
  20. 以下をNSToolbarにペースト
    Private Shared Function makeMenuSort(itemIdentifier As String) as Ptr
      Dim list(-1) As String
      
      // サブメニューとセパレータの仕様は独自のものです。必要なら適宜変更して下さい。
      list.Append "名前"
      list.Append "種類"
      list.Append "---"  // セパレータを示す
      list.Append "なし"
      
      return makeMenu(itemIdentifier,list,101)
    End Function
    
  21. 以下をNSToolbarにペースト
    Private Shared Function makeTarget(name As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      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 TargetInstance <> nil then
        return TargetInstance
      end if
      
      // クラス名を引数のname(名前は任意だが、重複を避けるためにアイテムのIdentifierにしている。)、メタクラス名をNSObjectにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), name, 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      // Tarrgetに送られてきたActionの受け口となるメソッドを追加(action:をXojo側で用意したactionEventメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("action:"), AddressOf actionEvent, "@@:@") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッド(Protocol?)を追加(validateMenuItem:をXojo側で用意したvalidateMenuItemメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("validateMenuItem:"), AddressOf validateMenuItem, "c@:@") then
        msgBox "error."
        return nil
      end if
      
      // 上記で生成したクラスのインスタンスを作成
      Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr
      Declare Function init Lib "Cocoa" selector "init" (obj_id As Ptr) As Ptr
      Dim targetId As Ptr = init(alloc(newClassId))
      
      // インスタンスを保持
      TargetInstance = targetId
      
      // インスタンスを返す
      return targetId
    End Function
    
  22. 以下をNSToolbarにペースト
    Private Shared Sub makeToolbarInstance(win As Window)
      
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      // create the toolbar object
      Dim toolbar1 As Ptr = NSClassFromString("NSToolbar")
      Declare Function toolbarAlloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      toolbar1 = toolbarAlloc(toolbar1)
      Declare Function toolbarInit Lib "Cocoa" Selector "initWithIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbar1 = toolbarInit(toolbar1, "MySampleToolbar")
      
      // set initial toolbar properties
      Declare Sub setAllowsUserCustomization Lib "Cocoa" Selector "setAllowsUserCustomization:" (receiver As Ptr, value As Boolean)
      setAllowsUserCustomization(toolbar1, true)
      Declare Sub setAutosavesConfiguration Lib "Cocoa" Selector "setAutosavesConfiguration:" (receiver As Ptr, value As Boolean)
      setAutosavesConfiguration(toolbar1, false)  // debug時にはoffの方がよさそう
      Declare Sub setDisplayMode Lib "Cocoa" Selector "setDisplayMode:" (receiver As Ptr, value As Integer)
      setDisplayMode(toolbar1, 1)  // 0=Default, 1=Icon & Text, 2=Icon Only, 3=Text Only
      
      // set our controller as the toolbar delegate
      Declare Sub setDelegate Lib "Cocoa" Selector "setDelegate:" (receiver As Ptr, id As Ptr)
      setDelegate toolbar1, makeDelegate()  // Delegateの設定
      
      // attach the toolbar to our window
      Declare Sub setToolbar Lib "Cocoa" Selector "setToolbar:" (receiver As WindowPtr, toolbar As Ptr)
      setToolbar(win, toolbar1)
      
      // clean up
      Declare Sub release Lib "Cocoa" Selector "release" (toolbar As Ptr)
      release(toolbar1)
    End Sub
    
  23. 以下をNSToolbarにペースト(大幅に改訂(2018.01.17))
    Private Shared Function setToolItemSearch(itemIdentifier As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // サーチフィールド初期化
      Dim search1 As Ptr = NSClassFromString("NSSearchField")
      search1 = alloc(search1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      search1 = initWithFrame(search1, NSMakeRect(0,0,150,24))
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, "NSSearchField")
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, "Search")
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, "Search Your Document")
      
      // サーチフィールドクリック後、直ちに文字入力を可能とするための設定
      Declare Sub refusesFirstResponder Lib "Cocoa" Selector "setRefusesFirstResponder:" (receiver As Ptr, flg As Boolean)
      refusesFirstResponder(search1,true)
      
      // アイテムのビューにサーチフィールドを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, search1)
      
      // Target/Action設定
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(search1, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(search1, NSSelectorFromString("action:"))
      
      // 検索オプション設定(本サンプルでは、Retrnキーを押した時点でActionが発生、を選択)
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Dim cell1 As Ptr = cell(search1)  // NSSearchFieldCellを取得
      Declare Sub setSendsWholeSearchString Lib "Cocoa" Selector "setSendsWholeSearchString:" (receiver As Ptr, flag As Boolean)
      setSendsWholeSearchString(cell1, true)  // false:キーストローク毎にActionが発生, true:Retrnキーを押した時点でActionが発生
      Declare Sub sendsSearchStringImmediately Lib "Cocoa" Selector "setSendsSearchStringImmediately:" (receiver As Ptr, flag As Boolean)
      sendsSearchStringImmediately(cell1, false)  // false:文字をある程度溜めてからActionが発生, true:文字を入力すると直ちにActionが発生
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  24. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSegment(itemIdentifier As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      Dim image0 As Ptr = NSClassFromString("NSImage")
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Dim image2 As Ptr = NSClassFromString("NSImage")
      Dim image3 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image0 = imageNamed(image0, "NSIconViewTemplate")
      image1 = imageNamed(image1, "NSListViewTemplate")
      image2 = imageNamed(image2, "NSColumnViewTemplate")
      image3 = imageNamed(image3, "NSFlowViewTemplate")
      
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,111,24))
      
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 4)
      
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image0, 0)
      setImage(segment1, image1, 1)
      setImage(segment1, image2, 2)
      setImage(segment1, image3, 3)
      
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As Single, no As Integer)
      setWidth(segment1, 26, 0)
      setWidth(segment1, 26, 1)
      setWidth(segment1, 26, 2)
      setWidth(segment1, 26, 3)
      
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, true, 0)
      setSelected(segment1, false, 1)
      setSelected(segment1, false, 2)
      setSelected(segment1, false, 3)
      
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setTag Lib "Cocoa" Selector "setTag:forSegment:" (receiver As Ptr, tag As Integer, no As Integer)
      setTag(cell(segment1), 501, 0)
      setTag(cell(segment1), 502, 1)
      setTag(cell(segment1), 503, 2)
      setTag(cell(segment1), 504, 3)
      
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:forSegment:" (receiver As Ptr, text As CFStringRef, no As Integer)
      setToolTip(cell(segment1), "Segmented Control 0", 0)
      setToolTip(cell(segment1), "Segmented Control 1", 1)
      setToolTip(cell(segment1), "Segmented Control 2", 2)
      setToolTip(cell(segment1), "Segmented Control 3", 3)
      
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, "NSSegmentedControl")
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, "Segmented Control")
      
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(toolbarItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(toolbarItem, NSSelectorFromString("action:"))
      
      return toolbarItem
    End Function
    
  25. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSegment1(itemIdentifier As String, label As String, labelL As String, tooltip As String, icon As String, tag As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image1 = imageNamed(image1, icon)
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,38,24))
      
      // セグメント数/アイコン/幅/選択状態/タグ設定
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 1)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image1, 0)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As Single, no As Integer)
      setWidth(segment1, 34, 0)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)  // 非選択
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setTag Lib "Cocoa" Selector "setTag:forSegment:" (receiver As Ptr, tag As Integer, no As Integer)
      setTag(cell(segment1), tag, 0)  // タグだけ判別するので、同じActionメソッドを使用するセグメント間で固有の数値にする
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, label)
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, labelL)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, tooltip)
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      // Target/Action設定
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(toolbarItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(toolbarItem, NSSelectorFromString("action:"))
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  26. 以下をNSToolbarにペースト(メニューを示す下向き矢印の表示を、標準機能に改めた。(2021.05.11))
    Private Shared Function setToolItemSegment1Menu(itemIdentifier As String, label As String, labelL As String, tooltip As String, icon As String, menu As Ptr) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // 標準イメージの取得
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image1 = imageNamed(image1, icon)
      Declare Sub setTemplate Lib "Cocoa" Selector "setTemplate:" (receiver As Ptr, flg As Boolean)
      setTemplate(image1, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,40,22))
      
      // セグメント数/イメージ/選択状態/メニュー
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 1)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image1, 0)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As CGFloat, no As Integer)
      setWidth(segment1, 36, 0)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)  // 非選択
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setMenu Lib "Cocoa" Selector "setMenu:forSegment:" (receiver As Ptr, menu As Ptr, no As Integer)
      setMenu(cell(segment1), menu, 0)
      Declare Sub setShowsMenuIndicator Lib "Cocoa" Selector "setShowsMenuIndicator:forSegment:" (receiver As Ptr, flg As Boolean, no As Integer)
      setShowsMenuIndicator(segment1, true, 0)  // メニューを示す下向き矢印表示
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, label)
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, labelL)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, labelL)
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
    以下の旧版は、実装方法の一つではあるので、参考まで。
    Private Shared Function setToolItemSegment1Menu(itemIdentifier As String, label As String, labelL As String, tooltip As String, icon As String, menu As Ptr) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // イメージの生成(標準イメージを貼り付けるベース)
      Dim image0 As Ptr = NSClassFromString("NSImage")
      image0 = alloc(image0)
      Declare Function initWithSize Lib "Cocoa" Selector "initWithSize:" (receiver As Ptr, size As NSSize) As Ptr
      image0 = initWithSize(image0, NSMakeSize(40,24))
      
      // 標準イメージの取得
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Dim image2 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image1 = imageNamed(image1, icon)
      image2 = imageNamed(image2, "NSDropDownIndicatorTemplate")
      
      // イメージの合成
      Declare Sub lockFocus Lib "Cocoa" Selector "lockFocus" (receiver As Ptr)
      lockFocus(image0)
      Declare Sub compositeToPoint Lib "Cocoa" Selector "compositeToPoint:operation:" (receiver As Ptr, item1 As NSPoint, item2 As Integer)
      compositeToPoint(image1, NSMakePoint(5, 5), 2)
      compositeToPoint(image2, NSMakePoint(25, 10), 2)
      Declare Sub unlockFocus Lib "Cocoa" Selector "unlockFocus" (receiver As Ptr)
      unlockFocus(image0)
      
      Declare Sub setTemplate Lib "Cocoa" Selector "setTemplate:" (receiver As Ptr, flg As Boolean)
      setTemplate(image0, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,40,22))
      
      // セグメント数/アイコン/幅/選択状態/メニュー
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 1)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image0, 0)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As Single, no As Integer)
      setWidth(segment1, 36, 0)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)  // 非選択
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setMenu Lib "Cocoa" Selector "setMenu:forSegment:" (receiver As Ptr, menu As Ptr, no As Integer)
      setMenu(cell(segment1), menu, 0)
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, label)
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, labelL)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, labelL)
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  27. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSegmentPair(itemIdentifier As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // 標準イメージの取得
      Dim image0 As Ptr = NSClassFromString("NSImage")
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image0 = imageNamed(image0, "NSGoLeftTemplate")
      image1 = imageNamed(image1, "NSGoRightTemplate")
      Declare Sub setTemplate Lib "Cocoa" Selector "setTemplate:" (receiver As Ptr, flg As Boolean)
      setTemplate(image0, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      setTemplate(image1, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,51,24))
      
      // セグメント数/外観/アイコン/幅/選択状態/ツールチップ
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 2)
      Declare Sub setSegmentStyle Lib "Cocoa" Selector "setSegmentStyle:" (receiver As Ptr, cnt As Integer)
      setSegmentStyle(segment1, 8)  // 8だとImageのTemplateが効かない > OS標準でもそのようなので仕様?
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image0, 0)
      setImage(segment1, image1, 1)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As Single, no As Integer)
      setWidth(segment1, 23, 0)
      setWidth(segment1, 23, 1)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)
      setSelected(segment1, false, 1)
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setTag Lib "Cocoa" Selector "setTag:forSegment:" (receiver As Ptr, tag As Integer, no As Integer)
      setTag(cell(segment1), 701, 0)
      setTag(cell(segment1), 702, 1)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:forSegment:" (receiver As Ptr, text As CFStringRef, no As Integer)
      setToolTip(cell(segment1), "Segmented Control 0", 0)
      setToolTip(cell(segment1), "Segmented Control 1", 1)
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, "Button Pair")
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, "Button Pair")
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(toolbarItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(toolbarItem, NSSelectorFromString("action:"))
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  28. 以下をNSToolbarにペースト
    Private Shared Function toolbarAllowedItemIdentifiers(id As Ptr, SEL As CString, toolbar As Ptr) as Ptr
      // カスタマイズダイアログのアイテムの並びを規定
      
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      Dim arr As Ptr = NSClassFromString("NSMutableArray")  // クラスメソッドなので、まずNSMutableArrayクラスを取得
      Declare Function getArray Lib "Cocoa" Selector "array" (receiver As Ptr) As Ptr  // Return Array*
      arr=getArray(arr)
      
      Declare Sub addObject Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As CFStringRef)
      Declare Sub addObjectNil Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As Ptr)
      
      addObject(arr, SegmentedControlPairToolbarItemIdentifier)  // ユーザ定義アイテム
      addObject(arr, SegmentedControlToolbarItemIdentifier)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierSort)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierShare)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierTag)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierQuick)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierAction)  // ユーザ定義アイテム
      addObject(arr, SearchToolbarItemIdentifier)  // ユーザ定義アイテム
      addObject(arr, "NSToolbarSpaceItem")
      addObject(arr, "NSToolbarFlexibleSpaceItem")
      
      return arr
    End Function
    
    注)SELの型をPtrとしていたが、CStringの方が相応しいので変更した。(未使用なので変更しなくても実害はなし。)(2018.07.30)
  29. 以下をNSToolbarにペースト
    Private Shared Function toolbarDefaultItemIdentifiers(id As Ptr, SEL As CString, toolbar As Ptr) as Ptr
      // デフォルトのアイテムの並びを規定
      
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      Dim arr As Ptr = NSClassFromString("NSMutableArray")  // クラスメソッドなので、まずNSMutableArrayクラスを取得
      Declare Function getArray Lib "Cocoa" Selector "array" (receiver As Ptr) As Ptr  // Return Array*
      arr=getArray(arr)
      
      Declare Sub addObject Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As CFStringRef)
      Declare Sub addObjectNil Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As Ptr)
      
      addObject(arr, SegmentedControlPairToolbarItemIdentifier)  // ユーザ定義アイテム
      addObject(arr, "NSToolbarFlexibleSpaceItem")
      addObject(arr, SegmentedControlToolbarItemIdentifier)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierSort)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierShare)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierTag)  // ユーザ定義アイテム
      addObject(arr, "NSToolbarSpaceItem")
      addObject(arr, ToolbarItemIdentifierQuick)  // ユーザ定義アイテム
      addObject(arr, ToolbarItemIdentifierAction)  // ユーザ定義アイテム
      addObject(arr, "NSToolbarFlexibleSpaceItem")
      addObject(arr, SearchToolbarItemIdentifier)  // ユーザ定義アイテム
      
      return arr
    End Function
    
    注)SELの型をPtrとしていたが、CStringの方が相応しいので変更した。(未使用なので変更しなくても実害はなし。)(2018.07.30)
  30. 以下をNSToolbarにペースト
    Private Shared Function toolbarItemForItemIdentifierWillBeInsertedIntoToolbar(id As Ptr, SEL As CString, toolbar As Ptr, itemIdentifier As CFStringRef, flag As Boolean) as Ptr
      
      if itemIdentifier = SearchToolbarItemIdentifier then
        return setToolItemSearch(itemIdentifier)
        
      elseif itemIdentifier = SegmentedControlToolbarItemIdentifier then
        return setToolItemSegment(itemIdentifier)
        
      elseif itemIdentifier = ToolbarItemIdentifierShare then
        return setToolItemSegment1(itemIdentifier,"Button","Button","Button","NSShareTemplate",601)
        
      elseif itemIdentifier = ToolbarItemIdentifierTag then
        return setToolItemSegment1(itemIdentifier,"Button","Button","Button","NSBookmarksTemplate",611)  // 本来はタグアイコンを代替使用
        
      elseif itemIdentifier = ToolbarItemIdentifierQuick then
        return setToolItemSegment1(itemIdentifier,"Button","Button","Button","NSQuickLookTemplate",621)
        
      elseif itemIdentifier = ToolbarItemIdentifierSort then
        return setToolItemSegment1Menu(itemIdentifier,"Btn Menu","Btn Menu","Btn Menu","NSHomeTemplate",makeMenuSort(itemIdentifier))  // 本来はソートアイコンを代替使用
        
      elseif itemIdentifier = ToolbarItemIdentifierAction then
        return setToolItemSegment1Menu(itemIdentifier,"Btn Menu","Btn Menu","Btn Menu","NSActionTemplate",makeMenuAction(itemIdentifier))
        
      elseif itemIdentifier = SegmentedControlPairToolbarItemIdentifier then
        return setToolItemSegmentPair(itemIdentifier)
        
      else
        return nil
      end if
    End Function
    
    注)SELの型をPtrとしていたが、CStringの方が相応しいので変更した。(未使用なので変更しなくても実害はなし。)(2018.07.30)
  31. 以下をNSToolbarにペースト
    Private Shared Function toolbarSelectableItemIdentifiers(id As Ptr, SEL As CString, toolbar As Ptr) as Ptr
      // 選択(凹んだ)状態にしたいアイテムのリストを返す
      
      return nil
    End Function
    
    注)SELの型をPtrとしていたが、CStringの方が相応しいので変更した。(未使用なので変更しなくても実害はなし。)(2018.07.30)
  32. 以下をNSToolbarにペースト
    Private Shared Function validateMenuItem(id As Ptr, SEL As CString, sender As Ptr) as Boolean
      // インスタンスメソッドに渡す
      return ActionHandler1.Invoke(sender)  // クラス生成元でActionを受け取るメソッドを呼び出す
    End Function
    
    注)SELの型をPtrとしていたが、CStringの方が相応しいので変更した。(未使用なので変更しなくても実害はなし。)(2018.07.30)
  33. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ActionHandler、データ型:ActionDelegate、を追加)
    Private Shared Property ActionHandler as ActionDelegate
    
  34. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ActionHandler1、データ型:ActionDelegate1、を追加)
    Private Shared Property ActionHandler1 as ActionDelegate1
    
  35. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:SearchDelegateInstance、データ型:Ptr、を追加)
    Private Shared Property SearchDelegateInstance as Ptr
    
  36. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:SearchToolbarItemIdentifier、データ型:String、標準値:My Search Toolbar Item、を追加)
    Private Shared Property SearchToolbarItemIdentifier as String = "My Search Toolbar Item"
    
  37. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:SegmentedControlPairToolbarItemIdentifier、データ型:String、標準値:My Segmented Control Pair Toolbar Item、を追加)
    Private Shared Property SegmentedControlPairToolbarItemIdentifier as String = "My Segmented Control Pair Toolbar Item"
    
  38. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:SegmentedControlToolbarItemIdentifier、データ型:String、標準値:My Segmented Control Toolbar Item、を追加)
    Private Shared Property SegmentedControlToolbarItemIdentifier as String = "My Segmented Control Toolbar Item"
    
  39. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:TargetInstance、データ型:Ptr、を追加)
    Private Shared Property TargetInstance as Ptr
    
  40. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ToolbarItemIdentifierAction、データ型:String、標準値:My Action Toolbar Item、を追加)
    Private Shared Property ToolbarItemIdentifierAction as String = "My Action Toolbar Item"
    
  41. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ToolbarItemIdentifierQuick、データ型:String、標準値:My Quick Look Toolbar Item、を追加)
    Private Shared Property ToolbarItemIdentifierQuick as String = "My Quick Look Toolbar Item"
    
  42. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ToolbarItemIdentifierShare、データ型:String、標準値:My Share Toolbar Item、を追加)
    Private Shared Property ToolbarItemIdentifierShare as String = "My Share Toolbar Item"
    
  43. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ToolbarItemIdentifierSort、データ型:String、標準値:My Sort Toolbar Item、を追加)
    Private Shared Property ToolbarItemIdentifierSort as String = "My Sort Toolbar Item"
    
  44. 以下をNSToolbarにペースト(できなければ共有プロパティに、名前:ToolbarItemIdentifierTag、データ型:String、標準値:My Tag Toolbar Item、を追加)
    Private Shared Property ToolbarItemIdentifierTag as String = "My Tag Toolbar Item"
    
  45. 他に、NSMakePoint/NSMakeRect/NSMakeSize(メソッド)、NSPoint/NSRect/NSSize(構造体)が必要ですが、それらはmacoslibからコピーさせて頂きました。(上記NSToolbarにコピーする。)
 実行してみたところ、各コントロールが機能することを確認しました。
S Shot1

S Shot1


 おわりに

 今回も仕組みを理解するために、極力シンプルな書き方を心懸けています。
(例えば、allocした変数の一部は然るべきタイミングでReleaseするべきと思われますが、そのためにはコードを工夫する必要があります。)
 実用目的であれば、macoslibをそのまま利用させて頂くことを考えた方がいいでしょう。
追記:削除したサーチフィールドの実装は代替法として有効であり、ケースによっては使い勝手がいいこともあるため、復活しておきました。内容はこちら

 お世話になったサイト

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

 参考サイト(1):cocoa - How to force NSToolBar validation? - Stack Overflow
 参考サイト(2):Fucking NSImage Syntax
 参考サイト(3):OS Xステータスバーアプリケーションの作り方 — Genji App Blog(ステータス項目を表示する、の5.項)


 更新履歴

 2022.01.27 おわりにの記述に、追記を追加。
 2021.05.11 方針のその他の方針を変更。Xojoでの実装、の28 26項を変更。
 2018.07.30 Xojoでの実装、の16,30,31,32,33,34 16,28,29,30,31,32項を改訂。
 2018.01.17 Xojoでの実装、のソースのうち、controlTextViewDoCommandBySelector/makeDelegateTextViewを削除、setToolItemSearchを大幅改訂。
 2016.11.25 新規作成


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