はんぎょねこの憂鬱

耳から変な汁が出てきた

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

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

スペックおさらい

OS Ubuntu 16.04 LTS or Windows 10 Home
CPU 🤔 Quad-core 1.6GHz
GPU Integrated processor
RAM 8GB
ストレージ容量 128GB (😬 Samsung MDGAGC 200MB/sec)
画面の大きさ 😀 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パフォーマンス全然足りない(AirもSurface3も持ってないんだけど同じくらいらしい)
  • 本体右側が熱い。松岡修造が住んでるんじゃないか?タイピングしてると熱いな~ってなる
  • えっ?USB Type-Cポート1個しかないのに電源ケーブルに使うの?
  • Capsキーを間違えて押しちゃう&小さくて意図的には押しづらい(半角全角切替に使う ⇒ Alt+`で切り替えることにした)
  • スペースキーとクリックを間違えることがよくある
  • スペースキーが二つに分かれてるのがキモい
  • トラックポイントはGとHの間に欲しい(親指が横に当たるので操作しづらい)
  • トラックポイントがツルツルしてて滑る(手元にあるThinkpad X61のキャップと交換したがサイズが微妙に違うのかトラックポイントを動かした際にフチがあたってしまう⇒新品のキャップだと大丈夫でした。蓋を閉じたときスクリーンに跡がつくけど)
  • スピーカーの音質が気に食わない&イヤホンジャックのノイズが多い
  • ストレージがMDGAGC(SSDよりもっさりする。Antimalwareが動いてる間は使い物にならない。せめてMCG8GCにしてほしかった)

f:id:dungeonneko:20170713002414p:plain

メモ

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

まとめ

まぁこんなもんかなという感じ。僕は今からコールドスリープするから
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_())

PySide movable and resizable widget without frame

f:id:dungeonneko:20170619180539g:plain

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を使うと一番簡単であります

f:id:dungeonneko:20170612143019g:plain

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スタイル(進捗表示しないで処理の終了だけ待つやつ)にしたい

f:id:dungeonneko:20170612153620g:plain

プログレスバーの範囲を 0 ~ 0 にする

QtGui.QProgressDialog('何か処理しています...', 'キャンセル', 0, 0, None, 0)

バー横の空白が残る場合は進捗表示テキストをセンター寄せすればいい

prog.setStyleSheet('QProgressBar {text-align: center;}')

QScrollAreaに固定されたヘッダーを表示する

f:id:dungeonneko:20170605143912g:plain

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_())

スライダーの移動量を固定する

f:id:dungeonneko:20170605163459g:plain

下記コードを追加する

def scrollControll(x):
    x = int(x / 128) * 128
    scroll.horizontalScrollBar().setValue(x)

scroll.horizontalScrollBar().setSingleStep(128)  # ボタン押された時の移動量
scroll.horizontalScrollBar().sliderMoved.connect(scrollControll)

PySide ドラッグでデータ受け渡し

f:id:dungeonneko:20170525143550g:plain

import sys
from PySide import QtCore, QtGui


# ドラッグ&ドロップで色を受け渡す
class WidgetItem(QtGui.QLabel):
    def __init__(self, color):
        super().__init__('')
        self._color = color
        self.setStyleSheet('border: 1px solid black;')
        self.setFixedSize(32, 32)
        self.setAcceptDrops(True)

    def paintEvent(self, event):
        self.changeColor()
        super().paintEvent(event)

    def changeColor(self):
        pal = QtGui.QPalette(self.palette())
        pal.setColor(QtGui.QPalette.Window, QtGui.QColor(self._color))
        self.setAutoFillBackground(True)
        self.setPalette(pal)

    def mousePressEvent(self, event):
        # ドラッグオブジェクトに色データ(テキスト)を埋め込んで実行
        drag = QtGui.QDrag(self)
        mime = QtCore.QMimeData()
        mime.setText(self._color)
        drag.setMimeData(mime)
        drag.exec_()

    def dragEnterEvent(self, event):
        event.accept()

    def dragMoveEvent(self, event):
        event.accept()

    def dropEvent(self, event):
        if event.mimeData().hasText():
            self._color = event.mimeData().text()
            self.changeColor()


app = QtGui.QApplication(sys.argv)

widget = QtGui.QWidget()
widget.setFixedSize(640, 240)
widget.setLayout(QtGui.QHBoxLayout())
layout = widget.layout()
layout.addWidget(WidgetItem('red'))
layout.addWidget(WidgetItem('blue'))
layout.addWidget(WidgetItem('green'))
layout.addWidget(WidgetItem('white'))
widget.show()
sys.exit(app.exec_())

PySide ドラッグでWidgetを移動させる

f:id:dungeonneko:20170525134629g:plain

import sys
from PySide import QtCore, QtGui

# ドラッグで動くWidget
class WidgetItem(QtGui.QLabel):
    def __init__(self):
        super().__init__('')
        self.setStyleSheet('border: 1px solid black; background-color: red;')
        self.setFixedSize(32, 32)
        self._drag = False
        self._offset = QtCore.QPoint(0, 0)

    def mousePressEvent(self, event):
        self._drag = True
        self._offset = event.pos()

    def mouseReleaseEvent(self, event):
        self._drag = False

    def mouseMoveEvent(self, event):
        if self._drag:
            self.move(self.mapToParent(event.pos() - self._offset))

app = QtGui.QApplication(sys.argv)

widget = QtGui.QWidget()
widget.setFixedSize(640, 480)
widget.setLayout(QtGui.QVBoxLayout())
layout = widget.layout()
item = WidgetItem()
layout.addWidget(item)
widget.show()
sys.exit(app.exec_())