Paepoi

Paepoi » PyObjC Tips » その他 NSControl

その他 NSControl

最終更新日 2024.08.25

個別ページを作るまでもないものを。

NSComboBox
右にある逆三角形をタップするとプルダウンして選択できます。
NSTextField のサブクラスなので NSTextField のメソッドも利用できます。
文字列の選択に特化しているようです。

#!/usr/bin/env python3

import AppKit, objc

items = [
    'やっぱり超望遠で野鳥でしょ',
    'GoPro を固定してツーリング動画',
    '電車だよ、わかんねえかなぁ',
    '靴に付いたカメラで空を見上げたい'
]

class MyView(AppKit.NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # NSComboBox @ NSTextField のサブクラス
        # 高さを厳密にしないとズレて表示されるのでこんな感じに
        #
        self.cbox = AppKit.NSComboBox.labelWithString_('何が撮りたい?')
        h = self.cbox.frameSize()[1]
        self.cbox.setFrame_(((10, 10), (200, h)))
        self.cbox.addItemsWithObjectValues_(items)
        self.addSubview_(self.cbox)
        #
        return self

    def isFlipped(self):
        # 左上を原点にする
        return True

class MyWindow(AppKit.NSWindow):
    def init(self):
        rect = AppKit.NSMakeRect(0, 0, 220, 100)
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            rect,
            AppKit.NSTitledWindowMask |
            AppKit.NSClosableWindowMask |
            AppKit.NSResizableWindowMask |
            AppKit.NSMiniaturizableWindowMask,
            AppKit.NSBackingStoreBuffered, False)
        # NSView
        self.canvas = MyView.alloc().initWithFrame_(rect)
        self.contentView().addSubview_(self.canvas)
        # etc
        self.setTitle_('Sample')
        self.setDelegate_(self)
        return self

    def windowWillClose_(self, sender):
        '''
            終了時に値を書き出し
            何も選択していない場合は -1 になる
        '''
        num = self.canvas.cbox.indexOfSelectedItem()
        if num > -1:
            print(self.canvas.cbox.objectValueOfSelectedItem())

class AppDelegate(AppKit.NSObject):

    wins = []

    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        self.wins.append(window)
        AppKit.NSApp.activateIgnoringOtherApps_(True)

    def applicationSupportsSecureRestorableState_(self, app):
        return True

class AppMenu(AppKit.NSMenu):
    def init(self):
        objc.super(AppMenu, self).init()
        item_app  = AppKit.NSMenuItem.new()
        self.addItem_(item_app)
        menu_app = AppKit.NSMenu.new()
        item_app.setSubmenu_(menu_app)
        # quit menu
        item_quit = AppKit.NSMenuItem.new()
        item_quit.initWithTitle_action_keyEquivalent_('Quit App', 'terminate:', 'q')
        menu_app.addItem_(item_quit)
        return self

AppKit.NSApplication.sharedApplication()
AppKit.NSApp.setMainMenu_(AppMenu.new())
AppKit.NSApp.setDelegate_(AppDelegate.new())
NSApp.run()

webp/cb.webp

NSPopUpButton
NSCombobox と同様ですがこちらはどの部分をタップしてもプルダウンできます。
又内部の NSMenu にアクセスできますので画像付きのポップアップも利用できます。
未選択状態は用意されていないので必要な場合は自分で作る必要があります。

#!/usr/bin/env python3

import AppKit, objc

items = ['Apache の', 'アイコンを', '勝手に使って', 'ごめんなチャイ']

