Python PyQt5 でGuiアプリを作る

Python PyQt5 でGuiアプリを作る

PyQt5のインストール

*Mac
$brew install pyqt5

*windows
リンク先参照。

とりあえずPyQt5でwindowを作る


#!/usr/bin/env python
from PyQt5.QtWidgets import (QApplication, QWidget, QComboBox, QDialog,
        QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
        QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
        QVBoxLayout)

import sys

class MainWindow(QWidget):

    def __init__(self,parent=None):
        #super() でスーパークラスのインスタンスメソッドを呼び出す
        super(MainWindow, self).__init__(parent)
        #ボタンの作成
        button=QPushButton("Print")
        #ボタンをクリックした場合、Print_text()を実行する
        button.clicked.connect(self.Print_text)
        #レイアウト、QVBoxLayoutのインスタンス
        mainLayout = QVBoxLayout()
        #Widget追加
        mainLayout.addWidget(button)
        #QVBoxLayoutをaddWidgetを追加したものに更新
        self.setLayout(mainLayout)
        #windowのタイトル変更
        self.setWindowTitle("Test App")

    def Print_text(self):
        print('You have pushed the button')

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

メモ

super() でスーパークラスを取得します。
button.clicked.connect(self.Print_text)を使うことでクリックした際に他の関数を呼ぶことができます。
レイアウトはQVBoxLayout()を使うことで自動で配置されるようにしています。
self.setLayout(mainLayout)について理解をしきれていないのでリンク先を参照ください。

QGraphicsViewを使ってみる

PyQt5で画像を取り扱う方法はいくつかあるようですが、QGraphicsViewを使ってみます。
QPenとQBrushの使いかたが情報がすくなく大変でした。PySideのほうが情報が多いかもしれません。共にPythonバインディングなので非常に参考になります。


#!/usr/bin/env python
from PyQt5.QtWidgets import (QApplication, QWidget, QComboBox, QDialog,
        QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
        QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
        QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsPixmapItem)
from PyQt5.QtGui import (QIcon, QPixmap, QBrush, QPen, QColor)
from PyQt5 import QtCore

import sys
import os
import re


class MainWindow(QWidget):

    def __init__(self,parent=None):
        #super() でスーパークラスのインスタンスメソッドを呼び出す
        super(MainWindow, self).__init__(parent)

        path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')

        view = QGraphicsView()
        scene = QGraphicsScene()

        item = QGraphicsPixmapItem(QPixmap(path))
     #画像の位置調整
        item.setOffset (10, 10)
        scene.addItem(item)

     #円をいっぱい描く。20×20
        for i in range(0,200,10):
            for j in range(0,200,10):
                #QPenの設定
                pen = QPen(QtCore.Qt.green, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
                #QBrushの設定
                brush = QBrush(QColor(255, 0, 0, 127),QtCore.Qt.Dense1Pattern)
                scene.addEllipse(i,j,10,10,pen,brush)

        view.setScene(scene)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(view)

        self.setLayout(mainLayout)
        #windowのタイトル変更
        self.setWindowTitle("Test App5")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
    app.setWindowIcon(QIcon(path))
    P = MainWindow()
    P.show()
    sys.exit(app.exec_())

QGraphicsViewとPillowでgifアニメーションをつくる

PyQt5でGUIをつくります。画像をタイマー動かしgifアニメーションにするプログラムです。 QGraphicsViewとPillow (PIL) 使います。
Pillow (PIL)はanacondaならインストールされていると思います。
インストールしていない人pipからできるようですが、簡単にインストールできない場合もあるようなので事前にネットで情報を確認したほうがいいかもしれません。

プログラムのポイントとしてはQGraphicsViewをタイマーによって動かしてアニメーションさせます。
その際に画像をpngで保存をして、movieボタンを押した際にアニメーションをストップさせます。
PILでgifを作成して、不要のファイルを削除しています。

#!/usr/bin/env python
from PyQt5.QtWidgets import (QApplication, QWidget, QComboBox, QDialog,
        QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
        QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
        QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsPixmapItem)
from PyQt5.QtGui import (QIcon, QPixmap, QBrush, QPen, QColor)
from PyQt5 import QtCore
from PyQt5.QtCore import (QLineF, QPointF, QRectF, Qt, QTimer)

from PIL import Image, ImageDraw

from glob import glob
import sys
import os
import re


class Test_graphics(QGraphicsItem):
    def __init__(self):
        super(Test_graphics, self).__init__()
        self.time = 0
        self.a = 1

    def paint(self, painter, option, widget):
        painter.setPen(Qt.black)
        i = self.time
        painter.drawEllipse(i, i, 10, 10)

    def boundingRect(self):
        return QRectF(0,0,400,400)

    def redraw(self):
        if self.time == 0:
            self.a = 1
        elif self.time >= 390:
            self.a = -1
        else:
            pass
        x = self.time + 10*self.a
        self.time = x
        self.update()

class MainWindow(QWidget):

    def __init__(self,parent=None):
        super(MainWindow, self).__init__(parent)

        self.movieButton = QPushButton("&movie")
        self.movieButton.clicked.connect(self.make_movie)
        buttonLayout = QVBoxLayout()
        buttonLayout.addWidget(self.movieButton)

        path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
        self.view = QGraphicsView()
        scene = QGraphicsScene()
        self.item = Test_graphics()
        self.view.setSceneRect(0, 0, 400, 400);
        item = QGraphicsPixmapItem(QPixmap(path))
        item.setOffset (110, 110)
        scene.addItem(item)

        scene.addItem(self.item)
        self.view.setScene(scene)
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.view)
        mainLayout.addLayout(buttonLayout)
        self.setLayout(mainLayout)
        #windowのタイトル変更
        self.setWindowTitle("Test App7")
        self.plot_times = 0
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.time_Event)
        self.timer.start(100)

        if os.path.isdir("./png") == False :
            os.mkdir("./png")
        else:
            pass

    def time_Event(self):
        self.item.redraw()
        self.plot_times = self.plot_times + 1
        if self.plot_times >= 10000 :
            plot_times_str = str(self.plot_times)
        elif self.plot_times >= 1000 :
            plot_times_str = "0" + str(self.plot_times)
        elif self.plot_times >= 100 :
            plot_times_str = "00" + str(self.plot_times)
        elif self.plot_times >= 10 :
            plot_times_str = "000" + str(self.plot_times)
        else :
            plot_times_str = "0000" + str(self.plot_times)

        self.view.grab().save("png/test_" + plot_times_str +".png")
        
    def make_movie(self):
        self.timer.stop()
        images = []
        file_num= glob("./png/**.png")

        file_num.sort()

        for i in range(0, len(file_num), 1):
            im =Image.open(file_num[i], 'r')
            fp = im.copy()
            im.close()
            images.append(fp)

        #duraton uints is micro seconds
        images[0].save("image.gif",
               save_all=True, append_images=images[1:], optimize=False, duration=100, loop=0)

        for i in range(0, len(file_num), 1):
            os.remove(file_num[i])
        self.plot_times = 0

