Hello World / plɹoM ollǝH

Programmers Live in Vain

QTreeWidgetItemでアイコン複数表示

HTMLを表示するdelegateを用意するのが手っ取り早い

f:id:dungeonneko:20170411134501p:plain

コードはここらへんを参考に

stackoverflow.com

PyQt版の回答をゴニョゴニョして作成

import sys
from PySide import QtCore, QtGui


class RichTextDelegate(QtGui.QStyledItemDelegate):
    def paint(self, painter, option, index):
        option_v4 = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(option_v4, index)
        doc = self.make_text(option_v4.text)

        option_v4.text = ""
        style = QtGui.QApplication.style()
        style.drawControl(QtGui.QStyle.CE_ItemViewItem, option_v4, painter)

        painter.save()
        rect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, option_v4)
        painter.translate(rect.topLeft())
        painter.setClipRect(rect.translated(-rect.topLeft()))
        context = QtGui.QAbstractTextDocumentLayout.PaintContext()
        if option_v4.state & QtGui.QStyle.State_Selected:
            context.palette.setColor(
                QtGui.QPalette.Text, option.palette.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
        doc.documentLayout().draw(painter, context)
        painter.restore()

    def sizeHint(self, option, index):
        option_v4 = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(option_v4, index)
        doc = self.make_text(option_v4.text)
        return QtCore.QSize(doc.idealWidth(), doc.size().height())

    def make_text(self, text):
        doc = QtGui.QTextDocument()
        doc.setDocumentMargin(1)
        f = QtGui.QTreeWidgetItem().font(0)
        f.setPointSize(11)
        doc.setDefaultFont(f)
        doc.setHtml(text)
        return doc


app = QtGui.QApplication(sys.argv)
tree = QtGui.QTreeWidget()
tree.setHeaderHidden(True)
tree.setItemDelegate(RichTextDelegate())
hoge = QtGui.QTreeWidgetItem()
hoge.setText(0, '<i>hoge</i> <img src="hoge.png"/><img src="hoge.png"/>')
fuga = QtGui.QTreeWidgetItem()
fuga.setText(0, '<b>fuga</b> <img src="hoge.png"/><img src="hoge.png"/><img src="hoge.png"/>')
piyo = QtGui.QTreeWidgetItem()
piyo.setText(0, '<font color="red">piyo</font>')
hoge.addChild(fuga)
hoge.addChild(piyo)
tree.addTopLevelItem(hoge)
tree.show()
sys.exit(app.exec_())

Raspberry Piでトイレにクラシック音楽を流す

人がきたら音楽を流す装置をトイレに設置しました(割と好評)

  • ケースはRaspberry Piの箱に100均で買った折り紙を貼って作成
  • 本体のUSBでBluetoothスピーカーを充電

f:id:dungeonneko:20170407163311j:plain

必要なもの

Raspberry Piと人感センサーの接続

下記ページを確認しながらRaspberry Piと人感センサーを接続

対応するピン同士をジャンパーワイヤで繋ぐ

人感センサー Raspberry Pi
+Power <---> 5V PWR
GND <---> GND
High/Low Output <---> GPIO18

人感センサーで音を鳴らすプログラムの作成

  • python
  • mp3を再生したかったのでpygameモジュール
  • スクリプトと同じフォルダにあるmp3をランダムで再生
     
import pygame, os, random, time, RPi.GPIO

pygame.init()
pygame.mixer.pre_init(44100, 16, 2, 1024 * 4)
pygame.mixer.init()
pygame.mixer.set_num_channels(8)
screen = pygame.display.set_mode((320, 240))
shutdown = False
clock = pygame.time.Clock()
files = []
active = False
last_activated = 0
pin = 18
RPi.GPIO.setmode(RPi.GPIO.BCM)
RPi.GPIO.setup(pin, RPi.GPIO.IN)

# 入力を検知したあとに何秒間流すか
timeout = 30

# 音楽の再生
def play_random_track():
    global files
    # 再生リストがなくなったらmp3ファイルを検索してシャッフル
    if not files:
        files = [f for f in os.listdir('./') if f.endswith('.mp3')]
        random.shuffle(files)
    # 再生リストから一番最初の音楽をとってきて鳴らす
    pygame.mixer.music.load(files.pop(0))
    pygame.mixer.music.set_volume(1.0)
    pygame.mixer.music.play()

# メインループ
while not shutdown:
    # 入力フラグ
    active = False

    # OSイベント処理
    for e in pygame.event.get():
        # 閉じるボタンやESCキーが入力されたらプログラムを終了する
        if e.type == pygame.QUIT or (e.type == pygame.KEYDOWN and e.key == 27):
            shutdown = True
            break
        # テスト用:Enterキーで音を鳴らせるようにしておく
        elif e.type == pygame.KEYDOWN and e.key == 13:
            active = True
            continue

    # 人感センサーからの入力
    if RPi.GPIO.input(pin) == RPi.GPIO.HIGH:
        active = True

    # 入力があったときの処理
    if active:
        # 入力時間を更新する
        last_activated = time.time()
        # 再生してないときは次のトラックを再生
        if not pygame.mixer.music.get_busy():
            play_random_track()

    # 最後の入力から一定時間(timeout秒)が経過したら音楽をフェードアウトさせる
    if (time.time() - last_activated) > timeout:
        if pygame.mixer.music.get_busy():
            pygame.mixer.music.fadeout(5000)

    pygame.display.flip()
    clock.tick(5)  # 処理負荷を抑える(1秒間に5回ループをまわす)

RPi.GPIO.cleanup()
pygame.quit()

電源入れたら自動でプログラムが動くようにする

以前の記事と同じ手順で起動時にBluetoothスピーカー接続&今回用意したスクリプトを起動するように修正

pulseaudio -D
sleep 5  # 適当にウェイト
bluetoothctl << EOF
power on
connect FF:FF:FF:FF:FF:FF  # BluetoothスピーカーのMACアドレス
quit
EOF
sleep 5  # 適当にウェイト
pacmd set-sink-volume 1 32767  # 音量調節(デバイス番号、音量~65565)

cd otohime
python3.4 otohime.py

Haskell環境構築メモ

これは自分のためのメモだから良い子は見ちゃダメ

OS: Windows10, IDE: Atom

インストール

1. Haskell PlatformからインストーラをDLして実行

www.haskell.org

適当にNext押してたら%APPDATA%\local\binにインストールされてパスが通った

stackのセットアップもすぐやったほうがいい

stack setup
2. ide-haskellのページを見ながら必要なものをインストール

バイナリ

stack install stylish-haskell
stack install ghc-mod
stack install hlint

Atomパッケージ

apm install language-haskell haskell-ghc-mod ide-haskell-cabal ide-haskell autocomplete-haskell

プロジェクトの作成

cd parentDir
stack new projectName

依存パッケージの追加

.cabalファイルのビルドターゲットのbuild-dependesにカンマ区切りで追加して

cabal install

実行

cabal run

環境構築がもうちょっと簡単になら流行りそうなのに

Python3でSkypeにメッセージ送信

skpyを使います

準備

pip install skpy

最近のイベントからグループチャットを検索してメッセージ送信

from skpy import Skype


def send(user, password, topic, message):
    sk = Skype(user, password)
    for c in sk.chats.recent():
        chat = sk.chats[c]
        if hasattr(chat, 'topic') and chat.topic == topic:
            chat.sendMsg(message)
            break


if __name__ == '__main__':
    send('hogehoge', 'password1234', 'group chat name', 'hello world')

PySide ドラッグ&ドロップ

忘れがちなポイント

  • setAcceptDrops(True)
  • 各イベントでevent.accept
  • ファイルパスはTextじゃなくてURL

f:id:dungeonneko:20170307160033g:plain

from PySide import QtCore, QtGui
import sys, os

class DragAndDrop(QtGui.QLabel):
    def __init__(self):
        super().__init__()
        self.setText('Drag and drop here')
        self.setAlignment(QtCore.Qt.AlignCenter)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        filename = os.path.basename(event.mimeData().urls()[0].path())
        self.setText(filename)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    w = DragAndDrop()
    w.show()
    sys.exit(app.exec_())

QMessageBoxでチョロっとダイアログ表示

f:id:dungeonneko:20170222145049g:plain

import sys
from PySide import QtGui

app = QtGui.QApplication(sys.argv)
icon = None
QtGui.QMessageBox.about(icon, 'About', 'Hello.')
QtGui.QMessageBox.question(icon, 'Question', 'Are you dead?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
QtGui.QMessageBox.information(icon, 'Info', 'You are dead!', QtGui.QMessageBox.Ok)
QtGui.QMessageBox.warning(icon, 'Warn', 'You are dead!', QtGui.QMessageBox.Ok)
QtGui.QMessageBox.critical(icon, 'Error', 'You are dead!', QtGui.QMessageBox.Ok)

戻り値は君の眼で確かめてみてくれ!

Pythonでウインドウハンドル取得してGetClientRectしてみる

WIN32から離れられない貴方へ

import sys
from PySide import QtGui
import ctypes


class RECT(ctypes.Structure):
    _fields_ = [('left', ctypes.c_long),
                ('top', ctypes.c_long),
                ('right', ctypes.c_long),
                ('bottom', ctypes.c_long)]


class TestWidget(QtGui.QWidget):
    def __init__(self):
        super().__init__()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        
        # ここから!
        ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
        ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
        hwnd = ctypes.pythonapi.PyCapsule_GetPointer(self.winId(), None)
        rect = RECT()
        ctypes.windll.user32.GetClientRect(hwnd, ctypes.byref(rect))
        print(rect.left, rect.top, rect.right, rect.bottom)

if __name__ == '__main__':
    a = QtGui.QApplication(sys.argv)
    w = TestWidget()
    w.show()
    sys.exit(a.exec_())

参考記事

stackoverflow.com