ホームページ開発ツール>Xojo / Real Studio / REALbasic コラム

Xojo / Real Studio / REALbasic コラム


 ○Xojo 2016r3 多言語版
 ○Xojo 2016r1.1 多言語版
 ○Xojo 2015r4.1 多言語版
 ○Xojo 2015r3 多言語版
 ○Xojo 2014r3.1 多言語版
 ○Xojo 2014r2 多言語版
 ○Xojo 2014r1 多言語版
 ○Real Studio 2011r3 以前のコラムはこちら
 タイマーを動的に生成する(ネイティブ)

 以前、こちらで「コントロールのオンザフライ生成機能は、Xojo自身も持ってはいますが、それはコントロール配列であり、最初の一個目はウィンドウに配置しておかなければならない」と書きましたが、どうもこれはウィンドウ内に直接配置するコントールについてであり、そうではないコントロールは動的に生成できるようです。
 例えばタイマーをAppに置きたい、という場合は、以下のようにすればできました。
  1. Xojoで新規プロジェクトを作成
  2. 以下をAppにペースト(できなければ、Sub - Endの間をOpenイベントに記述)
    Sub Open() Handles Open
      Timer1 = new TimerOnTheFly(AddressOf Timer1Action)
      Timer1.Period = 1000
      Timer1.Mode = 1
      
      Timer2 = new TimerOnTheFly(AddressOf Timer2Action)
      Timer2.Period = 3000
      Timer2.Mode = 1
    End Sub
    
  3. 以下をAppにペースト
    Public Sub Timer1Action()
      msgBox "done 1"
    End Sub
    
  4. 以下をAppにペースト
    Public Sub Timer2Action()
      msgBox "done 2"
    End Sub
    
  5. 以下をAppにペースト(できなければプロパティに、名前:Timer1、データ型:TimerOnTheFly、を追加)
    Protected Property Timer1 as TimerOnTheFly
    
  6. 以下をAppにペースト(できなければプロパティに、名前:Timer2、データ型:TimerOnTheFly、を追加)
    Protected Property Timer2 as TimerOnTheFly
    
  7. 新規クラス(名前は、ここでは「TimerOnTheFly」)を作成し、Superを「Timer」にする。
  8. 以下をTimerOnTheFlyにペースト(できなければ移譲に、名前:ActionDelegate、を追加)
    Public Sub ActionDelegate()
    
  9. 以下をTimerOnTheFlyにペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      ActionHandler.Invoke()  // クラス生成元でActionを受け取るメソッドを呼び出す
    End Sub
    
  10. 以下をTimerOnTheFlyにペースト
    Public Sub Constructor(action As ActionDelegate)
      ActionHandler = action  // クラス生成元でActionを受け取るメソッドを登録
    End Sub
    
  11. 以下をTimerOnTheFlyにペースト(できなければプロパティに、名前:ActionHandler、データ型:ActionDelegate、を追加)
    Public Property ActionHandler as ActionDelegate
    
 実行すると、ウィンドウが表示された後に、メッセージが表示されます。
 戻る  先頭へ


 インスペクターバー追加時のウィンドウ高さを補正する(Cocoa)

 インスペクターバーを追加すると、バーの高さ分だけウィンドウ領域が下にズレるのですが、ウィンドウの高さは変化せず、結果として領域下部が見えなくなる、といった現象が起きます。
 ウィンドウをリサイズしてやると正しく表示されるようになるので、高さが増えたことの情報が行き渡っていないような感じです。
 試行の結果、インスペクターバー追加後に以下を記述してやれば、回避できることが確認できました。
