ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでもう一つの通知センターを利用する

 Xojo / Real Studio Trial and Error

CocoaのDeclareでもう一つの通知センターを利用する

目次
 はじめに

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

 通知センターは、既にCocoaのDeclareで通知センターを利用する他で取り上げましたが、ここでは、もう一つの通知センター、について調べてみました。

 なお検証には、Xojo 2016 Release 3を用いています。(Mac mini mid 2010 + macOS 10.13.6 High Sierra)


 方針

 Xojoでは、2013 Release 1以降、スレッドからコントロールにアクセスできなくなってしまったので、代替方法としてタイマーの使用が推奨?されています。
(言語リファレンスのThreadの項に、サンプルが載っています。)
 それでもいいのですが、他にも方法がないのか、調べてみることにしました。

 思い当たったのは、以前にもやった通知センターですが、処理内容がちょっと違うので検索してみたところ、以下がヒットしました。

 参考サイト(1):見えない通知を捕まえて通知駆動アプリケーションを作る - ザリガニが見ていた...。

 ここで、通知センターには二種類あることを知りました。
 今回使えそうなのは、(以前使った)NSUserNotificationCenterではなく、NSNotificationCenterのようです。

 当初は、同じアプリ内なので、NSNotificationCenterでいいかと思ったのですが、ThreadAccessingUIExceptionエラーで止まってしまいました。
 デバッガの情報を見ると、直接メソッドを呼んでいるようなスタックになっています。
 なので、別アプリに通知を送る、NSDistributedNotificationCenterを使ってみたところ、…、今度はうまくいくいきました。

 一方、せっかくなので(笑)、NSNotificationCenterの方も試してみることにしました。
 事例としては、(スレッドには使えないので)参考サイト(1)で取り上げられていた、ウィンドウの背景色にしてみました。

 このケースでは、通知は各ウィンドウ(インスタンス)が受け取ることになりますが、通知を最初に受け取るのはクラスメソッドのため、これを各ウィンドウ(インスタンス)に振り分ける処理が必要になります。
 直接インスタンスメソッドで受けられないか、いくつか試してはみたのですが、試した範囲ではうまくいきませんでした。
注)これまでも、このクラス - インスタンス問題はあったが、受け手が一箇所しかなかったため、インスタンス生成時に一回指定すれば事足りた。
 そこで、各ウィンドウ(インスタンス)生成ごとに、イベントをレイズするメソッドのアドレスを配列に追加し、通知受け取り時は、通知名(実際にはランタイムAPIのインスタンスに継承された、ランタイムAPIのクラス名)に埋め込まれたウィンドウ番号を判定して、振り分けるようにしました。
 ここに、「イベントをレイズ」とあるのは、受け手が一つの場合のようにインスタンス生成時にメソッドのアドレスを渡すことができないため、クラス側のみで処理しようとすると、イベントの方が都合がいいからです。(ただし、生成後は可能なので、別メソッド化すれば、従来(例1含む)方式で処理することも可能。)

 以上を踏まえ、それぞれの仕様は以下の通りとしました。

 例1(NSDistributedNotificationCenter)
 例2(NSNotificationCenter)

 Xojoでの実装(例1)
