PySide2 ビルドしてみる
ここ見たら大体書いてあるよ
https://wiki.qt.io/PySide2_GettingStarted
PySide2最新の状況はこのへんをチェック
環境
- Windows10
- Python 3.6 (64bit)
- Qt 5.6
- OpenSSLは使わないよ
インストールしておくもの
ビルド
- pyside-setupリポジトリの5.6ブランチをrecursiveでcloneする
- 一応virtualenvでビルド環境つくってactivate
- sphinxモジュールをインストール
- VCコンパイラのパス通す
- 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よりもっさりする)
メモ
まとめ
まぁこんなもんかなという感じ。僕は今からコールドスリープするから
transbook t90の後継機が出たら起こしてくれ
PySide 編集可能なQTreeWidgetを作る
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_())
PySide movable and resizable widget without frame
import sys, enum from PySide import QtCore, QtGui class Item(QtGui.QLabel): Manipilate = enum.Enum('Manipilate', 'none move resize_l resize_r') def __init__(self, text): super().__init__(text) self.setStyleSheet('background-color: white; border: 1px solid black; padding: 4px;') self.resize(128, 64) self._mani = Item.Manipilate.none self._offset = QtCore.QPoint(0, 0) self._rect = self.rect() self.setMouseTracking(True) def mousePressEvent(self, event): pos = event.pos() if self._mani == Item.Manipilate.none: self._mani = self.get_manipulation(pos) self._offset = event.pos() self._rect = self.geometry() def mouseReleaseEvent(self, event): self._mani = Item.Manipilate.none def mouseMoveEvent(self, event): pos = event.pos() if self._mani == Item.Manipilate.none: self.setCursor({ Item.Manipilate.none: QtCore.Qt.ArrowCursor, Item.Manipilate.move: QtCore.Qt.ArrowCursor, Item.Manipilate.resize_l: QtCore.Qt.SizeHorCursor, Item.Manipilate.resize_r: QtCore.Qt.SizeHorCursor }[self.get_manipulation(pos)]) elif self._mani == Item.Manipilate.move: self.move(self.mapToParent(pos - self._offset)) elif self._mani == Item.Manipilate.resize_l: sub = pos - self._offset self.setGeometry(self._rect.x() + sub.x(), self._rect.y(), self._rect.width() - sub.x(), self._rect.height()) self._rect = self.geometry() elif self._mani == Item.Manipilate.resize_r: sub = pos - self._offset self.setGeometry(self._rect.x(), self._rect.y(), self._rect.width() + sub.x(), self._rect.height()) self.update() def get_manipulation(self, pos): if pos.x() < 8: return Item.Manipilate.resize_l if pos.x() > (self.width() - 8): return Item.Manipilate.resize_r else: return Item.Manipilate.move app = QtGui.QApplication(sys.argv) widget = QtGui.QWidget() widget.setFixedSize(640, 480) item = Item('item') item.setParent(widget) item.move(0, 0) widget.show() sys.exit(app.exec_())
PySide Progressbarを表示してみる
QProgressDialogを使うと一番簡単であります
import sys from PySide import QtGui app = QtGui.QApplication(sys.argv) prog = QtGui.QProgressDialog('何か処理しています...', 'キャンセル', 0, 100, None, 0) prog.show() prog.setValue(50) sys.exit(app.exec_())
キャンセルボタンなくしたい
コンストラクタのキャンセルボタンのテキストにNoneを指定
QtGui.QProgressDialog('何か処理しています...', None, 0, 100, None, 0)
ウインドウのボタンを消したい
コンストラクタの最後の引数でウインドウフラグを指定
QtGui.QProgressDialog('何か処理しています...', 'キャンセル', 0, 100, None, QtCore.Qt.Window | QtCore.Qt.WindowTitleHint | QtCore.Qt.CustomizeWindowHint)
リサイズなくしたい
setFixedSizeを呼ぶ
prog.setFixedSize(prog.sizeHint())
Marqueeスタイル(進捗表示しないで処理の終了だけ待つやつ)にしたい
プログレスバーの範囲を 0 ~ 0 にする
QtGui.QProgressDialog('何か処理しています...', 'キャンセル', 0, 0, None, 0)
バー横の空白が残る場合は進捗表示テキストをセンター寄せすればいい
prog.setStyleSheet('QProgressBar {text-align: center;}')
QScrollAreaに固定されたヘッダーを表示する
import sys from PySide import QtGui class MyTable(QtGui.QWidget): def __init__(self): super().__init__() lo = QtGui.QHBoxLayout() lo.setContentsMargins(0, 0, 0, 0) lo.setSpacing(0) self.setLayout(lo) self._header = QtGui.QLabel('header') self._header.setStyleSheet('border-right: 1px solid black;\ border-bottom: 1px solid black;\ background-color: red;') self._header.setFixedSize(128, 32) lo.addWidget(self._header) for i in range(0, 8): item = QtGui.QLabel('cell {0}'.format(i)) item.setStyleSheet('border-right: 1px solid black;\ border-bottom: 1px solid black;\ background-color: white;') item.setFixedSize(128, 32) lo.addWidget(item) def setHeaderPos(self, x, y): self._header.move(x, y) self._header.raise_() app = QtGui.QApplication(sys.argv) table = MyTable() scroll = QtGui.QScrollArea() scroll.setWidget(table) def moveHeader(): x = scroll.horizontalScrollBar().value() table.setHeaderPos(x, 0) scroll.horizontalScrollBar().valueChanged.connect(moveHeader) scroll.show() sys.exit(app.exec_())
スライダーの移動量を固定する
下記コードを追加する
def scrollControll(x): x = int(x / 128) * 128 scroll.horizontalScrollBar().setValue(x) scroll.horizontalScrollBar().setSingleStep(128) # ボタン押された時の移動量 scroll.horizontalScrollBar().sliderMoved.connect(scrollControll)