ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでリッチテキストを扱う・修飾の種類を追加する

 Xojo / Real Studio Trial and Error

CocoaのDeclareでリッチテキストを扱う・修飾の種類を追加する

目次
 はじめに

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

 リッチテキスト(NSAttributedString)の修飾の種類の追加について試してみました。

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


 方針

 スタイル付きテキストの修飾は、インスペクターバーで多くのことができますが、含まれないものもあります。
 なので、追加してみることにしました。項目は以下の通りです。
 (注:シャドウと取り消し線は、フォントパネルから指定できるのですが、これらも対象とすることにします。)
項目名 Cocoaでのパラメータ名 Xojoでの指定名
アウトライン NSStrokeWidthAttributeName NSStrokeWidth
シャドウ NSShadowAttributeName NSShadow
カーニング NSKernAttributeName NSKern
取り消し線 NSStrikethroughStyleAttributeName NSStrikethrough
 参考サイト(1):NSAttributedStringを使ってみる | Tea Leaves

 指定は、(1) 文字が未入力、または入力済だが非選択、(2) 文字が入力されていて、全部または一部が選択状態、の二通りに対応します。
(1)は、NSAttributedStringではなく、NSTextViewの属性。
 どちらのケースも、既存のアトリビュートに追加する形をとりますが、

 (1)では、NSTextViewのtypingAttributesで現在のキャレット位置のアトリビュート(ディクショナリ形式)を取得して、適用します。
 (2)では、textStorageで全体を取得後、選択範囲に対して適用します。この時、返ってくるのはNSAttributedStringなので編集できないため、Mutable化します。

 (2)の場合、当初は選択範囲に含まれる既存のアトリビュートを個別に取得して、それぞれに適用する方法も試したのですが、それをしなくても「見かけ上は」同じ結果になったので、省略しても大丈夫(?)そうです。
 また、それとも関連しそうですが、アウトラインやシャドウのカラーの設定は、しないとフォントカラーが適用される(?)ようです。

 機能はメニューに実装することとし、ツールバーや独自のパネル類は使いません。
 メニュー構成と動作は、原則として、テキストエディットを参考に行います。

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

 Xojoでの実装
