2

最後に入力した文字を除くすべてを非表示にするビューをOSXCocoaで作成する必要があります(設定された時間が経過するとその文字が非表示になるまで)。基本的に、 OSXCocoaUITextFieldでwithを使用したいと思います。textfield.secureTextEntry = YES

OSXCocoaにインポートする方法が見つかりませんでしたUITextField。とは2つの異なるフレームワークからのものであるためNSTextField、これはとにかく可能ではないと思います。UITextField

NSSecureTextFieldOS Xでは、Cocoaは設定された時間、最後の文字を表示し続けません。また、この動作を変更する設定可能なインスタンスまたはクラスプロパティを見つけることができませんでした。

NSTextFieldから開始してイベントをトリガーして、独自の実装をロールしようとしましkeyUp:たが、コーナーケースで問題が発生しています。私の現在のアプローチは、保存されているテキストNSTextFieldを非表示の文字(最後の文字を除くすべて、一定時間など)に変更することです。ただし、この手法では、ユーザーが7文字のパスワードで2番目から5番目の文字を選択し、それらを削除するとどうなりますか。次に、どの隠し文字が削除されたかを把握して、正しく入力されたパスワードを取得できるようにするにはどうすればよいですか?

したがって、独自の実装をロールする必要がある場合は、に格納されている実際のテキストを変更する必要はなくNSTextField、代わりにビューが画面に表示される方法を変更する必要があると思います。しかし、私は現在これを行う方法を見つけることができません。ここで助けていただければ幸いです。

また、自分の実装をロールバックしないという強い偏見があるとも言えます。以前の作業を活用するか、UITextFieldOS X Cocoaにインポートしてこの問題を解決する方法を誰かが知っている場合は、それらの解決策を歓迎します(そして強く支持します)。

4

1 に答える 1

1

を使用するNSTextFieldと、保存されているテキストからテキストの描画をうまく分離できませんでした。をNSFormatterカスタマイズして、フィールドエディタのカスタマイズを簡単に調べてみました。私が得た最も近いものは、カスタマイズすることでしたdrawInteriorWithFrame:inView:。これにより、描画を制御できるようになりましたが、フィールドエディタがオブジェクトを制御できない場合(つまり、オブジェクトのテキストを編集していない場合のみ)です。私がやろうとしていたことに対して、すべてのアプローチは非常に複雑に見えました。

を使用NSTextViewして、これを機能させることができました。アプローチは、文字の描画を保存された文字から分離し、実際のテキストをオブジェクトに保存することです。描画メソッドは、テキストを非表示にするために必要な場合にアスタリスクを使用するだけであり、オブジェクトに格納されているテキスト値には影響しません。

このアプローチを使用して機能するコードを次に示します。これはClozureCommonLispに実装されており、ClozureのObjectiveCブリッジを介してCocoaと通信します。

(defclass easygui::cocoa-password-entry-text-view (easygui::cocoa-text-view)
  ((pending-fun :accessor pending-fun :initform nil)
   (visible-char-time-secs :reader visible-char-time-secs :initform 1))
  (:metaclass ns:+ns-object))

(defclass easygui::cocoa-password-entry-layout-manager (ns:ns-layout-manager)
  ((last-char-vis-p :accessor last-char-vis-p :initform nil))
  (:metaclass ns:+ns-object))

(defclass password-entry-text-view (text-view)
  ()
  (:default-initargs :specifically 'easygui::cocoa-password-entry-text-view))

(objc:defmethod #/initWithFrame: ((self easygui::cocoa-password-entry-text-view) (frame #>NSRect))
  (unwind-protect (call-next-method frame)
    (#/replaceLayoutManager: (#/textContainer self)
     (#/init (#/alloc easygui::cocoa-password-entry-layout-manager)))
    (#/setFont: self
     (convert-font "Courier" 12))))

(objc:defmethod (#/drawGlyphsForGlyphRange:atPoint: :void) ((self easygui::cocoa-password-entry-layout-manager) (glyph-range #>NSRange) (at-point #>NSPoint))
  (let ((glyph-cnt (#/numberOfGlyphs self)))
    (let ((hide-until (if (last-char-vis-p self) (1- glyph-cnt) glyph-cnt)))
      (dotimes (i hide-until)
        (#/replaceGlyphAtIndex:withGlyph: self i 13))))
  (call-next-method glyph-range at-point))

(defmethod dialog-item-hidden-text ((view password-entry-text-view))
  (let ((text (dialog-item-text view)))
    (let ((layout-manager (#/layoutManager (cocoa-ref view))))
      (with-output-to-string (strm)
        (dotimes (i (1- (length text)))
          (format strm "*"))
        (format strm "~a" (if (last-char-vis-p layout-manager)
                            (char text (1- (length text)))
                            "*"))))))

(defmethod cursor-at-end-of-text-p ((cocoa-self easygui::cocoa-password-entry-text-view))
  (awhen (#/selectedRanges cocoa-self)
    (when (eq (#/count it) 1)
      (awhen (#/rangeValue (#/objectAtIndex: it 0))
        (let ((pos (ns:ns-range-location it)))
          (let ((length (ns:ns-range-length it)))
            (when (eq length 0)
              (when (eq pos (#/length (#/string cocoa-self)))
                t))))))))

(objc:defmethod (#/keyDown: :void) ((cocoa-self easygui::cocoa-password-entry-text-view) the-event)
  (call-next-method the-event)
  (labels ((get-keypress (the-event)
             (let* ((chars (#/characters the-event))
                    (str (objc:lisp-string-from-nsstring chars))
                    (char (char str 0)))
               char)))
    (handle-keypress-on-view
      (easygui::easygui-view-of cocoa-self)
      (get-keypress the-event))))

(defmethod handle-keypress-on-view ((view password-entry-text-view) keypress)
  (let ((cocoa-self (cocoa-ref view)))
    (cond ((or (eq keypress #\rubout)
               (not (cursor-at-end-of-text-p cocoa-self)))
           (setf (last-char-vis-p (#/layoutManager cocoa-self)) nil))
          (t
           (setf (last-char-vis-p (#/layoutManager cocoa-self)) t)
           (setf (pending-fun cocoa-self)
                 (alambda ()
                   (when (eq #'self (pending-fun cocoa-self))
                     (setf (last-char-vis-p (#/layoutManager cocoa-self)) nil)
                     (#/setNeedsDisplay: cocoa-self #$YES))))
           (schedule-for-event-process
             (pending-fun cocoa-self)
             (visible-char-time-secs cocoa-self))))))
于 2013-02-28T23:22:45.460 に答える