頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


macOSでNSViewの下のボタンをクリックできなくしたい

当然、NSViewオブジェクトの下に隠れたボタンはクリックできないだろう、と思っていたんだけどどうもmacOSではできるっぽい。

↑というツイート後に試行錯誤した結果、、、
NSButtonのサブクラスでhitTest(_:)をoverrideして、そこで被せてるviewオブジェクトもクリックしてるようならnilを返す(ボタンは無効)ようにすれば意図通りに動くことを確認した。
    override func hitTest(_ point: NSPoint) -> NSView? {
if let _ = cover.hitTest(point) {
return nil
}
return super.hitTest(point)
}
あらかじめ上に被さるNSViewオブジェクトの参照(↑のコードだとcover)をもらっておく必要がある。

とりあえず機能することはわかったんだけど、サブクラス作るのも参照もらっておくのも面倒だし、イマイチすっきりしないなあ。



macOS 10.15.6 Catalina
Xcode 11.6
Swift 5.2.4
スポンサーサイト






undoするとなぜか一番最初まで戻る(未解決)


↑こういうツイートをしたんだけど、少し詳細に。

動画ではincreaseというボタンを1回押すたびに値が1増え、その都度undoの処理を
registerUndo(withTarget:handler:)
で登録している。
なのでundoを実行すると値が1減ることを期待するのだが、なぜかある場合では一番最初まで戻ってしまうのだ。


色々試したところ、この不具合?(仕様?)が起きるのはメインのviewControllerに
presentAsModalWindow(_:)
で別なviewControllerを追加してそこで実行した場合のみ発生した。他の追加方法で
presentAsSheet(_:)
present(_:asPopoverRelativeTo:of:preferredEdge:behavior:)
present(_:animator:)
などがあるが、どれも期待通りに動いた。
先のツイートの動画ではわかりやすいようにundoボタンを使っているが⌘+zでも同様。
また、メインのviewControllerのviewで実行しても期待通りに動く。

結局原因わからず、、、presentAsModalWindow(_:)を使うのをやめる方向でアプリ開発は対応するかなあ。
何かわかったら教えてください。



macOS 10.15.6 Catalina
Xcode 11.6
Swift 5.2.4


1枚の画像からicnsファイルを作成する

macOSアプリのdocument based appだとアプリのアイコン以外に書類のアイコンも設定できる。

Xcodeのプロジェクトファイルのアイコン

↑Xcodeだとこんな感じのやつ。

これを設定しようとしたら随分はまった。

アイコンの設定画面

↑そもそもここでpng画像を指定しても実際の書類のアイコンに全く反映しない。

icnsファイルなるものにすればいけるという記事を見てそれを作ろうとしたら準備する画像の種類やらフォルダ名やら色々と決まり事があるみたい。

この画像で決まり!というものがあればそこから必要な画像を作成(サイズを変えて出力)すればいいんだろうけど、試行錯誤したいのでその都度複数のサイズで出力してicnsファイルをターミナルで出力して、、、というのが面倒なので1024x1024pxサイズの画像1枚からicnsファイルを出力するようなmacOSアプリを作った。

1. デスクトップにフォルダを作成し、1枚の画像からリサイズした画像数枚をそこに保存
2. そのフォルダからicnsファイルをデスクトップに出力
という処理を行う。

実行後に出力されたフォルダとicnsファイル

↑実行後にフォルダとicnsファイルがデスクトップに出力されるはず。

元画像はXcodeにコピーせずに参照だけ持ってくるようにしておけば、画像作成アプリで出力した後にこのアプリのコードを実行でicnsファイルが簡単にできる。

YamaguchiTatsuya/MakeIcns: This macOS project makes icns file from one 1024x1024 image.
↑コードはGitHubのこちらに。


なお、icnsファイルで書類アイコンを設定するとちゃんと反映した。



macOS 10.15.5 Catalina
Xcode 11.6
Swift 5.2.4


動画から画像を切り出す時の処理時間を計測した

macOSで動画ファイルから画像を切り出す時にAVFoundationのAVAssetImageGeneratorクラスの
func generateCGImagesAsynchronously(forTimes requestedTimes: [NSValue], completionHandler handler: @escaping AVAssetImageGeneratorCompletionHandler)
を使っている。
この最初の引数に欲しい画像の時刻に相当する値の配列を渡せばまるっとまとめてcompetionHandlerでくれる。
長い動画に対して処理をするとそこそこの時間、Macが固まることになる!
描画のタイミングはないからNSProgressIndicatorを書き換えることもできない。
ユーザーからすると、ちゃんと処理は進んでいるんだろうか?と心配になってしまう。

なのでなんとか途中で描画のタイミングを作って少しずつ画像を作成していくという方法を考えた。
心配なのはどのくらい時間のロスが発生するんだろうか?ということだ。

ということで一定枚数ごとに分割して画像を作成したらどうなるかを計測してみた。

全部で35枚の動画を作成する処理をn枚ごとに行った。
5枚ごとなら7回のループでちょうどだけど、
10枚ごとなら4回のループになり、4回目は枚数が少ない。

XCTest(ユニットテスト)のmeasureというのを使うとデフォルトで10回処理してその平均などを出してくれる。

結果をグラフにするとこんな感じ。
処理時間の結果のグラフ

そりゃ、まあ1回(横軸が35のところ)が最速になるよな。これを基準にすると、、、

処理時間の結果の表

1枚ごとなら15%ほど余計に時間がかかるけど、progress indicatorを書き換えるのなら1枚ごとじゃなくてもいいだろう。
10枚ごとなら4%ほどのロスだがこれで時々進捗を描けるならこっちの方がいいかな。


NSProgressIndicator
↑NSProgressIndicator。描画タイミングなくても逐次書き換えてくれるようになったらいいのにな。SwiftUIに期待?!



macOS 10.15.5 Catalina
Xcode 11.5
Swift 5.2.4


Number Formatter付きのNSTextFieldで入力を数値だけにする

人様が公開してるmacOSアプリのサンプルコードを眺めてたらNSTextFieldの設定画面に何やらNumber Formatterが接続されている、、、?

Xcodeのoutlet設定画面

でもなんだか表示が通常のと違って薄いし、どこのファイルにもそのようなoutletの宣言もない、、、?
これ何?と調べたところ、storyboardでNSTextFieldを追加する時にText Field with Number Formatterなんて選択肢もあったのだ(気付かなかったなあ)。

UI追加画面

↑これを選択してstoryboard上で設置する。
ところがText Fieldを選択してもinspector(Xcodeの右の方に出てくる詳細設定画面)には数値に関する設定画面がない、、、?
散々探した結果、storyboardやxibファイル選択時にXcodeのメイン画面の左の部品構成一覧のところで

パーツの構成画面

↑このようにText Fieldの下の階層にNumber Formatterとあるのでここをクリックすると

Number Formatterの設定画面

↑inspectorに設定画面が出てきた!


ここを設定すればtext fieldが数値しか受け付けない、とかできた。



macOS 10.15.4 Catalina
Xcode 11.5




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.