【ソースコードのコピー&ペーストについて】
ソースコード(グレー背景部分の全文)をコピーし、指定のウィンドウ/クラスにペーストすると、(新規作成して名前等を個別にコピー&ペーストしなくても)復元されます。
ただし、この方法は、メソッドでは問題ないようですが、イベント/アクション/プロパティでは不安定?なので、ペーストできない場合は、各項目のカッコ内を適用して下さい。
  1. 前回プロジェクトをベースとする
  2. MainMenuBar>編集メニューの次に、メニュー(Name:Format、Text:フォーマット)を追加
  3. MainMenuBar>編集メニューに、メニュー項目(Name:FormatOutline、Text:アウトライン)(Name:FormatShadow、Text:シャドウ)を追加
  4. MainMenuBar>編集メニューに、サブメニュー(Name:FormatKerning、Text:カーニング)(Name:FormatStrike、Text:取り消し線)を追加
  5. MainMenuBar>編集>カーニングメニューに、メニュー項目(Name:FormatKerningDefault、Text:デフォルト)(Name:FormatKerningNone、Text:使用しない)(Name:FormatKerningCondense、Text:きつく)(Name:FormatKerningExtend、Text:ゆるく)を追加
  6. MainMenuBar>編集>取り消し線メニューに、メニュー項目(Name:FormatStrikeSingle、Text:一本線)(Name:FormatStrikeDouble、Text:二本線)を追加
  7. 以下をWindow1のEnableMenuItemsイベントの最後に追加
    // チェックマーク判定
    SetFormatMenu(TextArea1)
    
  8. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatKerningCondenseメニューハンドラに記述)
    Function FormatKerningCondense() As Boolean
      attKind.kind="KCondens"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  9. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatKerningDefaultメニューハンドラに記述)
    Function FormatKerningDefault() As Boolean
      attKind.kind="KDefault"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  10. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatKerningExtendメニューハンドラに記述)
    Function FormatKerningExtend() As Boolean
      attKind.kind="KExtend"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  11. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatKerningNoneメニューハンドラに記述)
    Function FormatKerningNone() As Boolean
      attKind.kind="KNone"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  12. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatOutlineメニューハンドラに記述)
    Function FormatOutline() As Boolean
      if FormatOutline.Checked then  // 既にチェックありなら
        FormatOutline.Checked=false  // クリア
        attKind.Outline=false
      else
        FormatOutline.Checked=true  // チェック
        attKind.Outline=true
      end if
      
      attKind.kind="Outline"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  13. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatShadowメニューハンドラに記述)
    Function FormatShadow() As Boolean
      if FormatShadow.Checked then  // 既にチェックありなら
        FormatShadow.Checked=false  // クリア
        attKind.Shadow=false
      else
        FormatShadow.Checked=true  // チェック
        attKind.Shadow=true
      end if
      
      attKind.kind="Shadow"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  14. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatStrikeDoubleメニューハンドラに記述)
    Function FormatStrikeDouble() As Boolean
      if FormatStrikeDouble.Checked then  // 既にチェックありなら
        attKind.Strike=0  // クリア
      else
        attKind.Strike=2  // 2本線
      end if
      
      attKind.kind="StrikeD"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  15. 以下をWindow1にペースト(できなければ、Function - End Functionの間をFormatStrikeSingleメニューハンドラに記述)
    Function FormatStrikeSingle() As Boolean
      if FormatStrikeSingle.Checked then  // 既にチェックありなら
        attKind.strike=0  // クリア
      else
        attKind.strike=1  // 1本線
      end if
      
      attKind.kind="StrikeS"  // 種別セット
      SetAttrOption()  // 修飾処理
      
      Return True
    End Function
    
  16. 以下をWindow1にペースト
    Protected Sub SetAttrOption()
      if TextArea1.SelLength=0 then  // 文字が選択されていない
        
        // 現在のキャレット位置にオプション属性をセット
        SetAttrTextArea(TextArea1)
        
      else  // 文字が選択されている
        
        // 現在の文字選択範囲を退避
        Dim sst, sln As Integer
        sst=TextArea1.SelStart
        sln=TextArea1.SelLength
        
        // TextAreaの取得
        declare function documentView lib "Cocoa" selector "documentView" (obj_id as Integer) as Ptr  // Return NSTextView*
        Dim pnt1 As Ptr = documentView(TextArea1.Handle)
        
        // 現在の選択範囲を取得(ここからキャレット位置が取れる)
        Declare Function selectedRange Lib "Cocoa" Selector "selectedRange" (receiver As Ptr) As NSRange
        Dim rngSel As NSRange = selectedRange(pnt1)  // Cocoa側から取る
        
        // NSTextStorageの取得>NSAttributedStringの取得
        declare function textStorage lib "Cocoa" selector "textStorage" (obj_id as Ptr) As Ptr  // Return NSTextStorage*
        Dim pnt2 As Ptr = textStorage(pnt1)
        
        // 複製(Mutable化)
        Declare Function mutableCopy Lib "Cocoa" Selector "mutableCopy" (receiver As Ptr) As Ptr
        Dim attM As Ptr = mutableCopy(pnt2)
        
        // オプション属性のセット
        attM = SetAttrSelectedText(attM, rngSel)
        
        // ストレージにスタイル付きテキストをセット
        Declare Sub setAttributedString Lib "Cocoa" Selector "setAttributedString:" (receiver As Ptr, identifier As Ptr)
        setAttributedString(pnt2, attM)
        
        // 退避していた文字選択範囲を復元
        TextArea1.SelStart=sst
        TextArea1.SelLength=sln
        
        // clean up
        Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
        release(attM)
        
      end if
    End Sub
    
  17. 以下をWindow1にペースト
    Protected Function SetAttrSelectedText(atstr As Ptr, rngSel As NSRange) as Ptr
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      Declare Sub addAttribute Lib "Cocoa" Selector "addAttributes:range:" (receiver As Ptr, nane As Ptr, range As NSRange)
      Declare Function attributesAtIndex Lib "Cocoa" Selector "attributesAtIndex:effectiveRange:" (receiver As Ptr, idx As Integer, rng As Ptr) As Ptr
      Declare Function dictionaryWithObject Lib "Cocoa" Selector "dictionaryWithObject:forKey:" (receiver As Ptr, objt As Ptr, key As CFStringRef) As Ptr
      Declare Function objectForKey Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As Ptr
      Declare Function numberWithFloat Lib "Cocoa" Selector "numberWithFloat:" (receiver As Ptr, path As CGFloat) As Ptr
      Declare Function numberWithInteger Lib "Cocoa" Selector "numberWithInteger:" (receiver As Ptr, path As Integer) As Ptr
      Declare Function floatValue Lib "Cocoa" Selector "floatValue" (receiver As Ptr) As CGFloat
      Declare Sub removeObjectForKey Lib "Cocoa" Selector "removeAttribute:range:" (receiver As Ptr, name As CFStringRef, range As NSRange)
      
      Declare Function length Lib "Cocoa" Selector "length" (receiver As Ptr) As Integer
      Dim ll As Integer = length(atstr)  // 文字列長
      
      Declare Sub beginEditing Lib "Cocoa" Selector "beginEditing" (receiver As Ptr)
      beginEditing(atstr)  // 編集開始
      
      Dim i As Integer
      select case attKind.kind
      case "Outline" , "Shadow" , "StrikeS" , "StrikeD"
        
        if attKind.kind="Outline" then  // アウトライン
          
          if attKind.Outline then  // アウトラインあり
            // NSDictionary生成
            Dim dict As Ptr = NSClassFromString("NSMutableDictionary")
            Declare Function getDictionary Lib "Cocoa" Selector "dictionary" (receiver As Ptr) As Ptr
            dict = getDictionary(dict)
            // 実数をNSNumber形式に変換
            Dim numb As Ptr = NSClassFromString("NSNumber")
            numb = numberWithFloat(numb, 3.0)  // 3.0
            Declare Sub setObjectForKey Lib "Cocoa" Selector "setObject:forKey:" (receiver As Ptr, obj As Ptr, key As CFStringRef)
            setObjectForKey(dict, numb, "NSStrokeWidth")  // 線の幅
            // 属性をセット
            addAttribute(atstr, dict, rngSel)
          else
            // 属性を削除
            removeObjectForKey(atstr, "NSStrokeWidth", rngSel)
          end if
          
        elseif attKind.kind="Shadow" then  // シャドウ
          
          if attKind.Shadow then  // シャドウあり
            // NSShadow生成
            Dim shadow As Ptr = NSClassFromString("NSShadow")
            Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
            shadow = alloc(shadow)
            Declare Function init Lib "Cocoa" Selector "init" (receiver As Ptr) As Ptr
            shadow = init(shadow)
            Declare Sub setShadowOffset Lib "Cocoa" Selector "setShadowOffset:" (receiver As Ptr, range As CGSize)
            setShadowOffset(shadow, CGSizeMake(1.0, 7.0))  // 影のサイズ
            Declare Sub setShadowBlurRadius Lib "Cocoa" Selector "setShadowBlurRadius:" (receiver As Ptr, range As CGFloat)
            setShadowBlurRadius(shadow, 10.0)  // ぼかしの半径
            // 属性をセット
            Declare Sub addAttributeValue Lib "Cocoa" Selector "addAttribute:value:range:" (receiver As Ptr, nane As CFStringRef, val As Ptr, range As NSRange)
            addAttributeValue(atstr, "NSShadow", shadow, rngSel)
            // clean up
            Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
            release(shadow)
          else
            // 属性を削除
            removeObjectForKey(atstr, "NSShadow", rngSel)
          end if
          
        elseif attKind.kind="StrikeS" or attKind.kind="StrikeD" then  // 取り消し線
          
          if attKind.Strike>0 then  // 取り消し線あり
            // 整数をNSNumber形式に変換
            Dim numb As Ptr = NSClassFromString("NSNumber")
            Dim vv As Integer
            if attKind.kind="StrikeS" then
              vv = 1  // Single
            else
              vv = 9  // Double
            end if
            numb = numberWithInteger(numb, vv)
            // NSDictionary生成
            Dim dict As Ptr = NSClassFromString("NSDictionary")
            dict = dictionaryWithObject(dict, numb, "NSStrikethrough")
            // 属性をセット
            addAttribute(atstr, dict, rngSel)
          else
            // 属性を削除
            removeObjectForKey(atstr, "NSStrikethrough", rngSel)
          end if
          
        end if
        
      case "KExtend" , "KCondens" , "KDefault" , "KNone"  // カーニング
        
        if not (attKind.kind="KNone") then  // カーニングあり
          Dim vv As CGFloat = 0.0  // 初期値 = デフォルト
          if attKind.kind="KExtend" or attKind.kind="KCondens" then
            // 現在の値を読み込み
            Dim attk As Ptr = attributesAtIndex(atstr, rngSel.location, nil)
            Dim ptrk As Ptr = objectForKey(attk, "NSKern")
            if ptrk<>nil then
              vv = floatValue(ptrk)
            end if
            // 値の増減
            if attKind.kind="KExtend" then
              vv=vv+4.0
            else  // KCondens
              vv=vv-4.0
            end if
          end if
          // 実数をNSNumber形式に変換
          Dim numb As Ptr = NSClassFromString("NSNumber")
          numb = numberWithFloat(numb, vv)
          // NSDictionary生成
          Dim dict As Ptr = NSClassFromString("NSDictionary")
          dict = dictionaryWithObject(dict, numb, "NSKern")
          // 属性をセット
          addAttribute(atstr, dict, rngSel)
        else
          // 属性を削除
          removeObjectForKey(atstr, "NSKern", rngSel)
        end if
        
      end select
      
      Declare Sub endEditing Lib "Cocoa" Selector "endEditing" (receiver As Ptr)
      endEditing(atstr)  // 編集終了
      
      // 矛盾の解消(効果ある??)
      declare sub fixAttributesInRange lib "Cocoa" selector "fixAttributesInRange:" (receiver as Ptr, range As NSRange)
      fixAttributesInRange(atstr, NSMakeRange(0, ll))
      
      return atstr
    End Function
    
  18. 以下をWindow1にペースト
    Protected Sub SetAttrTextArea(ef As TextArea)
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      Declare Sub setObjectForKey Lib "Cocoa" Selector "setObject:forKey:" (receiver As Ptr, obj As Ptr, key As CFStringRef)
      Declare Sub removeObjectForKey Lib "Cocoa" Selector "removeObjectForKey:" (receiver As Ptr, name As CFStringRef)
      Declare Function numberWithFloat Lib "Cocoa" Selector "numberWithFloat:" (receiver As Ptr, path As CGFloat) As Ptr
      
      // DocumentViewを取得
      Dim pnt1 As Ptr
      declare function documentView lib "Cocoa" selector "documentView" (obj_id as Integer) as Ptr  // Return NSTextView*
      pnt1 = documentView(ef.Handle)
      
      // 現在のキャレット位置のアトリビュート(NSDictionary形式)を取得
      Declare Function typingAttributes Lib "Cocoa" Selector "typingAttributes" (receiver As Ptr) As Ptr
      Dim dict0 As Ptr = typingAttributes(pnt1)
      
      // 複製
      Declare Function mutableCopy Lib "Cocoa" Selector "mutableCopy" (receiver As Ptr) As Ptr
      Dim dict1 As Ptr = mutableCopy(dict0)
      
      select case attKind.kind
      case "Outline"  // アウトライン
        
        if attKind.Outline then  // アウトラインあり
          // 実数をNSNumber形式に変換
          Dim numb As Ptr = NSClassFromString("NSNumber")
          numb = numberWithFloat(numb, 3.0)  // 3.0
          setObjectForKey(dict1, numb, "NSStrokeWidth")  // 線の幅
        else
          // 属性を削除
          removeObjectForKey(dict1, "NSStrokeWidth")
        end if
        
      case "Shadow"  // シャドウ
        
        if attKind.Shadow then  // シャドウあり
          // NSShadow生成
          Dim shadow As Ptr = NSClassFromString("NSShadow")
          Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
          shadow = alloc(shadow)
          Declare Function init Lib "Cocoa" Selector "init" (receiver As Ptr) As Ptr
          shadow = init(shadow)
          Declare Sub setShadowOffset Lib "Cocoa" Selector "setShadowOffset:" (receiver As Ptr, range As CGSize)
          setShadowOffset(shadow, CGSizeMake(1.0, 7.0))  // 影のサイズ
          Declare Sub setShadowBlurRadius Lib "Cocoa" Selector "setShadowBlurRadius:" (receiver As Ptr, range As CGFloat)
          setShadowBlurRadius(shadow, 10.0)  // ぼかしの半径
          setObjectForKey(dict1, shadow, "NSShadow")  // 影
          // clean up
          Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
          release(shadow)
        else
          // 属性を削除
          removeObjectForKey(dict1, "NSShadow")
        end if
        
      case "StrikeS" , "StrikeD"  // 取り消し線
        
        if attKind.Strike>0 then  // 取り消し線あり
          // 整数をNSNumber形式に変換
          Dim numb As Ptr = NSClassFromString("NSNumber")
          Declare Function numberWithInteger Lib "Cocoa" Selector "numberWithInteger:" (receiver As Ptr, path As Integer) As Ptr
          Dim vv As Integer
          if attKind.kind="StrikeS" then
            vv = 1  // Single
          else
            vv = 9  // Double
          end if
          numb = numberWithInteger(numb, vv)
          setObjectForKey(dict1, numb, "NSStrikethrough")  // 線の種別
        else
          // 属性を削除
          removeObjectForKey(dict1, "NSStrikethrough")
        end if
        
      case "KExtend" , "KCondens" , "KDefault" , "KNone"  // カーニング
        
        if not (attKind.kind="KNone") then  // カーニングあり
          Dim vv As CGFloat = 0.0  // 初期値 = デフォルト
          if attKind.kind="KExtend" or attKind.kind="KCondens" then
            // 現在の値を読み込み
            Declare Function objectForKey Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As Ptr
            Dim ptrk As Ptr = objectForKey(dict1, "NSKern")
            if ptrk<>nil then
              Declare Function floatValue Lib "Cocoa" Selector "floatValue" (receiver As Ptr) As CGFloat
              vv = floatValue(ptrk)
            end if
            // 値の増減
            if attKind.kind="KExtend" then
              vv=vv+4.0
            else  // KCondens
              vv=vv-4.0
            end if
          end if
          // 実数をNSNumber形式に変換
          Dim numb As Ptr = NSClassFromString("NSNumber")
          numb = numberWithFloat(numb, vv)
          setObjectForKey(dict1, numb, "NSKern")  // 間隔
        else
          // 属性を削除
          removeObjectForKey(dict1, "NSKern")
        end if
        
      end select
      
      // 属性をセット
      Declare Sub setTypingAttributes Lib "Cocoa" Selector "setTypingAttributes:" (receiver As Ptr, dict As Ptr)
      setTypingAttributes(pnt1, dict1)
    End Sub
    
  19. 以下をWindow1にペースト
    Protected Sub SetFormatMenu(ef As TextArea)
      // TextAreaの取得
      declare function documentView lib "Cocoa" selector "documentView" (obj_id as Integer) as Ptr  // Return NSTextView*
      Dim pnt1 As Ptr = documentView(ef.Handle)
      
      // 現在のキャレット位置のアトリビュート(NSDictionary形式)を取得
      Declare Function typingAttributes Lib "Cocoa" Selector "typingAttributes" (receiver As Ptr) As Ptr
      Dim dict As Ptr = typingAttributes(pnt1)
      
      // 含まれる全てのキーを取得
      Dim key As String
      Dim oline, shadow As Boolean
      Dim j, strike As Integer
      Dim pnt2 As Ptr
      Declare Function count Lib "Cocoa" Selector "count" (receiver As Ptr) As Integer
      Dim jmax As Integer = count(dict)  // 要素数
      Declare Function allKeys Lib "Cocoa" Selector "allKeys" (receiver As Ptr) As Ptr
      Dim keys As Ptr = allKeys(dict)  // キーのリスト
      Declare Function objectAtIndexString Lib "Cocoa" Selector "objectAtIndex:" (receiver As Ptr, idx As Integer) As CFStringRef
      Declare Function objectForKey Lib "Cocoa" Selector "objectForKey:" (receiver As Ptr, key As CFStringRef) As Ptr
      Declare Function floatValue Lib "Cocoa" Selector "floatValue" (receiver As Ptr) As CGFloat
      for j=0 to jmax-1
        key = objectAtIndexString(keys, j)  // 個々のキー取得
        if key="NSStrokeWidth" then  // アウトライン
          oline=true
        end if
        if key="NSShadow" then  // シャドウ
          shadow=true
        end if
        if key="NSStrikethrough" then  // 取り消し線
          strike=0
          pnt2 = objectForKey(dict, "NSStrikethrough")
          if pnt2<>nil then  // 設定済なら
            strike = floatValue(pnt2)  // 現在の値を読み込み
          end if
        end if
      next
      
      // 当該メニューのチェックマーク操作と値セット
      if oline then
        FormatOutline.Checked=true
        attKind.Outline=true
      else
        FormatOutline.Checked=false
        attKind.Outline=false
      end if
      if shadow then
        FormatShadow.Checked=true
        attKind.Shadow=true
      else
        FormatShadow.Checked=false
        attKind.Shadow=false
      end if
      if strike=1 then
        FormatStrikeSingle.Checked=true
        FormatStrikeDouble.Checked=false
        attKind.Strike=1
      elseif strike=9 then
        FormatStrikeSingle.Checked=false
        FormatStrikeDouble.Checked=true
        attKind.Strike=2
      else
        FormatStrikeSingle.Checked=false
        FormatStrikeDouble.Checked=false
        attKind.Strike=0
      end if
    End Sub
    
  20. 以下をWindow1にペースト(できなければプロパティに、名前:attKind、データ型:GFAttrOption、を追加)
    Protected Property attKind as GFAttrOption
    
  21. 以下をWindow1(または適当なモジュール)の構造体(Structures)に追加
    Structure GFAttrOption
      kind As String*8
      Outline As Boolean
      Shadow As Boolean
      Strike As UInt8
    End Structure
    
 実行してみたところ、追加したテキストの修飾が機能することを確認しました。
S Shot1


 おわりに

 数値は固定としましたが、より細かいチューニングができるように、オプションパネルを追加する等した方がいいかもしれません。
 シャドウに関しては、フォントパネルに任せてしまう手もあるかも。
 あと、(2)のケースでの「既存のアトリビュートを無視して追加のみ」については、更に検証が必要かもしれません。(既存に追加または置き換え、の方が無難かも。)

 なお、OS9以前のEditFieldにあった「袋文字、影、文字間拡張/縮小(SelOutline, SelShadow, SelExtend, SelCondense)」はOSXでは使えなくなっていますが、それらの互換性維持にも使えるかもしれません。(TextAreaのサブクラス作って、計算型プロパティで実装すればいけるのかな?)


 お世話になったサイト

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

 参考サイト(1):NSAttributedStringを使ってみる | Tea Leaves


 更新履歴

 2018.07.20 新規作成


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