class MyView(AppKit.NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # NSPopUpButton @ NSButton のサブクラス
        # autoenablesItems プロパティを True にしないと変化しない
        #
        self.pbtn = AppKit.NSPopUpButton.alloc().initWithFrame_pullsDown_(((10, 10), (200, 40)), False)
        self.pbtn.addItemsWithTitles_(items)
        self.pbtn.setAutoenablesItems_(True)
        self.addSubview_(self.pbtn)
        # ICON のセット
        for i, s in enumerate(['a.png', 'c.png', 'f.png', 'p.png']):
            # apache のアイコンを拝借、皆デフォルトで入っているよね?
            path = f'/usr/share/httpd/icons/{s}'
            image = AppKit.NSImage.alloc().initWithContentsOfFile_(path)
            menu = self.pbtn.itemArray()[i]
            menu.setImage_(image)
            # 選択した時にアクションさせる
            menu.setTarget_(self)
            menu.setAction_('onSelect:')
        #
        return self

    def onSelect_(self, sender):
        # 選択を変更するとココに来る
        print(sender.title())

    def isFlipped(self):
        # 左上を原点にする
        return True

class MyWindow(AppKit.NSWindow):
    def init(self):
        rect = AppKit.NSMakeRect(0, 0, 220, 100)
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            rect,
            AppKit.NSTitledWindowMask |
            AppKit.NSClosableWindowMask |
            AppKit.NSResizableWindowMask |
            AppKit.NSMiniaturizableWindowMask,
            AppKit.NSBackingStoreBuffered, False)
        # NSView
        self.canvas = MyView.alloc().initWithFrame_(rect)
        self.contentView().addSubview_(self.canvas)
        # etc
        self.setTitle_('Sample')
        return self

class AppDelegate(AppKit.NSObject):

    wins = []

    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        self.wins.append(window)
        AppKit.NSApp.activateIgnoringOtherApps_(True)

    def applicationSupportsSecureRestorableState_(self, app):
        return True

class AppMenu(AppKit.NSMenu):
    def init(self):
        objc.super(AppMenu, self).init()
        item_app  = AppKit.NSMenuItem.new()
        self.addItem_(item_app)
        menu_app = AppKit.NSMenu.new()
        item_app.setSubmenu_(menu_app)
        # quit menu
        item_quit = AppKit.NSMenuItem.new()
        item_quit.initWithTitle_action_keyEquivalent_('Quit App', 'terminate:', 'q')
        menu_app.addItem_(item_quit)
        return self

AppKit.NSApplication.sharedApplication()
AppKit.NSApp.setMainMenu_(AppMenu.new())
AppKit.NSApp.setDelegate_(AppDelegate.new())
AppKit.NSApp.run()

webp/pop.webp

NSSlider
NSSlider は名前のとおりスライダーです。

#!/usr/bin/env python3

import AppKit, objc

class MyView(AppKit.NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # 普通に作る、初期値は 0.0〜1.0
        #
        slider1 = AppKit.NSSlider.sliderWithTarget_action_(self, 'onSlide1:')
        slider1.setFrameOrigin_((10, 10))
        self.addSubview_(slider1)
        #slider1.setSliderType_(NSSliderTypeCircular) # 使いづらい
        #
        # カスタマイズ版、メソッド名で何を指定しているか解るはず
        # ちなみに整数で指定しても勝手に float と解釈してくれる
        #
        slider2 = AppKit.NSSlider.sliderWithValue_minValue_maxValue_target_action_(
            120, 80, 200, self, 'onSlide2:')
        # メモリの表示、線の数を指定
        slider2.setNumberOfTickMarks_(7)
        # メモリ上にしか止まらないように
        slider2.setAllowsTickMarkValuesOnly_(True)
        # 配置
        slider2.setFrameOrigin_((10, 40))
        self.addSubview_(slider2)
        #
        # 上記の数値を表示するラベル
        #
        self.label = AppKit.NSTextField.labelWithString_('80.0')
        self.label.setFrameOrigin_((150, 40))
        self.addSubview_(self.label)
        #
        return self

    def onSlide1_(self, sender):
        # 選択を変更するとココに来る
        print(sender.floatValue())

    def onSlide2_(self, sender):
        # 選択を変更、label を変更
        self.label.setStringValue_(f'{sender.floatValue()}')
        # はみ出さないように
        self.label.sizeToFit()

    def isFlipped(self):
        # 左上を原点にする
        return True

class MyWindow(AppKit.NSWindow):
    def init(self):
        rect = AppKit.NSMakeRect(0, 0, 220, 100)
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            rect,
            AppKit.NSTitledWindowMask |
            AppKit.NSClosableWindowMask |
            AppKit.NSResizableWindowMask |
            AppKit.NSMiniaturizableWindowMask,
            AppKit.NSBackingStoreBuffered, False)
        # NSView
        self.canvas = MyView.alloc().initWithFrame_(rect)
        self.contentView().addSubview_(self.canvas)
        # etc
        self.setTitle_('Sample')
        return self