// インスペクターバー付加によるHeightの増加に、ウィンドウが追随しないことへの対策(なぜか、これでうまくいくみたい。)
me.Height=me.Height
(Trial and Errorの新規トピックでは対応済ですが、旧トピックでは未実装だったので、追加しておきました。)
 戻る  先頭へ


 Cocoaツールバーとインスペクターバーの順番【10.7限定】(Cocoa)

 こちらこちらのトピックにある、Cocoaツールバーとインスペクターバーについての注意事項です。
 両者を同時に使用する場合、10.7では、Cocoaツールバーの後にインスペクターバーを付加する必要があります。
 逆にすると、表示が崩れます。

 10.8以降では、どちらが先でも問題なく表示されます。
 戻る  先頭へ


 OSのバージョンを取得する(Cocoa)

 System.Gestaltが、いつの間にかDEPRECATEDになっていたので。
 NSProcessInfoを使う方法もあるようですが、Major,Minor,BugFix各バージョンを数値として取得したい場合は、以下の方が簡単そうです。
(参考サイト:OS X のバージョン番号を取得する - Qiita
// 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr

// SystemVersion.plistの取得
Declare Function dictionaryWithContentsOfFile Lib "Cocoa" Selector "dictionaryWithContentsOfFile:" (receiver As Ptr, path As CFStringRef) As Ptr
Dim dic As Ptr = NSClassFromString("NSDictionary")  // クラスメソッドなので、まずNSDictionaryクラスを取得
dic = dictionaryWithContentsOfFile(dic, "/System/Library/CoreServices/SystemVersion.plist")

// ProductVersionキーの内容を取得
Declare Function objectForKeyStr Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As CFStringRef
Dim osVer As String = objectForKeyStr(dic, "ProductVersion")
 osVerには、例えば「10.12.5」のような文字列が返ってきますので、ドットをセパレータに分解後数値化すればOKです。
 戻る  先頭へ


 TextAreaでの日本語文字列コピー時の文字化けを回避する(ネイティブ)

 Xojoのデフォルトの設定では、TextAreaに書き込んだ日本語の文字列を「コピー」すると、この時点で文字化けが発生します。(Finderで「クリップボードを表示」してみると分かります。)
 この現象は、TextAreaのFontをデフォルトの「System」から日本語フォント(ヒラギノ系でもOsakaでもOK)に変更することで、回避できます。
Fontの設定は、インスペクタの歯車アイコンボタンを押して表示されるペインで行う。(またはコードで指定してもOK)
 スタイルが不要であれば、(デフォルトでオンになっている)「Styled」をオフにすることでも回避できます。(この場合は、FontはSystemのままでもOK)
 戻る  先頭へ


 文字列定数の内容を取得する(Cocoa)

 Cocoaではパラメータの指定に、文字列定数(NSString * const)が使われることがあります。
 Xojoでは定数名を指定しても、自動的に内容を持ってきてはくれないので、ググるかヘッダを調べるかして、自分で内容をセットする必要がありました。
 これでは不便なので、例によってmacoslibを紐解いてみたところ、CFBundleの機能を使って取得していることが分かりました。

 ただし、この機能のためだけにmacoslibを導入するのはちょっと重たい気がするので、必要な部分のみを抜き出させて頂きました。
  1. Xojoで新規プロジェクトを作成し、TextField1、Textfield2、PushButton1を置く
  2. 以下をPushButton1のActionイベントに記述
    Dim symbolName As String = TextField1.Text  // TextField1から文字列定数を取得
    
    // CFBundleの取得
    declare function CFBundleGetBundleWithIdentifier lib "Cocoa" (bundleID as CFStringRef) as Ptr
    Dim cfb As Ptr = CFBundleGetBundleWithIdentifier("com.apple.Cocoa")
    
    // 与えられた名前に対応するシンボルのポインタを取得
    declare function CFBundleGetDataPointerForName lib "Cocoa" (bundle as Ptr, symbolName as CFStringRef) as Ptr
    dim p as Ptr = CFBundleGetDataPointerForName(cfb, symbolName)
    
    // ポインタの示す文字列を取得
    declare function CFRetain lib "Cocoa" (cf as Ptr) as CFStringRef
    Dim st As CFStringRef = CFRetain(p.Ptr(0))
    
    TextField2.Text = st  // TextField2に内容を表示
    
 戻る  先頭へ


 クラス側から生成元のメソッドを呼び出す(ネイティブ)

 自作のクラスにおいて、クラス側から、そのクラスを生成した側のメソッドを呼び出したい場合があります。
 この場合、例えば「クラス側にプロパティ(例:caller)を用意してクラス生成時にselfをセットし、caller.method()として呼び出す」という方法もありますが、プロパティには(呼び出し側の)型を指定しなければならないため、使い方に制約がつくことになります。

 他に方法がないか、例によってmacoslibを眺めていたところ、Delegateが目に留まりました。
 Delegateは、実行時にメソッドを切り替えたいようなケースを想定したもの?のようですが、今回の目的にも使えそうな感じでした。
  1. クラス内に、デリゲートを定義
  2. クラス内に、「定義したデリゲートをデータ型とする」プロパティを定義
  3. クラス生成時に、(クラス側から呼び出したい)クラス生成元のメソッドを、上述のプロパティに登録
    (メソッドはAddressOfを付けて渡し、型には「定義したデリゲート」を指定する。デリゲートはPtr型に自動的に変換される、とのこと。)
  4. クラス生成元のメソッドを呼び出したい時は、上述のプロパティをInvokeする
 コードで表すとすると、例えば、
  1. 新規クラスを作成(名前は、ここではデフォルトの「Class1」とした。)
  2. 以下をClass1の移譲(Delegates)に追加
    デリゲート名: ActionDelegate
    引数:なし
    戻り値型:なし
    
  3. 以下をClass1のメソッド(Methods)に追加(注:Constructorは予約語で、クラスをnewした時に自動的に呼び出される。)
    メソッド名: Constructor
    引数:action As ActionDelegate
    
    ActionHandler = action  // クラス生成元でActionを受け取るメソッドを登録
    ActionEvent()  // この例では、直ちに呼び出す
    
  4. 以下をClass1のメソッド(Methods)に追加
    メソッド名: ActionEvent
    引数:なし
    戻り値型:なし
    
    ActionHandler.Invoke()  // クラス生成元でActionを受け取るメソッドを呼び出す
    
  5. 以下をClass1のプロパティ(Properties)に追加(注:データ型は、デリゲート名と一致させる。)
    プロパティ名: ActionHandler
    データ型: ActionDelegate
    標準値: なし
    

  6. 以下をWindow1のOpenイベントに記述(注:引数は、Constructorに渡される。)
    Dim cls As Class1 = new Class1(AddressOf CalledFromClass1)  // クラスのインスタンスを生成(Actionを受け取るメソッドを、引数で指定する)
    
  7. 以下をWindow1のメソッド(Methods)に追加
    メソッド名: CalledFromClass1
    引数:なし
    戻り値型:なし
    
    MsgBox "Called From Class1"  // 動作確認用
    
 上記例ではメソッド/プロパティを使用しましたが、共有メソッド/共有プロパティでも同様です。

 戻る  先頭へ


 Declareの引数がアドレスの場合に値を取得する(Cocoa&Carbonも?)

(暫くやってないとすぐ忘れるので、ここに記しておきます。)
 Declareで指定したいメソッドの引数が、アドレスの場合があります。
 この場合、まずは(取得したい値の型にかかわらず)全てMemoryBlockを割り当てて、その後、型に応じた処理をして値を取得します。

 Cocoa Objective-cでの記述例(注:Carbonの場合も基本的に同じ筈)
id *data;
int value;
NSString *err;
[NShoge getData:&data value:&value error:&err];  // 注:あくまで例題で、CocoaにこのようなAPIはありません
 上記例のXojoでの実装例
Dim hoge As Ptr = NSClassFromString("NShoge")  // (この文は、例題としての整合性を図るためのもので、本題とは直接関係ありません。)

Dim data As New MemoryBlock(4)
Dim value As New MemoryBlock(4)
Dim err As New MemoryBlock(4)

Declare Sub getDataValueErr Lib "Cocoa" Selector "getData:value:error:" (receiver As Ptr, data As Ptr, value As Ptr, err As Ptr)  // アドレス指定の引数の型はPtr
getDataValueErr(hoge, data, value, err)

// 値がオブジェクトの場合(ここではNSDictionaryとしている)
Declare Function objectForKey Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As CFStringRef
Dim r As CFStringRef = objectForKey(data.Ptr(0), "keyword")  // オブジェクトから情報を引き出す

// 値がintの場合
Dim v As Integer = value.Int32Value(0)

// 値がNSStringの場合
Declare Function UTF8String Lib "Cocoa" Selector "UTF8String" (receiver As Ptr) As CString
Dim s As String = UTF8String(err.Ptr(0))

msgBox r+" "+Str(v)+" "+s
 戻る  先頭へ


 ウィンドウのタイトルにアイコンとパスのポップアップメニューを表示する(Cocoa)

 XojoのIDE自体は対応しているのですが、ユーザが使えるAPIを見つけられなかったので。(あったら教えてください。)
 ウィンドウのタイトルにオープンしたファイルのアイコンと、タイトル右クリック時にアイコンと、パスをフォルダごとに区切ったポップアップメニューを表示します。
メソッド名: setTitleWithRepresentedFilename
引数: w As Window, f As FolderItem

// 同時にタイトル名もセットします。タイトル名をセットしたくない場合は、setRepresentedFilename:
Declare Sub setTitleWithRepresentedFilename Lib "Cocoa" selector "setTitleWithRepresentedFilename:" (receiver As Integer, path As CFStringRef)
setTitleWithRepresentedFilename(w.Handle, f.NativePath)

 戻る  先頭へ


 ファイルの拡張子を取得する(Cocoa)

 Xojoネイティブの機能にはなさそうだったので。
メソッド名: GetFileExtention
引数: f As FolderItem
戻り値型: String

Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
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
return pathExtension(stringWithString(nsstr, f.NativePath))
 戻る  先頭へ


 ダーティフラグを操作する(Cocoa>ネイティブ)

 本件は、Xojoネイティブの機能であるWindow.ContentsChangedを使えばできます(知らんかった…)。
 以下は参考までにどうぞ。

 こんなことばっかりやっていると、「素直にXcodeで開発したら?」って声が聞こえてきそう(笑)ですが...
 ダーティフラグを操作したいウィンドウに、以下のメソッドを追加します。
メソッド名: SetDirtyFlag
引数: flag As Boolean

Declare Sub setDocumentEdited Lib "Cocoa" selector "setDocumentEdited:" (receiver As Integer, flag As Boolean)

setDocumentEdited(self.Handle, flag)  // self.Handleはウィンドウのハンドル。flag = true:付加 false:除去
注)汎用関数化したい場合は、引数にWindowまたはWindowのハンドルを追加してやるといいでしょう。

 戻る  先頭へ


 ウィンドウメニューについて(Cocoa編 ダイアモンドマークを付加・改訂版)

 「ウィンドウメニューについて(Cocoa編)」のうち、「しまわれた項目にダイアモンドマークを付加」は、理解が不十分だったため、書き直しました。
  1. 「しまわれた項目にダイアモンドマークを付加」
     こちらもXcodeを参考にしたいところですが、Document-Based Applicationを作ってみると分かるとおり、ウィンドウメニューへの追加やマーク付け等は自動で行われるため。手掛りは得られませんでした。
     なので、定番メソッドであるSetItemMark()のCocoa互換版がないか検索してみたところ、こちらのサイトがヒットしました。

     ここを糸口に更に調べてみたところ、メニュー項目のイメージを書き換えればいけるらしいことが分かりました。即ち、
     (1) マークの付加/クリアは、メニュー項目のCheckedプロパティをtrue/falseにする、という通常の処理で行う。
     (2) マーク付加時のイメージを、しまうが実行されたらダイアモンドに、戻す(ドックから出す)が実行されたらチェックマークに差し替える。
    という、SetItemMark()に近い(同じかどうかはよくわかりません。)ものです。

     イメージのタイプは参考サイトではNSMenuItemBulettになっていますが、類推してNSMenuItemDiamondとしたところ、うまくいきました。
     また、イメージセットの対象となるStateにはonState/offState/mixedStateとありますが、趣旨から言って、onState(デフォルトのイメージはチェックマーク)が妥当と思われます。
     なお、イメージの取得にはこちらのサイトを参考にさせて頂きました。

     セット(ダイアモンド)はMinimizeイベント、リセット(チェックマーク)はRestoreイベントで、以下のメソッドをコールします。(ただし、RestoreはMaximizeでも呼ばれるので、MinimizeとMaximizeを区別する仕込みが別途必要。)
    メソッド名: SetOnStateImage
    引数: iMenuItem As MenuItem, flag As Boolean
    
    Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
    
    Dim iPtr As Ptr = nil
    Declare Function imageNamed Lib "Cocoa" selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
    if flag then  // flag = true:マークをダイアモンドにセット false:マークをデフォルト(チェックマーク)にリセット
        iPtr = imageNamed(NSClassFromString("NSImage"), "NSMenuItemDiamond")  // イメージを取得
    else
        iPtr = imageNamed(NSClassFromString("NSImage"), "NSMenuItemSelection")  // イメージを取得
    end if
    
    // メニューのハンドルを取得(メッセージの受け手として利用できる。)
    Dim iMenuHandle As Integer
    iMenuHandle = iMenuItem.Handle(MenuItem.HandleType.CocoaNSMenuItem)
    if iMenuHandle = 0 Then
        //msgBox "error."
        return
    end if
    
    Declare Sub setOnStateImage Lib "Cocoa" selector "setOnStateImage:" (receiver As Integer, image As Ptr)
    setOnStateImage(iMenuHandle, iPtr)  // onStateのイメージを設定
    
    注)XojoでDocument-Based Applicationを作成する場合、ウィンドウメニューへの書類名の追加は自分で行うことになるので、引数にはその(自分で生成した)メニュー項目を指定する。
 戻る  先頭へ


 ファイルタイプグループの項目を並べ替える(Cocoa&Carbon)

 ファイルタイプグループの項目が多くなってくると、並べ替えた方がスッキリする場合があるのですが、IDE上では並べ替えることができません。(推測)
 なので、何か方法がないか調べてみたところ、「XMLでエクスポートし、テキストエディットで開いて並べ替えた後、インポート」すればいいことが分かりました。
 多分に原始的で、集中力を要求されはするものの、有効な手法としてReal Studioの頃は機能していました。

 ところが、Xojoになってエクスポートのダイアログから出力フォーマットの選択オプションがなくなり、バイナリでしか書き出せなくなってしまったため、この手が使えなくなってしまいました。(推測)
 「xojo export xml」で検索してみても、めぼしい情報が得られなかったので、結局、以下の方法で凌ぐことにしました。
  1. ファイルタイプグループ(以下、FileTypes1)をクリックし、ファイルメニューから「FileTypes1をエクスポート...」を選択して、書き出す。
  2. 書き出したファイル(FileTypes1.xojo_filetypeset)をXojoアイコンにドラッグ&ドロップ。
  3. ファイルメニューから「名前を付けて保存...」を選択し、Formatを「Xojo XML プロジェクト」にして保存。
  4. 保存したファイル(FileTypes1.xojo_xml_project)をテキストエディットで開く。
  5. 3行目の「<block type="Project" ID="0">」から「<block type="FileTypes1" ID="...">の直前」までを削除。
  6. 「<block type="Module" ID="...">」から「最後から2行目の</block>」までを削除。
  7. この時点でひとまず保存。

    これで、Real StudioでのXMLエクスポート相当のファイルが出来上がりました。(推測)
    あとは、「<FileType> 〜 </FileType>」が一つの項目なので、これを範囲指定してカット&ペーストで順番を入れ替えます。
    終わったら保存し、

  8. まず、既存のファイルタイプグループをIDE上から削除。(インポート後に削除してもいいが、その場合は名前がFileTypes2等に変わってしまうことに注意)
  9. ファイルメニューから「インポート...」を選択し、編集後のファイル(FileTypes1.xojo_xml_project)を指定して取り込む。
 以下はTipsです。
  1. アイコンも文字化されるので巨大な文字列となり、扱い難くなるので、予め削除して、インポート後にIDE上で再設定した方が楽かも。
  2. アイコンは一度セットすると、全て削除しても「丸に三点マーク」が表示されなくなるが、XML上で「<Icon> </Icon>」の2行を削除してやると復活する。
 余裕があれば、XMLパーサーを自作してツール化する手もありますが、滅多にやることでもないので手作業でもいいかな、と。
 なお、もっと簡単に並べ替える方法があれば、教えて頂けると助かります。
 戻る  先頭へ


 書体を含めたフォント名を取得する(Cocoa)

 本稿は、再構成してこちらに移動しました。(2014/10/30)

 戻る  先頭へ


 パッケージ形式の書類について(Cocoa&Carbon)

 パッケージ(バンドル)形式の書類は、Xojoでは標準的にはサポートされていないようなので、少し調べてみました。
 パッケージ形式の書類は「実体はフォルダであるが、Finder上では単一の書類として扱えるもの」です。
