ちろる

理系大学生が自由気ままに

PyQt お絵かきツール その1

PyQtとは?

PyQtは、クロスプラットフォームGUIツールキットであるQtのPythonバインディングにして、PythonGUIプログラミングをするときの選択肢の一つである。PyQtの他には、PySide・PyGTK・wxPythonTkinterなどのGUIツールキットが存在する。Qtと同様にPyQtフリーソフトウェアである。PyQtPythonプラグインとして実装されている。

PyQt|Wikipedia

PyQtとはPythonGUIのソフトを作るための一手段。GUIツールキットは他にも種類がありますので特徴を列挙しておきます。

Kivy

最近話題のやつでスマホアプリとかにも使われてるし、めちゃめちゃ見た目がかっちょいい。

wxPython

wxWidgetsというC++で書かれたやつのラッパー。wxPythonを覚えればC++でもすぐにGUIが書けるようになる。日本語情報はかなり多いしシェア率もトップレベル。

PyQt

wxPythonにとても似ているけど、PyQt自体の日本語情報は少ない。wxPython同様にC++書かれたQtのラッパーなので、それ向け記事を読んで自分でPythonで動くように読み換える能力があれば使える。(関数名と引数が把握できれば使える)

Tkinter

Pythonに標準で付属しているGUIライブラリなので環境構築は楽(というか何もしなくても使える)が、あまりデザインが綺麗ではない。
多くの参考書はGUIでこれを用いているので、入門にはとってもおすすめ。

PyGTK

GTK+のラッパー。GTK自体古い(?)らしくもうあまり使われてないみたい。(詳しくは知らない)


他にも色々あるが、メジャーなのはこんな感じ。難易度が高すぎずデザイン性も確保したいということでPyQtwxPythonの2択から選んだ。wxPythonの方が若干簡単そうだったのでそちらを使おうとしたら、インストールでなぜか上手くいかなかったので諦めてPyQtを使ってる。
f:id:tsupiano:20171125194935p:plain

PyQt入門

素晴らしき先人様の記事がたくさんあるのでそちらを読んでください。本記事ではPyQt5を使うけど、PyQt4のプログラムも多少変更すれば使えるので、読めるよ!C++のQtに関する記事は関数と引数が何かを知るのに役に立つ!
qiita.com
myenigma.hatenablog.com
d.hatena.ne.jp

いよいよ本題、お絵かきツールのベース作り

まずは完成したお絵かきツールのベース。ザーッと目を通す。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication,QWidget 

class Widget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.points = []
        self.psets = []
        self.setMinimumSize(500, 500)
        self.setMaximumSize(500, 500)

    def mousePressEvent(self, event):
        self.points.append(event.pos())
        self.update()

    def mouseMoveEvent(self, event):
        self.points.append(event.pos())
        self.update()

    def mouseReleaseEvent(self, event):
        self.psets.append(self.points)
        self.points = []
        self.update()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Space:
            self.points = []
            self.psets = []
            self.update()        

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(Qt.black)

        for points in self.psets:
            painter.drawPolyline(*points)

        if self.points:
            painter.drawPolyline(*self.points)

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

関数paintEvent、 keyPressEvent、mouseReleaseEvent、mousePressEvent、mouseMoveEventがそれぞれPyQtの中に最初からあり、各イベントごとにその名前の関数を呼び出してくれる。それぞれの役割は以下の通り。

・paintEvent / 画面を描画
・keyPressEvent / キーを押した時のイベント処理
・mousePressEvent / マウスを押した時のイベント処理
・mouseMoveEvent / マウスを動かした時のイベント処理
・mouseReleaseEvent / マウスを離した時のイベント処理

mouse*の関数でマウスの座標をリストに登録、paintEventで描画、というシンプルなプログラム。Spaceを押すことによってリストが空にされ、白紙に戻せる。

painter = QPainter(self)

でキャンバスを用意して、

painter.setPen(Qt.black)

でペンを用意。このときに線の太さとかも変えられるのでsetPenでググってみるといいかも。

painter.drawPolyline(*self.points)

QPointのリストに*をつけて渡してやると線が表示される。

※モジュールをインポートするときによく"from PyQt5.QtCore import *"みたいに"*"でインポートするプログラムを見るけど、あれは練習だからそうしてあるのであって、実際は名前空間を汚してしまう(関数名とかかごっちゃになる)ので実践で使うときは必ず特定のものだけインポートするようにする。