class AppDelegate(AppKit.NSObject):

    wins = []

    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        self.wins.append(window)
        AppKit.NSApp.activateIgnoringOtherApps_(True)

    def applicationSupportsSecureRestorableState_(self, app):
        return True

class AppMenu(AppKit.NSMenu):
    def init(self):
        objc.super(AppMenu, self).init()
        item_app  = AppKit.NSMenuItem.new()
        self.addItem_(item_app)
        menu_app = AppKit.NSMenu.new()
        item_app.setSubmenu_(menu_app)
        # quit menu
        item_quit = AppKit.NSMenuItem.new()
        item_quit.initWithTitle_action_keyEquivalent_('Quit App', 'terminate:', 'q')
        menu_app.addItem_(item_quit)
        return self

AppKit.NSApplication.sharedApplication()
AppKit.NSApp.setMainMenu_(AppMenu.new())
AppKit.NSApp.setDelegate_(AppDelegate.new())
AppKit.NSApp.run()

webp/sl.webp

NSSegmentedControl
NSSegmentedControl はボタンのグループ化を超簡単に実現してくれます。

#!/usr/bin/env python3

import AppKit, objc

buttons = ['ボタンの', 'グループ化は', '簡単', 'です']

class MyView(AppKit.NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # システム環境設定のディスプレイとかで使われているアレ
        #
        sc = AppKit.NSSegmentedControl.segmentedControlWithLabels_trackingMode_target_action_(
            buttons, AppKit.NSSegmentSwitchTrackingSelectOne, self, 'onSeg:')
        # インデックスで選択を指定
        sc.setSelectedSegment_(1)
        sc.setFrameOrigin_((10, 10))
        self.addSubview_(sc)
        #
        return self

    def onSeg_(self, sender):
        # 選択を変更するとココに来る
        print(sender.selectedSegment())

    def isFlipped(self):
        # 左上を原点にする
        return True

class MyWindow(AppKit.NSWindow):
    def init(self):
        rect = AppKit.NSMakeRect(0, 0, 300, 100)
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            rect,
            AppKit.NSTitledWindowMask |
            AppKit.NSClosableWindowMask |
            AppKit.NSResizableWindowMask |
            AppKit.NSMiniaturizableWindowMask,
            AppKit.NSBackingStoreBuffered, False)
        # NSView
        self.canvas = MyView.alloc().initWithFrame_(rect)
        self.contentView().addSubview_(self.canvas)
        # etc
        self.setTitle_('Sample')
        return self

class AppDelegate(AppKit.NSObject):

    wins = []

    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        self.wins.append(window)
        AppKit.NSApp.activateIgnoringOtherApps_(True)

    def applicationSupportsSecureRestorableState_(self, app):
        return True

class AppMenu(AppKit.NSMenu):
    def init(self):
        objc.super(AppMenu, self).init()
        item_app  = AppKit.NSMenuItem.new()
        self.addItem_(item_app)
        menu_app = AppKit.NSMenu.new()
        item_app.setSubmenu_(menu_app)
        # quit menu
        item_quit = AppKit.NSMenuItem.new()
        item_quit.initWithTitle_action_keyEquivalent_('Quit App', 'terminate:', 'q')
        menu_app.addItem_(item_quit)
        return self

AppKit.NSApplication.sharedApplication()
AppKit.NSApp.setMainMenu_(AppMenu.new())
AppKit.NSApp.setDelegate_(AppDelegate.new())
AppKit.NSApp.run()

webp/gl.webp

Copyright(C) sasakima-nao All rights reserved 2002 --- 2024.