PyObjC NSCollectionView

JXA で後回しにし続けていた画像サムネイル表示をそろそろ作りたい。

NSCollectionView – AppKit | Apple Developer Documentation

どうやらコレを使えばイケるらしい。
色々遠回りしたけど上手くいったコードをいきなり。

#!/usr/bin/env python3

import objc, os, re
from AppKit import *

PATH = '/Users/sasakima-nao/Pictures/nae'

class ItemView(NSView):
    def init(self):
        objc.super(ItemView, self).init()
        self.image = None
        return self

    def drawRect_(self, rect):
        self.image.drawInRect_(rect)

class CollectionViewItem(NSCollectionViewItem):
    def init(self):
        objc.super(CollectionViewItem, self).init()
        self.setView_(ItemView.alloc().initWithFrame_(NSMakeRect(0, 0, 100, 100)))
        return self

    def setRepresentedObject_(self, rep):
        objc.super(CollectionViewItem, self).setRepresentedObject_(rep)
        if rep != None:
            self.view().image = rep['pic']

class ComipoliCollectionView(NSCollectionView):
    def init(self):
        objc.super(ComipoliCollectionView, self).init()
        a = []
        l = os.listdir(PATH)
        for s in l:
            if re.search(r'\.(jpg|png)$', s, re.I):
                f = '{0}/{1}'.format(PATH, s)
                image = NSImage.alloc().initWithContentsOfFile_(f)
                a.append({'pic': image})
        self.setItemPrototype_(CollectionViewItem.new())
        self.setContent_(a)
        return self


class ComipoliWindow(NSWindow):
    def init(self):
        frame = NSMakeRect(100, 400, 400, 300)
        objc.super(ComipoliWindow, self).initWithContentRect_styleMask_backing_defer_(
            frame,
            NSTitledWindowMask |
            NSClosableWindowMask |
            NSResizableWindowMask |
            NSMiniaturizableWindowMask,
            NSBackingStoreBuffered,
            False)
        self.setTitle_('thumbnail')
        self.setDelegate_(self)
        # view
        self.canvas = ComipoliCollectionView.new()
        self.canvas.setFrameSize_(frame.size)
        self.contentView().addSubview_(self.canvas)
        return self

    def windowDidResize_(self, sender):
        aw = self.contentView().frame().size.width
        ah = self.contentView().frame().size.height
        size = NSMakeSize(aw, ah)
        self.canvas.setFrameSize_(size)

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

NSApplication.sharedApplication()
window = ComipoliWindow.new()
window.makeKeyAndOrderFront_(window)
NSApp.setMainMenu_(ComipoliMenu.new())
NSApp.activateIgnoringOtherApps_(True)
NSApp.run()

NSCollectionView, NSCollectionViewItem, NSView が最小限必要。
表示したい NSImage は適当なキーで辞書にいれて配列に突っ込む。
辞書毎に setRepresentedObject_ が呼ばれるので取り出す。
他にも手段があるようだけど、一つの方法として。

後選択可能にしたりとかもやらないと。
画像や PDF のリサイズやバックグラウンド処理をやらないと。
苗ちゃんの画像が古いのは実はもうやっていないからだとか。