Archive for the 'NSMenuItem' Category

2013/10/10 AppleScriptObjCで複数項目選択可能なポップアップボタンを

AppleScriptObjCのプログラムで、複数項目が選択可能なポップアップボタンを作ってみました。

作ってみましたといっても、ポップアップボタンは、ボタンをクリックすると表示されるメニュー項目のうち、選択状態にあるものをボタンのタイトルとして表示するというものであり、複数項目の選択はできません。

mpop9.png

できないながらも、どーにかして複数項目選択できるようにしなくてはならない(このへん、海外のクライアントの要望)ということで、NSPopupButtonをそのままで使うことは無理です。

そこで、NSPopupButtonをクリックすると表示されるメニューの方をなんとかしてしまえ、ということになります(このあたりまでは、海外のサイトでもよく話が出ている)。

メニューとしてNSCustomViewとかNSBoxあたりを指定する、というのがだいたいのオチなのですが……実際に試してみると、言うほど簡単ではありません。

さらにメニューに表示させる項目の数を動的に変化させたいという話もあり、メニューとして表示させるビューの大きさの制御とか、NSMatrixの位置をNSCustomViewやNSBox内のどこを基準に寄せるかといった話をクリアしなくてはなりません。

popup1.png

結局、それが面倒だったので、NSMatrixを直接メニューとして指定して表示させるようにしてみました。

popup2.png

これなら、NSMatrixを載せている「下地」との位置関係やサイズの調整などを一切行わなくてすむために、楽にできました。

そこまでクリアしても、まだ大変なことが続きます。

メニューで複数項目を選択できるところまではなんとかクリアしたのですが、その選択内容をポップアップボタンのタイトルに指定すると……メニュー内に新たな選択項目として追加されてしまうのでした。

……いろいろ思い悩んだ結果、クライアントには「勘弁してください」と泣きつき、この「複数項目選択可能なポップアップボタン」はお蔵入りに。

正確にいうと、ポップアップボタンにわざわざしなくても、ウィンドウ上にふつーにチェックボックスとして並べれば、その方が確実だしよいのではないか、という提案を行いました。

ところが、その翌日にはなんとか動くところまで持って行けました。結局、ポップアップボタンに選択状態を表示させるとメニューに追加されてしまうので、選択内容を別の部品に表示させることに。

枠や下地の描画をやめて、マウスクリックを無視するように設定して、ポップアップボタンの上に載せておけば、まるでポップアップボタンに選択状態を表示している……かのように見えるはずです。

mpop1.png
▲ビルドして起動したところ

mpop2.png
▲「+」ボタンをクリックしてテーブル内の行を追加し、それぞれにデータを入力

mpop3.png
▲ひととおりメニューに表示する項目を入力し終わったら、「Reflect」ボタンをクリック。これで、テーブルの内容をもとにポップアップメニューを動的に作成

mpop4.png
▲テーブル内容をもとに作成されたポップアップメニュー

mpop6.png
▲メニュー内の複数項目を選択できる

mpop7.png
▲複数選択した状態を別のテキストフィールド上に表示

→ Xcodeプロジェクトのダウンロード(69KB)

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– ViewInMenu

– Created by Takaaki Naganoya on 2013/10/08.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
  property pu : missing value – IBOutlet for the popUpButton
  
property item1 : missing value
  
property mat : missing value – IBOutlet for the matrix of NSLabels
  
  property theData : {} – the table data
  
property theArrayController : missing value
  
property aTable : missing value
  
  property aTextF : missing value
  
  
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    set theData to {}
    
    set item1 to current application’s NSMenuItem’s alloc()’s initWithTitle_action_keyEquivalent_(“”, missing value, “”)
    
item1’s setView_(mat)
    
item1’s setTarget_(me)
    
pu’s removeAllItems()
    
pu’s |menu|()’s addItem_(item1)
    
    aTextF’s setStringValue_(“”)
    
  end applicationWillFinishLaunching_
  
  
  
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  
  
  on matrixClick_(sender) – IBAction for the matrix
    
    aTextF’s setStringValue_(“”)
    
    tell theArrayController
      set outList to arrangedObjects() as list
    end tell
    
    set aLen to length of outList
    
set aList to {}
    
    
    repeat with i from 0 to (aLen - 1)
      
      set aTmpVal to mat’s cellAtRow_column_(i, 0)’s integerValue()
      
set aTmpVal to aTmpVal as number
      
      if aTmpVal is equal to 1 then
        
        set aTmpText to mat’s cellAtRow_column_(i, 0)’s title()
        
set the end of aList to aTmpText
        
      end if
      
    end repeat
    
    set aText to retArrowText__(aList, “, “)
    
set aText to aText as string
    
    aTextF’s setStringValue_(aText)
    
  end matrixClick_
  
  
  
  
  –Array Controllerから動的にメニューを作成する
  
on buttonClick_(sender) – IBAction for the button
    
    set outList to {}
    
    tell theArrayController
      set theList to arrangedObjects() as list
    end tell
    
    log {“theList”, theList}
    
    repeat with i in theList
      set j to contents of i
      
set jj to aTitle of j
      
set jj to jj as string
      
set the end of outList to jj
    end repeat
    
    set aLen to length of outList
    
    
    mat’s renewRows_columns_(aLen, 1)
    
mat’s sizeToCells()
    
    repeat with i from 0 to (aLen - 1)
      set aStr to contents of item (i + 1) of outList
      
set aStr to aStr as string
      
mat’s cellAtRow_column_(i, 0)’s setTitle_(aStr)
    end repeat
    
    
    aTextF’s setStringValue_(“”)
    
  end buttonClick_
  
  
  –リストを任意のデリミタ付きでテキストに
  
on retArrowText__(aList, aDelim)
    
    set aText to “”
    
set aLen to length of aList
    
set aCount to 1
    
    repeat with i in aList
      set j to i as string
      
      if aCount < aLen then
        set aText to aText & j & aDelim
      else
        set aText to aText & j
      end if
      
      set aCount to aCount + 1
      
    end repeat
    
    return aText
    
  end retArrowText__
  
  
  
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に