AppKitアプリのウインドウの大きさと位置を制御する | macOSアプリの作り方

Cocoa版Hello World作成の続きです。今回は、ウインドウの最小サイズと最大サイズを設定します。また、ウインドウをスクリーンの中央に配置する処理を、HelloWindowContorllerクラスに追加します。

この記事では前回作成したサンプルコードを使用します。前回作成したサンプルコードは次の記事からダウンロードできます。

目次

ウインドウの最小サイズ・最大サイズの設定

ウインドウの最小サイズ・最大サイズはコード設定する方法と、Storyboardファイル内で設定する方法があります。この記事ではコードで設定する方法を解説します。どちらの方法でも構わないのですが、次のような理由でコード定義にしました。

  • 値を決定するときに試行錯誤が簡単。
  • 将来のバージョンなどで値を変更していったときに変更履歴を追うのが容易になる。

最小値・最大値を設定するコードを追加する

Storyboardファイルからウインドウを読み込むと、AppKitはNSWindowController.windowDidLoad()メソッドを実行します。windowDidLoad()メソッドはウインドウの初期化処理を行うためのデリゲートメソッドです。このメソッド内で最小値・最大値を設定します。

次のようにコードを追加します。

import Cocoa

class HelloWindowController: NSWindowController {
    
    let minWindowWidth: CGFloat = 200
    let minWindowHeight: CGFloat = 150
    let maxWindowWidth: CGFloat = 1200
    let maxWindowHeight: CGFloat = 900

    override func windowDidLoad() {
        super.windowDidLoad()
        
        window?.minSize = CGSize(width: minWindowWidth,
                                 height: minWindowHeight)
        window?.maxSize = CGSize(width: maxWindowWidth,
                                 height: maxWindowHeight)
    }

}

次のスクリーンキャプチャは最小サイズにしているときのスクリーンキャプチャです。

最小サイズのときのウインドウ
最小サイズのときのウインドウ

ウインドウの取得

AppKitのウインドウはNSWindowController.windowプロパティに入っています。

open var window: NSWindow?

最小サイズ

ウインドウの最小サイズはNSWindow.minSizeプロパティに設定します。

open var minSize: NSSize

最大サイズ

ウインドウの最大サイズはNSWindow.maxSizeプロパティに設定します。

open var maxSize: NSSize

カーソルの制御

サイズ変更可能なウインドウの場合、ウインドウの角やフレームなどにカーソルを持って行くと、カーソルが自動的にリサイズ可能なことを示すように変化します。AppKitでは何もしなくても、macOSの標準的なカーソル制御を行ってくれます。

例えば、次のスクリーンキャプチャはウインドウサイズを広げることも縮めることもできる状態のときです。

縮小・拡張のどちらも可能
縮小・拡張のどちらも可能

最小サイズのときは、これ以上縮小できないことを示すカーソルになります。

拡大のみ可能
拡大のみ可能

最大サイズのときは、これ以上を広げることができないことを示すカーソルになります。

縮小のみ可能
縮小のみ可能

ウインドウを中央に配置する

ウインドウを中央に配置する処理を追加します。

コードの追加

単純に考えると、スクリーンサイズとウインドウサイズを元に、中央に配置する座標を計算するという処理になります。

NSWindowクラスにはウインドウを中央に移動するメソッドがあるので、計算しなくても、用意されているメソッドを使うだけで中央に配置できます。

次のようにコードを変更します。

import Cocoa

class HelloWindowController: NSWindowController {
    
    let minWindowWidth: CGFloat = 200
    let minWindowHeight: CGFloat = 150
    let maxWindowWidth: CGFloat = 1200
    let maxWindowHeight: CGFloat = 900

    override func windowDidLoad() {
        super.windowDidLoad()
        
        window?.minSize = CGSize(width: minWindowWidth,
                                 height: minWindowHeight)
        window?.maxSize = CGSize(width: maxWindowWidth,
                                 height: maxWindowHeight)

        window?.makeKeyAndOrderFront(nil)
        window?.center()
    }

}

追加したコードは次の部分です。

window?.makeKeyAndOrderFront(nil)
window?.center()

ウインドウリストとキーウインドウについて

macOSではスクリーンに表示されているウインドウを管理しているウインドウリストがあります。

windowDidLoad()メソッドが実行されている時点では、ウインドウリストにウインドウが入っていないので、スクリーンにはウインドウは表示されません。

この状態でcenter()メソッドを使っても、どのスクリーンに対して中央なのかが決まらないので、center()メソッドが動きません。

そこで、NSWindow.makeKeyAndOrderFront()メソッドを使用します。makeKeyAndOrderFront()メソッドは次のような処理を行います。

  • 先頭のスクリーンにウインドウを移動する。
  • ウインドウをキーウインドウに変更する
  • ウインドウを表示する

キーウインドウとは?

スクリーンには複数のアプリが同時に起動し、各アプリは複数のウインドウを持っています。キーボードからキー入力を行うと、最前面にあるウインドウがキーダウンイベントを受け取り、キー入力を処理します。このウインドウのことを「キーウインドウ」と呼びます。

微妙に中央ではない?

center()メソッドで配置されたウインドウが微妙に中央ではないことに気がつきましたか?水平方向は中央揃えになっていますが、若干、上方向にずれて表示されます。

これは、不具合ではありません。

人間の視覚は、完全な中央よりも若干上にずれた位置の方が見やすく、気がつきやすいため、このような仕様になっています。

サンプルコードのダウンロード

今回の記事で作成したサンプルコードはこちらからダウンロードできます。

003_CocoaHelloWorld.zip

著書紹介

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

目次