Paepoi

Paepoi » PyObjC Tips » その他 NSControl

その他 NSControl

最終更新日 2019.05.19

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

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

#!/usr/bin/env python3

from AppKit import *

RECT = ((0, 0), (220, 100))
wins = []
items = ['白襟', '襟カバー', '巨大な襟', '中パー']

class MyView(NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # NSComboBox @ NSTextField のサブクラス
        # 高さを厳密にしないとズレて表示されるのでこんな感じに
        #
        self.cbox = 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(NSWindow):
    def init(self):
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            RECT,
            NSTitledWindowMask | NSClosableWindowMask |
            NSResizableWindowMask | NSMiniaturizableWindowMask,
            NSBackingStoreBuffered, False)
        self.center()
        self.setTitle_('NSComboBox')
        self.setDelegate_(self)
        # View
        self._view = MyView.alloc().initWithFrame_(RECT)
        self.contentView().addSubview_(self._view)
        #
        return self

    def windowWillClose_(self, sender):
        #
        # 終了時に値を書き出し
        # 何も選択していない場合は -1 になる
        #
        num = self._view.cbox.indexOfSelectedItem()
        if num > -1:
            print(f'貴方は{items[num]}が好き')
            # 下記でもいい
            #print(f'貴方は{self._view.cbox.objectValueOfSelectedItem()}が好き')

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        wins.append(window)

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

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

img/nscombobox.png

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

#!/usr/bin/env python3

from AppKit import *

RECT = ((0, 0), (220, 100))
wins = []
items = ['Apache の', 'アイコンを', '勝手に使って', 'ごめんなチャイ']

class MyView(NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # NSPopUpButton @ NSButton のサブクラス
        # autoenablesItems プロパティを True にしないと変化しない
        #
        self.pbtn = 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 = 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(NSWindow):
    def init(self):
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            RECT,
            NSTitledWindowMask | NSClosableWindowMask |
            NSResizableWindowMask | NSMiniaturizableWindowMask,
            NSBackingStoreBuffered, False)
        self.center()
        self.setTitle_('NSPopUpButton')
        self.setDelegate_(self)
        # View
        self._view = MyView.alloc().initWithFrame_(RECT)
        self.contentView().addSubview_(self._view)
        #
        return self

    def windowWillClose_(self, sender):
        # 終了時に値を書き出し
        print(self._view.pbtn.title())
        # index ならこう得る
        #num = self._view.pbtn.indexOfSelectedItem()

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        wins.append(window)

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

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

img/nspopupbutton.png

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

#!/usr/bin/env python3

from AppKit import *

RECT = ((0, 0), (220, 100))
wins = []

class MyView(NSView):
    def initWithFrame_(self, rect):
        objc.super(MyView, self).initWithFrame_(rect)
        #
        # 普通に作る、初期値は 0.0〜1.0
        #
        slider1 = NSSlider.sliderWithTarget_action_(self, 'onSlide1:')
        slider1.setFrameOrigin_((10, 10))
        self.addSubview_(slider1)
        #slider1.setSliderType_(NSSliderTypeCircular) # 使いづらい
        #
        # カスタマイズ版、メソッド名で何を指定しているか解るはず
        # ちなみに整数で指定しても勝手に float と解釈してくれる
        #
        slider2 = 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 = 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(NSWindow):
    def init(self):
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            RECT,
            NSTitledWindowMask | NSClosableWindowMask |
            NSResizableWindowMask | NSMiniaturizableWindowMask,
            NSBackingStoreBuffered, False)
        self.center()
        self.setTitle_('NSSlider')
        #self.setDelegate_(self)
        # View
        self._view = MyView.alloc().initWithFrame_(RECT)
        self.contentView().addSubview_(self._view)
        #
        return self

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        wins.append(window)

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

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

img/nsslider.png

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

#!/usr/bin/env python3

from AppKit import *

RECT = ((0, 0), (300, 100))
wins = []
buttons = ['ボタンの', 'グループ化は', '簡単', 'です']

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

    def onSeg_(self, sender):
        # 選択を変更するとココに来る
        print(sender.selectedSegment())
        #print(sender.intValue()) 実はコレと同じ

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

class MyWindow(NSWindow):
    def init(self):
        objc.super(MyWindow, self).initWithContentRect_styleMask_backing_defer_(
            RECT,
            NSTitledWindowMask | NSClosableWindowMask |
            NSResizableWindowMask | NSMiniaturizableWindowMask,
            NSBackingStoreBuffered, False)
        self.center()
        self.setTitle_('NSSegmentedControl')
        #self.setDelegate_(self)
        # View
        self._view = MyView.alloc().initWithFrame_(RECT)
        self.contentView().addSubview_(self._view)
        #
        return self

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, notification):
        window = MyWindow.new()
        window.makeKeyAndOrderFront_(window)
        wins.append(window)

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

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

img/nssegmentedcontrol.png

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