はんぎょねこの憂鬱

耳から変な汁が出てきた

PySide keyPressEventが反応しないとき

もしかして

self.setFocusPolicy(QtCore.Qt.StrongFocus)

し忘れているんじゃないでしょうか。

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)
広告を非表示にする

ねんがんの GPD Pocket をてにいれたぞ

とりあえず一台ゲットしたので適当レビュー
使っているうちに意見をコロコロ変える可能性あります

スペックおさらい

OS Ubuntu 16.04 LTS or Windows 10 Home
CPU 🤔 Quad-core 1.6GHz
GPU Integrated processor
RAM 8GB
ストレージ容量 128GB (😬 Samsung MDGAGC)
画面の大きさ 😀 1920×1200,7 inch, 323.45PPI
画面の素材 Corning Gorilla Glass 3
冷却 Active Cooling(意外とうるさい)
サイズ 😀 180×106×18.5mm
素材 CNC precise all-in-one body made of magnesium and alloy
MacBookみたいなやつ)
Weight 😀 480g
バッテリー 😀 12時間
価格 😀 Indiegogo price $399, Retail price $599

詳細はIndiegogoのプロジェクトページを見てよ

気に入っているところ

  • 安い($399でゲットした)!頑丈!持ちやすい!小さい!
  • USB Type-Aポートがついてる
  • ディスプレイが綺麗
  • 持ち歩いてると「おっ、何それ?」って言われる

気に入らない点

  • CPUパフォーマンス全然足りない
  • 本体右側が熱い。タイピングしてると熱いな~ってなる
  • えっ?USB Type-Cポート1個しかないのに電源ケーブルに使うの?
  • Capsキー小さくて押しづらい
  • スペースキーとクリックを間違えることがよくある
  • スペースキーが二つに分かれてるのがキモい
  • トラックポイントはGとHの間に欲しい
  • 純正トラックポイントがツルツルしてて滑る
  • スピーカーの音質が気に食わない&イヤホンジャックのノイズが多い
  • ストレージがeMMC(SSDよりもっさりする)

f:id:dungeonneko:20170713002414p:plain

メモ

  • 次のモデルはSIMカード対応するという噂
  • 無線LAN802.11acしか対応してないっぽい
  • キー配置は慣れれば思ったより気にならない

まとめ

まぁこんなもんかなという感じ。僕は今からコールドスリープするから
transbook t90の後継機が出たら起こしてくれ

PySide 編集可能なQTreeWidgetを作る

f:id:dungeonneko:20170622151448g:plain

import sys
from PySide import QtCore, QtGui


class MyTreeWidget(QtGui.QTreeWidget):
    def __init__(self):
        super().__init__()
        self.setHeaderHidden(True)
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.contextMenuRequested)

        # アイテムの移動を有効にする
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.setDragEnabled(True)
        self.viewport().setAcceptDrops(True)

        # 挿入位置カーソルを表示する
        self.setDropIndicatorShown(True)

    def contextMenuRequested(self, pos):
        """ コンテキストメニュー
        """
        menu = QtGui.QMenu()
        item = self.itemAt(pos)
        if item:
            action = QtGui.QAction('Delete Item', self)
            action.triggered.connect(lambda: self.removeItem(item))
            menu.addAction(action)
        else:
            action = QtGui.QAction('New Item', self)
            action.triggered.connect(self.createNewItem)
            menu.addAction(action)
        menu.exec_(self.mapToGlobal(pos))

    def createNewItem(self):
        """ 新規項目
        """
        item = QtGui.QTreeWidgetItem()
        item.setText(0, 'Item')

        # アイテムを編集可能にする
        item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)

        self.addTopLevelItem(item)

    def removeItem(self, item):
        """ 項目削除
        """
        parent = item.parent()
        if parent:
            parent.takeChild(parent.indexOfChild(item))
        else:
            self.takeTopLevelItem(self.indexOfTopLevelItem(item))


app = QtGui.QApplication(sys.argv)
tr = MyTreeWidget()
tr.show()
sys.exit(app.exec_())