【ソースコードのコピー&ペーストについて】
ソースコード(グレー背景部分の全文)をコピーし、指定のウィンドウ/クラスにペーストすると、(新規作成して名前等を個別にコピー&ペーストしなくても)復元されます。
ただし、この方法は、メソッドでは問題ないようですが、イベント/アクション/プロパティでは不安定?なので、ペーストできない場合は、各項目のカッコ内を適用して下さい。
  1. Xojoで新規プロジェクトを作成
  2. Window1に、PushButton(Name:PushButton1)、ProgressBar(Name:ProgressBar1、Value:0)を追加
  3. 以下をPushButton1にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      // 通知センターに通知名と受け取り手を登録
      Dim tmp As NotificationCenter = new NotificationCenter("myNotif", kIdentifier, AddressOf PostGet)
      
      // プログレスバー初期化
      ProgressBar1.Value=0
      
      // スレッドを起動
      Dim th As CustomThread
      th=new CustomThread
      th.Run
    End Sub
    
  4. 以下をWindow1にペースト
    Private Sub PostGet(notify As Ptr)
      Dim progressValue As Integer
      
      if ProgressBar1.Value >= ProgressBar1.Maximum then  // 最大値を超えたら
        
        ProgressBar1.Value = 0  // クリア
        msgBox "Done"
        
      else  // 最大値以下なら
        
        // notifyが有効なら
        if notify<>nil  then
          
          // notifyからuserInfoを取得
          Declare Function userInfo Lib "Cocoa" Selector "userInfo" (receiver As Ptr) As Ptr
          Dim info As Ptr = userInfo(notify)
          if info<>nil then  // userInfoが有効なら
            
            // userInfoから値を取得
            Declare Function objectForKey Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As Ptr
            Dim vPtr As Ptr = objectForKey(info, "Value")
            if vPtr<>nil then  // 値が有効なら
              
              // 値を取得
              Declare Function integerValue Lib "Cocoa" Selector "integerValue" (receiver As Ptr) As Integer
              progressValue = integerValue(vPtr)
              
            end if
            
          end if
          
        end if
        
        // プログレスバーに値をセット
        ProgressBar1.Value = progressValue
        
      end if
    End Sub
    
  5. 新規クラスを作成(名前は、ここでは「NotificationCenter」とした。)
  6. 以下をNotificationCenterにペースト(できなければ移譲に、名前:ActionDelegate、を追加)
    Private Sub ActionDelegate(notify As Ptr)
    
  7. 以下をNotificationCenterにペースト
    Public Sub Constructor(clsName As String, notName As String, action As ActionDelegate)
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // ObserverとSelectorを生成
      MakeObserver(clsName)
      
      // defaultCenterを取得
      Dim nCenter As Ptr = NSClassFromString("NSDistributedNotificationCenter")
      Declare Function defaultCenter Lib "Cocoa" Selector "defaultCenter" (receiver As Ptr) As Ptr
      nCenter = defaultCenter(nCenter)
      
      // defaultCenterにObserver/Selector/名前/オブジェクトをセット
      Declare Sub addObserver Lib "Cocoa" Selector "addObserver:selector:name:object:" (receiver As Ptr, obs As Ptr,sel As Ptr, nam As CFStringRef, obj As Ptr)
      addObserver(nCenter, NotifyObserver, NotifySelector, notName, nil)
      
      // クラス生成元でActionを受け取るメソッドを登録
      ActionHandler = action
    End Sub
    
  8. 以下をNotificationCenterにペースト
    Private Sub MakeObserver(clsName As String)
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      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 NotifyObserver <> nil then
        return
      end if
      
      // クラス名をmyNotif、メタクラス名をNSObjectにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), clsName, 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      // 通知の受け口となるメソッドを追加(getPost:をXojo側で用意したgetPostメソッドで受け取る。)
      NotifySelector = NSSelectorFromString("getPost:")
      if not class_addMethod (newClassId, NotifySelector, AddressOf getPost, "@@:@") then
        msgBox "error."
        return
      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))
      
      // インスタンスを保持
      NotifyObserver = targetId
    End Sub
    
  9. 以下をNotificationCenterにペースト(できなければプロパティに、名前:NotifyObserver、データ型:Ptr、を追加)
    Private Property NotifyObserver as Ptr
    
  10. 以下をNotificationCenterにペースト(できなければプロパティに、名前:NotifySelector、データ型:Ptr、を追加)
    Private Property NotifySelector as Ptr
    
  11. 以下をNotificationCenterにペースト
    Private Shared Sub getPost(id As Ptr, SEL As CString, notify As Ptr)
      ActionHandler.Invoke(notify)  // クラス生成元でActionを受け取るメソッドを呼び出す
    End Sub
    
  12. 以下をNotificationCenterにペースト(できなければ共有プロパティに、名前:ActionHandler、データ型:ActionDelegate、を追加)
    Private Shared Property ActionHandler as ActionDelegate
    
  13. Xojoプロジェクトウィンドウ>ナビゲーターに、Threadをドロップ(名前は、ここではデフォルトの「CustomThread」とした。)
    (Xojoプロジェクトウィンドウ>ナビゲーター>Window1、ではない)
  14. 以下をCustomThreadにペースト(できなければ、Sub - Endの間をRunイベントに記述)
    Sub Run() Handles Run
      // 初期化
      Dim progressValue As Integer = 0
      
      // 100になるまで繰り返す
      while progressValue <= 100
        
        // インクリメント
        progressValue = progressValue + 1
        
        // 遅延
        Dim waitUntil As Integer = Ticks + 1
        while ticks < waitUntil
        wend
        
        // 通知を発行
        PutPost(progressValue)
        
      wend
    End Sub
    
  15. 以下をCustomThreadにペースト
    Public Sub PutPost(progressValue As Integer)
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // 通知と一緒に渡すパラメータを生成
      Dim numb As Ptr = NSClassFromString("NSNumber")  // 整数をNSNumber形式に変換
      Declare Function numberWithInteger Lib "Cocoa" Selector "numberWithInteger:" (receiver As Ptr, path As Integer) As Ptr
      numb = numberWithInteger(numb, progressValue)
      Dim dict As Ptr = NSClassFromString("NSDictionary")  // NSDictionaryにセット
      Declare Function dictionaryWithObject Lib "Cocoa" Selector "dictionaryWithObject:forKey:" (receiver As Ptr, objt As Ptr, key As CFStringRef) As Ptr
      dict = dictionaryWithObject(dict, numb, "Value")
      
      // defaultCenterを取得
      Dim nCenter As Ptr = NSClassFromString("NSDistributedNotificationCenter")
      Declare Function defaultCenter Lib "Cocoa" Selector "defaultCenter" (receiver As Ptr) As Ptr
      nCenter = defaultCenter(nCenter)
      
      // 通知を発行
      Declare Sub postNotification Lib "Cocoa" Selector "postNotificationName:object:userInfo:" (receiver As Ptr, nam As CFStringRef, obj As CFStringRef, info As Ptr)
      postNotification(nCenter, kIdentifier, nil, dict)
    End Sub
    
  16. 新規モジュールを作成(名前は、ここではデフォルトの「Module1」とした。)
  17. 以下をModule1にペースト(できなければ定数に、名前:kIdentifier、デフォルト値:com.mycompany.notifybgcolor.identifier、データ型:String、を追加)
    Public Const kIdentifier as String = com.mycompany.notifybgcolor.identifier
    
    注)デフォルト値は任意です。Bundle identifierに相当する部分はじめ、適宜変更して下さい。
 実行してみたところ、スレッドからプログレスバーを更新できることを確認しました。


 Xojoでの実装(例2)
  1. Xojoで新規プロジェクトを作成
  2. 以下をWindow1にペースト(できなければ定数に、名前:kIdentifier、デフォルト値:identifier、データ型:String、を追加)
    Public Const kIdentifier as String = identifier
    
    注)例1と同様、モジュールに置いても構いません。また、こちらもデフォルト値は任意です。
  3. Window1に、PushButton2個(Name:PushButton1, Name:PushButton2)、Slider3個(Name:Slider1, Name:Slider2, Name:Slider3)を追加
  4. Slider1, Slider2, Slider3のMaximumを255にセット
  5. 以下をPushButton1にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      // ウィンドウ生成
      Dim w2 As Window2 = new Window2("myNotif_"+Str(cnt), kIdentifier)
      
      // 初期化
      w2.InitApp(Str(cnt))
      
      // 表示
      w2.Show
      
      // カウントアップ
      cnt=cnt+1
    End Sub
    
  6. 以下をPushButton2にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // 通知と一緒に渡すパラメータを生成
      Dim dict As Ptr = NSClassFromString("NSDictionary")  // NSDictionary生成
      Declare Function dictionaryWithObject Lib "Cocoa" Selector "dictionaryWithObject:forKey:" (receiver As Ptr, objt As Ptr, key As CFStringRef) As Ptr
      dict = dictionaryWithObject(dict, RGBtoNSColor(RGB(Slider1.Value,Slider2.Value,Slider3.Value)), "Value")  // カラーをセット
      
      // 通知の発行
      PutPost(kIdentifier,dict)
    End Sub
    
  7. 以下をWindow1にペースト
    Private Sub PutPost(name As String, uinfo As Ptr)
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // defaultCenterを取得
      Dim nCenter As Ptr = NSClassFromString("NSNotificationCenter")
      Declare Function defaultCenter Lib "Cocoa" Selector "defaultCenter" (receiver As Ptr) As Ptr
      nCenter = defaultCenter(nCenter)
      
      // NSNotificationを作成する
      Dim notification As Ptr = NSClassFromString("NSNotification")
      Declare Function notificationWithName Lib "Cocoa" Selector "notificationWithName:object:userInfo:" (receiver As Ptr, nam As CFStringRef, obj As Ptr, info As Ptr) As Ptr
      notification = notificationWithName(notification, name, nil, uinfo)
      
      // 通知を発行
      Declare Sub postNotification Lib "Cocoa" Selector "postNotification:" (receiver As Ptr, notify As Ptr)
      postNotification(nCenter, notification)
    End Sub
    
  8. 以下をWindow1にペースト
    Private Function RGBtoNSColor(rgb As Color) as Ptr
      Dim r, g, b As CGFloat
      
      // 0〜255 を 0.0〜1.0 にマッピング
      r=rgb.Red/255
      g=rgb.Green/255
      b=rgb.Blue/255
      
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // カラーの取得
      Dim clr As Ptr = NSClassFromString("NSColor")
      
      // RGB値からカラーを生成
      Declare Function colorWithCalibrate Lib "Cocoa" Selector "colorWithCalibratedRed:green:blue:alpha:" _
      (receiver As Ptr, red As CGFloat, green As CGFloat, blue As CGFloat, alpha As CGFloat) As Ptr
      clr = colorWithCalibrate(clr, r, g, b, 1.0)  // alpha値は常に1.0
      
      // カラーを返す
      return clr
    End Function
    
  9. 以下をWindow1にペースト(できなければプロパティに、名前:cnt、データ型:Integer、を追加)
    Private Property cnt as Integer
    
  10. 新規クラスを作成(名前は、ここでは「NotificationCenterWin」とした。)
  11. 以下をNotificationCenterWinにペースト(できなければ移譲に、名前:ActionDelegate、引数:notify As Ptr、を追加)
    Private Sub ActionDelegate(notify As Ptr)
    
  12. 以下をNotificationCenterWinにペースト(できなければイベント定義に、イベント名:GetPost、引数:notify As Ptr、を追加)
    Event GetPost(notify As Ptr)
    
  13. 以下をNotificationCenterWinにペースト
    Public Sub Constructor(clsName As String, notName As String)
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // ObserverとSelectorを生成
      MakeObserver(clsName)
      
      // defaultCenterを取得
      Dim nCenter As Ptr = NSClassFromString("NSNotificationCenter")
      Declare Function defaultCenter Lib "Cocoa" Selector "defaultCenter" (receiver As Ptr) As Ptr
      nCenter = defaultCenter(nCenter)
      
      // defaultCenterにObserver/Selector/名前/オブジェクトをセット
      Declare Sub addObserver Lib "Cocoa" Selector "addObserver:selector:name:object:" (receiver As Ptr, obs As Ptr,sel As Ptr, nam As CFStringRef, obj As Ptr)
      addObserver(nCenter, NotifyObserver, NotifySelector, notName, nil)
      
      ActionHandler.Append AddressOf RaiseEventGetPost  // クラス生成元のイベントをレイズするため、インスタンスメソッドを登録(配列に追加)
    End Sub
    
  14. 以下をNotificationCenterWinにペースト
    Private Sub MakeObserver(clsName As String)
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      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 NotifyObserver <> nil then
        return
      end if
      
      // クラス名をclsNameで与えられる名前、メタクラス名をNSObjectにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), clsName, 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      // 通知の受け口となるメソッドを追加(getPost:をXojo側で用意したgetPostメソッドで受け取る。)
      NotifySelector = NSSelectorFromString("getPost:")
      if not class_addMethod (newClassId, NotifySelector, AddressOf getPost, "@@:@") then
        msgBox "error."
        return
      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))
      
      // インスタンスを保持
      NotifyObserver = targetId
    End Sub
    
  15. 以下をNotificationCenterWinにペースト
    Private Sub RaiseEventGetPost(notify As Ptr)
      // イベントをレイズ
      RaiseEvent GetPost(notify)
    End Sub
    
  16. 以下をNotificationCenterにペースト(できなければプロパティに、名前:NotifyObserver、データ型:Ptr、を追加)
    Public Property NotifyObserver as Ptr
    
  17. 以下をNotificationCenterにペースト(できなければプロパティに、名前:NotifySelector、データ型:Ptr、を追加)
    Private Property NotifySelector as Ptr
    
  18. 以下をNotificationCenterにペースト
    Private Shared Sub getPost(id As Ptr, SEL As CString, notify As Ptr)
      // 呼び出し元のクラスを取得
      Declare Function myClass Lib "Cocoa" selector "class" (class_id As Ptr) As Ptr
      Dim pnt1 As Ptr = myClass(id)
      
      // クラス名を取得
      Declare Function description Lib "Cocoa" selector "description" (class_id As Ptr) As CFStringRef
      Dim st As String = description(pnt1)
      
      // クラス名からウィンドウ番号を取得
      Dim cnt As Integer = Val(NthFieldB(st,"_",2))
      
      // イベントをレイズするため、ウィンドウ番号に対応したインスタンスメソッドを起動
      ActionHandler(cnt).Invoke(notify)
    End Sub
    
  19. 以下をNotificationCenterにペースト(できなければ共有プロパティに、名前:ActionHandler(-1)、データ型:ActionDelegate、を追加)
    Private Shared Property ActionHandler(-1) as ActionDelegate
    
  20. Xojoプロジェクトウィンドウ>ナビゲーターに、Windowをドロップ(名前は、ここではデフォルトの「Window2」とした。)
  21. Window2のSuperを「NotificationCenterWin」にする。
  22. 以下をWindow2にペースト(できなければ、Sub - Endの間をCloseイベントに記述)
    Sub Close() Handles Close
      // Observerが未設定なら戻る
      if NotifyObserver=nil then
        return
      end if
      
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      // defaultCenterを取得
      Dim nCenter As Ptr = NSClassFromString("NSNotificationCenter")
      Declare Function defaultCenter Lib "Cocoa" Selector "defaultCenter" (receiver As Ptr) As Ptr
      nCenter = defaultCenter(nCenter)
      
      // defaultCenterからObserverを削除
      Declare Sub removeObserver Lib "Cocoa" Selector "removeObserver:" (receiver As Ptr, obs As Ptr)
      removeObserver(nCenter, NotifyObserver)
    End Sub
    
  23. 以下をWindow2にペースト(できなければ、Sub - Endの間をGetPostイベントに記述)
    Sub GetPost(notify As Ptr) Handles GetPost
      // notifyが無効なら戻る
      if notify=nil  then
        return
      end if
      
      // notifyからuserInfoを取得
      Declare Function userInfo Lib "Cocoa" Selector "userInfo" (receiver As Ptr) As Ptr
      Dim uinfo As Ptr = userInfo(notify)
      // userInfoが無効なら戻る
      if uinfo=nil  then
        return
      end if
      
      // userInfoから値を取得
      Declare Function objectForKey Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As Ptr
      Dim vPtr As Ptr = objectForKey(uinfo, "Value")
      // 値が無効なら戻る
      if vPtr=nil  then
        return
      end if
      
      // 背景色のセット
      me.BackColor=NSColortoRGB(vPtr)
    End Sub
    
  24. 以下をWindow2にペースト
    Public Sub InitApp(cntString As String)
      // タイトルに固有番号を追加
      me.Title=me.Title+" "+cntString
      
      // 背景のカラーを白で初期化
      Dim clr As Color = RGB(255,255,255)
      
      // 背景色のセット
      me.BackColor=clr
    End Sub
    
  25. 以下をWindow2にペースト
    Private Function NSColortoRGB(pnt As Ptr) as Color
      #if Target32Bit
        Dim rA As New MemoryBlock(4)
        Dim gA As New MemoryBlock(4)
        Dim bA As New MemoryBlock(4)
        Dim aA As New MemoryBlock(4)
      #elseif Target64Bit
        Dim rA As New MemoryBlock(8)
        Dim gA As New MemoryBlock(8)
        Dim bA As New MemoryBlock(8)
        Dim aA As New MemoryBlock(8)
      #endif
      Dim rF, gF, bF As CGFloat
      
      Declare Sub getRGB Lib "Cocoa" Selector "getRed:green:blue:alpha:" (receiver As Ptr, red As Ptr, green As Ptr, blue As Ptr, alpha As Ptr)
      getRGB(pnt, rA, gA, bA, aA)  // rgb値を取得
      
      #if Target32Bit
        rF = rA.SingleValue(0)
        gF = gA.SingleValue(0)
        bF = bA.SingleValue(0)
      #elseif Target64Bit
        rF = rA.DoubleValue(0)
        gF = gA.DoubleValue(0)
        bF = bA.DoubleValue(0)
      #endif
      
      return RGB(rF*255,gF*255,bF*255)  // Color形式に変換して返す
    End Function
    
 実行してみたところ、ウィンドウの背景色を変更できることを確認しました。


 おわりに

 例1のケースでは、仕掛けが大掛かりな割には得られるものが少ないので、実用性は薄いかもしれません。

 例2のケースでは、ウィンドウを閉じると、通知センターへの登録は解除していますが、レイズイベント用の配列要素は削除していない(すればしたで、別の問題が発生)ので、一方的に増えてしまいます。Dictionary等を使えば任意の要素の削除が可能になりますが、オーバーヘッドを考えると、どちらがいいかは不明です。別の方法を考えたほうがいいかもしれません。


 お世話になったサイト

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

 参考サイト(1):見えない通知を捕まえて通知駆動アプリケーションを作る - ザリガニが見ていた...。


 更新履歴

 2018.08.10 新規作成


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