0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

メニューバーの「File」に「New Tab」の項目を追加する

Last updated at Posted at 2024-11-24

Xcode Version 16.1 (16B40) を使用しています。

サンプルの準備

新規プロジェクト → macOS → App でプロジェクトを作り ContentView の中身を移動してファイルを1つにします。

Sample0.png

サンプルの実行と変更

Xcode で Command+R でコンパイルして実行する

Sample1.png

メニューバーの "File" には新規タブで開く項目はありません

Sample2.png

メニューバーの "View" を開きます

Sample3.png

タブに関する項目が出てきました。

"Show All Tabs" を突いてみる

Sample4.png

新規でタブが足せる…

"Show Tabs Bar" を突いてみる

Sample5.png

こっちでも右上の "+" でタブが足せる…

タブ機能を有効活用するなら "File" に "New Tab" があった方がよさそうですが、デフォルトでは用意されてません。

"File" に "New Tab" を足す

"New Window" は openWindow で開く方法がありますが、これに準じる方法で "New Tab" する方法を見つけることができませんでした。NSWindow に ContentView を割り当てる方法が彼方此方にありますが、それだと App の body 定義が使用されません。メニューバーの "View" 操作経由のタブ追加では body 定義が有効です。

試しに openWindow や NSApplicationDelegate.applicationOpenUntitledFile で作った新規ウインドウをタブ グループに追加したら想定した動作になりました。

SampleApp.swift
import SwiftUI

@main
struct SampleApp: App {
    @Environment(\.openWindow) private var openWindow

    var body: some Scene {
        WindowGroup(id: "hello-world") {
            ContentView()
        }
        .commands {
            // メニュー バーの "File" に "New Tab" を追加
            //   ショートカットに Command+T を設定
            CommandGroup(before: .newItem) {
                Button("New Tab") {
                    openNewTab()
                }
                .keyboardShortcut("T", modifiers: [.command])
            }
        }
    }

    // 新規タブを開く
    private func openNewTab() {
        guard let keyWindow = NSApp.keyWindow else { return }
        guard let tabGroup = keyWindow.tabGroup else { return }
#if true
        guard let appDelegate = NSApp.delegate else { return }
        guard let openUntitledFile = appDelegate.applicationOpenUntitledFile else { return }
        if !openUntitledFile(NSApp) { return }
#else
        openWindow(id: "hello-world")
#endif
        // 追加される新規ウインドウは最後に存在すると推測
        guard let window = NSApplication.shared.windows.last else { return }
        // そのままだと独立ウインドウで現れるので tabGroup への追加を試みる
        tabGroup.addWindow(window)
    }
}

struct ContentView: View {
    static private var viewIndex: Int = 1
    static private var viewCount: Int = 0
    @State private var viewTitle = "Hello, World! (\(ContentView.viewIndex))"

    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(viewTitle)
        }
        .navigationTitle(viewTitle)
        .padding()
        .onAppear {
            ContentView.viewIndex += 1
            ContentView.viewCount += 1
        }
        .onDisappear {
            ContentView.viewCount -= 1
            if ContentView.viewCount == 0 {
                // 全てのウインドウを閉じたら終了
                NSApplication.shared.terminate(nil)
            }
        }
    }
}

#Preview {
    ContentView()
}

こんな方法でいいのか甚だ疑問だけど...

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?