例えば、テキストエディットで画像ファイルをドロップして保存すると、拡張子がrtfdの書類が作成されるが、これがパッケージ形式。
Cocoaでは、OS9以前からの資産であるResourceForkがDeprecatedとなったため、その代替として利用されることがある。
 パッケージ化する仕組みとしては、以下の二つが確認できました。
  1. フォルダ内にPkgInfoファイルを含める。
    ・ファイルの中身は「BNDL????」一行のみ。Contentsサブフォルダ内に収めるのが作法?
    ・フォルダ名に適当な拡張子を付加すると、直ちにパッケージ書類となる。
    ・手軽だが、フォルダ内に必ずしも必要でないファイルが含まれてしまう。また、これだけではアイコンが設定できない。

  2. アプリケーションのinfo.plistで、書類がパッケージであることを宣言する。
    ・Xcodeで作成する場合は、こちらの方式。
    ・PkgInfo方式に比べ、余分なファイルがない分フォルダ内がシンプル。
    ・方法は、
    1. Xojoで「ファイルタイプグループ」を作成し、当該書類を登録する。
      表示名:<各自が設定> オブジェクト名:<各自が設定> Macタイプ:fold Macクリエータ:MACS 拡張子:<各自が設定> アイコン:<各自が設定>
      
      注1)ポイントは、Macタイプを「fold」にすることと、拡張子を設定すること。
      注2)表示名はCFBundleTypeName(Finderの「情報を見る」で種類のところに表示)として使われ、オブジェクト名は内部処理(.Filter等)で使われる。
      注2)表示名はCFBundleTypeName(Finderの「情報を見る」で種類のところに表示。ただしOSによっては別表記になることも)や.Filterの指定に使われ、オブジェクト名は内部処理(ビルド設定>OS X>File Types を選択して表示されるダイアログ等)で使われる。(2015.01.22 訂正)

    2. ビルドしたアプリケーションのinfo.plistを開き、当該書類のパートに以下を追加。
      <key>LSTypeIsPackage</key>
      <true/>
      
      注)Xojo 2014r2以降にはinfo.plistのオーバーライド機能があるが、トップレベルのみで、本件のようなサブ階層の編集には未対応のようだ。
 パッケージ形式の書類は、Xojoからはフォルダとして見えるので、.Childで内部のファイルにアクセスできます。
 問題点は、当該書類をドラッグ&ドロップに対応させると、全てのフォルダがドロップ対象になってしまうことでしょうか。(拡張子でふるい分けができればいいのでしょうが、やり方が分かりません。)

 追記:パッケージをファイルとして認識しない(フォルダのままの)場合は、(LaunchServices databaseは常に更新されているので)まずは暫く様子を見て、それでも変化がなければ、以下の処理を行うと改善される場合があります。(ターミナルを使用します。)(2015/02/23)
  1. LaunchServices databaseを再構築。
    /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -f -all local,system,user
    
    注1)10.4以前では、lsregisterのパスが「/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support」
    注2)本処理を行うと、アプリケーションとファイルの関連付けがリセットされる。これにより、「このアプリケーションで開く」で表示されるリストがクリア/再取得されるため、関連付けをカスタマイズしている場合は、再設定が必要になる場合がある。
  2. Finderを再起動。
    killall Finder
    
 戻る  先頭へ


 ウィンドウメニューについて(Cocoa編)

 以前の「ウィンドウメニューについて」の内容はCarbon用で、Cocoaには適用されません。なので、纏めておくことにしました。
 ここで扱う項目は「しまう」「拡大/縮小」「すべてを手前に移動」メニューと「しまわれた項目にダイアモンドマークを付加」です。
  1. 「しまう」「拡大/縮小」
     Carbonとは異なり、「しまう」だけでなく、「拡大/縮小」もXojoの標準機能で事足ります。
    (しまう>Minimize、拡大/縮小>Maximize)

  2. 「すべてを手前に移動」
     Xcodeの当該メニューを参考に実装してみましたが、とりあえず動くみたいです。
    (対応するメニューハンドラに、以下を記述。)
    // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
    Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
    
    // NSApplicationオブジェクトを取得(メッセージの受け手)
    Dim sA As Ptr = NSClassFromString("NSApplication")
    Declare Function SharedApplication Lib "Cocoa" Selector "sharedApplication" (receiver As Ptr) As Ptr
    sA = SharedApplication(sA)
    
    Declare Sub arrangeInFront Lib "Cocoa" Selector "arrangeInFront:" (receiver As Ptr, id As Ptr)
    arrangeInFront(sA, nil)  // NSApplicationのセレクタであるarrangeInFront:の処理
    
    Return True
    

  3. 「しまわれた項目にダイアモンドマークを付加」
     本項は、理解が不十分だったため、書き直してこちらに移動しました。(2014/12/15)

  4. 補足
     上述のNSMenuItemBulettですが、アップルのガイドラインによると、変更があって保存されていない時に使われるものなので、こちらも対応しておいた方がよさそうです。(ガイドラインについては、例えばこちらのサイト参照。)

  5. macoslibについて
     例によって、macoslibはCocoaベースのウィンドウメニュー全般にも対応していますので、実用が目的であれば、使わせて頂いた方が手軽です。
 戻る  先頭へ


 CocoaのDeclareでバッジを表示する

 アプリケーションアイコン(Doc内)の「バッジ(アイコンの右肩に表示される赤丸)」表示ですが、CocoaのDeclareを使えば可能であることが確認できました。
メソッド名: ShowBadge
引数: str As String

// 以下は、Objective-cでの記述
// NSApplication *sA = [NSApplication sharedApplication];
// NSDockTile *tile = [sA dockTile];
// [tile setBadgeLabel:@"5"];

// 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr

// sharedApplicationの取得
Dim sA As Ptr = NSClassFromString("NSApplication")
Declare Function SharedApplication Lib "Cocoa" Selector "sharedApplication" (receiver As Ptr) As Ptr
sA = SharedApplication(sA)

// Docアイコンの取得
Dim tile As Ptr
Declare Function dockTile Lib "Cocoa" Selector "dockTile" (receiver As Ptr) As Ptr
tile = dockTile(sA)

// バッジを表示(引数は文字列。空文字列を指定するとクリア)
Declare Sub setBadgeLabel Lib "Cocoa" Selector "setBadgeLabel:" (receiver As Ptr, numString As CFStringRef)
setBadgeLabel(tile,str)
 引数に"5"とか指定すると、アイコンにバッジがつきます。""(空文字列)を指定すると、バッジが消えます。ちなみに引数は文字列なので、"abc"とかもできます。
 戻る  先頭へ


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