if __name__ == '__main__':
    app = QApplication(sys.argv)
    path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
    app.setWindowIcon(QIcon(path))
    P = MainWindow()
    P.show()
    sys.exit(app.exec_())


QGraphicsViewとOpenCVで動画作成

*OpenCV をインストールする。

環境は以下です。

MacBook Air MAC OSX Sierra 10.12.6
Python 3.6.1 :: Anaconda 4.4.0 (x86_64)
OpenCV3.3
Anacondaでpythonはインストール。homebrewもインストールしてある条件です。

インストールの参考にしたサイト

$brew tap homebrew/science
$brew install opencv3 –with-contrib –with-python3 –without-python

cv2.soファイルをインストールしたら
/usr/local/Cellar/opencv/3.3.0_3/lib/python3.6/site-packages/cv2.cpython-36m-darwin.so
にあったのanacondaのsite-packagesにシンボリックリンクの作成を作成する。
バージョンなどが違う可能性がありますが、$open /usr/local/Cellar/opencv でfinderを開き、次々フォルダーを開いていくと見つかると思います。homebrewでインストールしたものは/usr/local/Cellar/配下に入る。(リンク先参照)
シンボリックリンクじゃなくて、PYTHONPATHに追加してもたぶん大丈夫だと思う。(未実行未確認)

  シンボリックリンクの作成

(hogeはユーザー名)
$ln -s /usr/local/Cellar/opencv/3.3.0_3/lib/python3.6/site-packages/cv2.cpython-36m-darwin.so /Users/hoge/anaconda3/lib/python3.6/site-packages

実行してみる。

$python

>>import cv2
RuntimeError: module compiled against API version 0xb but this version of numpy is 0xa
Traceback (most recent call last):
  File "", line 1, in 
ImportError: numpy.core.multiarray failed to import

私はnumpyのverが古いとのエラーがでたので アップデートした。

$pip install numpy -U
$python

ここで問題なければ、インストールはできたことと思う。

上のGIFアニメーションの作成プログラムから def make_movie()を変更します。
変更は以下です。


#OpenCVを呼び出す。
import cv2
#~省略~

    def make_movie(self):
        self.timer.stop()
        images = []
        file_num= glob("./png/**.png")
        file_num.sort()
        #fourcc = cv2.VideoWriter_fourcc('m', 'p', 'g', '4’)
        #上記のようにfourccで指定するが、エラーがでたため、直接タグ0x00000020指定
        video = cv2.VideoWriter('video.mp4', 0x00000020, 10.0, (400, 400))

        for i in range(0, len(file_num), 1):
            img = cv2.imread(file_num[i].format(i))
            img = cv2.resize(img, (400,400))
            video.write(img)
        video.release()

        for i in range(0, len(file_num), 1):
            os.remove(file_num[i])
        self.plot_times = 0

#~省略~

  作成動画

以下参考にしたサイト。

 Qiita 
Pythonで連番画像から動画を作成する - Qiita
https://qiita.com/itoru257/items/228a91404fa77c780fd4
PythonでOpenCVを利用して、連番の画像ファイルから動画ファイルの作成を行った。#環境macOS Sierra (10.12.4)Python 3.5.3OpenCV 3.2.0#連番画像ファイル画像ファイルは...

Pythonカテゴリの最新記事