Hello World / plɹoM ollǝH

Programmers Live in Vain

pythonのreversedはイテレータを返す

反転したリストを複数回使うときにハマった

a = reversed([1, 2, 3])  # イテレータを返す
for x in a:
    print(x)
for x in a:
    print(x)  # ここは呼ばれない

reverseなどでリスト自体を反転させておくか

a = [1, 2, 3]
a.reverse()

for文ごとにreversedを呼べばOK

a = [1, 2, 3]
for x in reversed(a):
    print(x)
for x in reversed(a):
    print(x)

ちなみにsortedはリストを返す模様

プログラマのためのMaya攻略法

Mayaの内部構造をgoogle先生をウロウロしながら理解するのは効率が悪いので次の方法がおすすめ

  1. Complete Maya Programmingを読む
  2. devkitのサンプルを覗く
  3. MELコマンドの仕様はリファレンスを読む

Complete Maya Programmingは分厚く読むのは疲れるが、ツールを自作するときにも役立つ情報満載なので一度は読んでおいたほうが良いだろう。骨デジタルさんから日本語版も発売されている。Kindle版が欲しいから英語版を買ったけど日本語版買うべきだったな。一社に一冊欲しい。

devkitには今流行のAlembicのサンプルなんかもあったりします。そういえばCOLLADAってどうなったんですかね?

PySide1と2でQScrollArea::wheelEventの動作が若干違う

違うんじゃあああああああああああああああああぁぁぁぁあああばばばっばばばば

# from PySide2.QtWidgets import *
from PySide.QtGui import *
import sys

app = QApplication(sys.argv)

class MyWidget(QWidget):
    def wheelEvent(self, event):
        print('hoge')

class MyScrollArea(QScrollArea):
    def wheelEvent(self, event):
        print('fuga')  # PySide1のときは呼ばれてないっぽい

scrollArea = MyScrollArea()
w = MyWidget()
w.setFixedSize(640, 480)
scrollArea.setWidget(w)
scrollArea.show()
sys.exit(app.exec_())

QTimer.singleShotをサブスレッドで使うには

呼び出しスレッド側でexec関数をよんでイベントループを開始せよ

QTimer Class | Qt 4.8

In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.

イベントループにはいるとexitを呼ぶまで帰ってこないので注意

from PySide import QtCore, QtGui
import sys, time

class SingleShotThread(QtCore.QThread):
    def run(self):
        QtCore.QTimer.singleShot(1000, lambda: print('hoge'))
        self.exec_()  # イベントループ開始

app = QtGui.QApplication(sys.argv)
th = SingleShotThread()
th.finished.connect(lambda: print('finished'))
th.start()
time.sleep(3)
th.exit()  # exitを呼んで終了させる
sys.exit(app.exec_())

PySide2 ビルドしてみる

ここ見たら大体書いてあるよ

https://wiki.qt.io/PySide2_GettingStarted

PySide2最新の状況はこのへんをチェック

環境

  • Windows10
  • Python 3.6 (64bit)
  • Qt 5.6
  • OpenSSLは使わないよ

インストールしておくもの

ビルド

  1. pyside-setupリポジトリの5.6ブランチをrecursiveでcloneする
  2. 一応virtualenvでビルド環境つくってactivate
  3. sphinxモジュールをインストール
  4. VCコンパイラのパス通す
  5. wheelビルド実行
こんな感じ
> git clone -b 5.6 http://code.qt.io/cgit/pyside/pyside-setup.git/ --recursive
> pip install virtualenv
> virtualenv hogehoge
> hogehoge/Scripts/activate.bat
> pip install sphinx
> cd pyside-setup
> "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
> python setup.py bdist_wheel --ignore-git --qmake="C:\Qt\Qt5.6.2\5.6\msvc2015_64\bin\qmake.exe" --cmake="C:\Program Files\CMake\bin\cmake.exe"
fcntlを呼ぼうとしてエラーが出る?

popenasync.pyのdecode関数を適当に修正
(たぶん日本語表示しようとして例外出てる)

def decode(b):
    try:
        return b.decode('utf-8')
    except UnicodeDecodeError:
        return b.decode('shift-jis')

英語圏へ対応する気はなさそうだ

shibokenのドキュメントビルドでMarkupSafeのエラーが出る?

pip install sphinxでMarkupSafeのインストールに失敗しているのでいつものところからwheelを落とす

pip uninstall MarkupSafe
pip install MarkupSafe‑1.0‑cp36‑cp36m‑win_amd64.whl

こんな感じで再インストール

RC Pass 1 failed to run. というエラーが出る?

rc.exeにパスが通っていないか別プラットフォームのrc.exeを読んで失敗している

set PATH=%PATH%;C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x64

こんな感じでrc.exeのある場所にパスを通すか、WindowsSDKをインストールしなおすと良いと思う

bdist_wheelコマンドが見つからない?
pip install wheel

もしくはこのあたりを参考に

リンクエラーが発生する?

prebuiltなものとビルドターゲットがズレてると出る気がする。32bit版のPythonとかQtを使ってるとか、vcvarsall.bat呼ぶときにamd64つけてないとか

whlのサイズが大きいのが気になる?

setup.pyのdllコピーの規則がQt4時代から変わってないのが原因

  • デバッグ用のdllも含まれてしまっている
  • setup.pyの *d4.dll, *d?.dll となっている箇所を *d.dll に修正する
  • platformsのdllコピーしてるところに ignore=['*d.dll'] を追加する
pyside2uic.Compiler, pyside2uic.port_v3モジュールを使いたい?

setup.pyのsetup()の引数を変更する

packages = ['PySide2', 'pyside2uic', 'pyside2uic.Compiler', 'pyside2uic.port_v3']

PySide Custom Dialog

Dialogを自分で実装するときのポイント
  • QDialogを継承する
  • ボタン表示にはQDialogButtonBoxを使う
こんなかんじ
from PySide import QtCore, QtGui
import sys


class CustomDialog(QtGui.QDialog):
    def __init__(self):
        super().__init__()
        self._buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
        self._buttons.accepted.connect(self.accept)
        self._buttons.rejected.connect(self.reject)
        mainLayout = QtGui.QVBoxLayout()
        mainLayout.addWidget(self._buttons)
        self.setLayout(mainLayout)
        self.setWindowTitle('Custom Dialog')


app = QtGui.QApplication(sys.argv)
mainwindow = QtGui.QMainWindow()
mainwindow.show()
dialog = CustomDialog()
if QtGui.QDialog.Accepted == dialog.exec_():
    QtGui.QMessageBox.information(None, 'Info', 'accepted!', QtGui.QMessageBox.Ok)
else:
    QtGui.QMessageBox.critical(None, 'Info', 'rejected!', QtGui.QMessageBox.Ok)