Python : PyQt5を使えばテトリスが作れるらしい
環境
・Windows 10
PyQt5とは
PyQt5 is a module that can be used to create graphical user interfaces (GUI). PyQt5 is not backwards compatible with PyQt4.
You will need Python 2.6+ or newer. To test your Python version try one of these commands:
要するに、Pythonでいい感じのGUIをつくれるモジュールってことですね
チュートリアル
かなり整理されているチュートリアルがあります PyQt5 tutorial http://zetcode.com/gui/pyqt5/
全部やりましたが、
「あ、exeでインストールした時のあれってこうやって作るのね!」
と感動することが多かったです。
Tetris in PyQt5
テトリスまで作っていました。
ソースコードはこちら
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ ZetCode PyQt5 tutorial This is a Tetris game clone. Author: Jan Bodnar Website: zetcode.com Last edited: August 2017 """ from PyQt5.QtWidgets import QMainWindow, QFrame, QDesktopWidget, QApplication from PyQt5.QtCore import Qt, QBasicTimer, pyqtSignal from PyQt5.QtGui import QPainter, QColor import sys, random class Tetris(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): '''initiates application UI''' self.tboard = Board(self) self.setCentralWidget(self.tboard) self.statusbar = self.statusBar() self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage) self.tboard.start() self.resize(180, 380) self.center() self.setWindowTitle('Tetris') self.show() def center(self): '''centers the window on the screen''' screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) class Board(QFrame): msg2Statusbar = pyqtSignal(str) BoardWidth = 10 BoardHeight = 22 Speed = 300 def __init__(self, parent): super().__init__(parent) self.initBoard() def initBoard(self): '''initiates board''' self.timer = QBasicTimer() self.isWaitingAfterLine = False self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.board = [] self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clearBoard() def shapeAt(self, x, y): '''determines shape at the board position''' return self.board[(y * Board.BoardWidth) + x] def setShapeAt(self, x, y, shape): '''sets a shape at the board''' self.board[(y * Board.BoardWidth) + x] = shape def squareWidth(self): '''returns the width of one square''' return self.contentsRect().width() // Board.BoardWidth def squareHeight(self): '''returns the height of one square''' return self.contentsRect().height() // Board.BoardHeight def start(self): '''starts game''' if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.clearBoard() self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.newPiece() self.timer.start(Board.Speed, self) def pause(self): '''pauses game''' if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit("paused") else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.update() def paintEvent(self, event): '''paints all shapes of the game''' painter = QPainter(self) rect = self.contentsRect() boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight() for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shapeAt(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.drawSquare(painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape) if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare(painter, rect.left() + x * self.squareWidth(), boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape()) def keyPressEvent(self, event): '''processes key press events''' if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape: super(Board, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: self.tryMove(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY) elif key == Qt.Key_Down: self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY) elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY) elif key == Qt.Key_Space: self.dropDown() elif key == Qt.Key_D: self.oneLineDown() else: super(Board, self).keyPressEvent(event) def timerEvent(self, event): '''handles timer event''' if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() else: self.oneLineDown() else: super(Board, self).timerEvent(event) def clearBoard(self): '''clears shapes from the board''' for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape) def dropDown(self): '''drops down a shape''' newY = self.curY while newY > 0: if not self.tryMove(self.curPiece, self.curX, newY - 1): break newY -= 1 self.pieceDropped() def oneLineDown(self): '''goes one line down with a shape''' if not self.tryMove(self.curPiece, self.curX, self.curY - 1): self.pieceDropped() def pieceDropped(self): '''after dropping shape, remove full lines and create new shape''' for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.setShapeAt(x, y, self.curPiece.shape()) self.removeFullLines() if not self.isWaitingAfterLine: self.newPiece() def removeFullLines(self): '''removes all full lines from the board''' numFullLines = 0 rowsToRemove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shapeAt(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rowsToRemove.append(i) rowsToRemove.reverse() for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1)) numFullLines = numFullLines + len(rowsToRemove) if numFullLines > 0: self.numLinesRemoved = self.numLinesRemoved + numFullLines self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.isWaitingAfterLine = True self.curPiece.setShape(Tetrominoe.NoShape) self.update() def newPiece(self): '''creates a new shape''' self.curPiece = Shape() self.curPiece.setRandomShape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit("Game over") def tryMove(self, newPiece, newX, newY): '''tries to move a shape''' for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shapeAt(x, y) != Tetrominoe.NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return True def drawSquare(self, painter, x, y, shape): '''draws a square of a shape''' colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] color = QColor(colorTable[shape]) painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.squareHeight() - 1, x, y) painter.drawLine(x, y, x + self.squareWidth() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + self.squareHeight() - 1) painter.drawLine(x + self.squareWidth() - 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1) class Tetrominoe(object): NoShape = 0 ZShape = 1 SShape = 2 LineShape = 3 TShape = 4 SquareShape = 5 LShape = 6 MirroredLShape = 7 class Shape(object): coordsTable = ( ((0, 0), (0, 0), (0, 0), (0, 0)), ((0, -1), (0, 0), (-1, 0), (-1, 1)), ((0, -1), (0, 0), (1, 0), (1, 1)), ((0, -1), (0, 0), (0, 1), (0, 2)), ((-1, 0), (0, 0), (1, 0), (0, 1)), ((0, 0), (1, 0), (0, 1), (1, 1)), ((-1, -1), (0, -1), (0, 0), (0, 1)), ((1, -1), (0, -1), (0, 0), (0, 1)) ) def __init__(self): self.coords = [[0,0] for i in range(4)] self.pieceShape = Tetrominoe.NoShape self.setShape(Tetrominoe.NoShape) def shape(self): '''returns shape''' return self.pieceShape def setShape(self, shape): '''sets a shape''' table = Shape.coordsTable[shape] for i in range(4): for j in range(2): self.coords[i][j] = table[i][j] self.pieceShape = shape def setRandomShape(self): '''chooses a random shape''' self.setShape(random.randint(1, 7)) def x(self, index): '''returns x coordinate''' return self.coords[index][0] def y(self, index): '''returns y coordinate''' return self.coords[index][1] def setX(self, index, x): '''sets x coordinate''' self.coords[index][0] = x def setY(self, index, y): '''sets y coordinate''' self.coords[index][1] = y def minX(self): '''returns min x value''' m = self.coords[0][0] for i in range(4): m = min(m, self.coords[i][0]) return m def maxX(self): '''returns max x value''' m = self.coords[0][0] for i in range(4): m = max(m, self.coords[i][0]) return m def minY(self): '''returns min y value''' m = self.coords[0][1] for i in range(4): m = min(m, self.coords[i][1]) return m def maxY(self): '''returns max y value''' m = self.coords[0][1] for i in range(4): m = max(m, self.coords[i][1]) return m def rotateLeft(self): '''rotates shape to the left''' if self.pieceShape == Tetrominoe.SquareShape: return self result = Shape() result.pieceShape = self.pieceShape for i in range(4): result.setX(i, self.y(i)) result.setY(i, -self.x(i)) return result def rotateRight(self): '''rotates shape to the right''' if self.pieceShape == Tetrominoe.SquareShape: return self result = Shape() result.pieceShape = self.pieceShape for i in range(4): result.setX(i, -self.y(i)) result.setY(i, self.x(i)) return result if __name__ == '__main__': app = QApplication([]) tetris = Tetris() sys.exit(app.exec_())
実行方法
python tetris.py
実行はとても簡単です。
おわりに
最近は小さなアプリケーションを作ることが増えたので特にオフラインのアプリを作る際に重宝しそうです。
pip install opencv-contrib-pythonでPermission denied発生したときの対処法
環境
wiindows 10
Python 3.7.2
pip install opencv-contrib-pythonを実行したところエラーが発生
Could not install packages due to an EnvironmentError: [WinError 5] アクセスが拒否されました。: 'c:\\users\\user\\appdata\\local\\programs\\python\\python37\\Lib\\site-packages\\cv2\\cv2.cp37-win_amd64.pyd'
Consider using the `--user` option or check the permissions.
--userをつけたらいいよと言ってるので
pip install opencv-contrib-python --user
を実行したところ成功
csvファイルのデータをフィルタリングして結合し、別のcsvファイルとして出力するexeアプリの製作 (Python 3.6) (venv) (pyinstaller)
csvファイルを操作する簡単なexeアプリ
1. 環境
2. venvの作成
まず初めにPythonの仮想環境を作成します。
のちのち完成したファイルをexe化するのですが、その際に必要最低限のモジュールのみを導入するためです。
今回使用するのは使用するのはvenvです。
python -m venv env
仮想環境の有効化は
env\Script\acrivate
とコマンドラインで打つだけです。
先頭に(env)が表示されれば成功です。
(env) C:\user\name\...
ここからはすべてこの仮想環境で作業をします。
3. 必要なモジュールのインストール
必要なpythonモジュールをインストールします。
#numpyとpandasの依存関係でエラーが出るため、-U をつけて一緒にインストール pip install -U numpy pandas #exe化に必要なモジュール pip install pyinstaller
それと、csvの入出力フォルダも作成しておきます
mkdir CSV mkdir CSV_MERGED
4. python スクリプト
今回は以下のスクリプトを使用します。 csvファイルから一定値以下をフィルタリングして、別のcsvファイルに書き出す形です。
#!/usr/bin/env python # -*- coding: utf-8 -*- # import modules import numpy.core._dtype_ctypes import pandas as pd import glob import os import warnings warnings.filterwarnings('ignore') # parameters #try: # input_ = input('閾値 = ')# # threshold = float(input_) #except: # print('入力が正しくありません') while True: try: input_ = input("閾値 = ") threshold = float(input_) #if type(threshold) == 'float' : # break #print(input_) break except: print('入力が正しくありません') # get names of directory path = 'CSV' dir_name_tmp = os.listdir(path) dir_name_tmp = [f for f in dir_name_tmp if os.path.isdir(os.path.join(path, f))] for dir_name in dir_name_tmp: print("\n") print("-----現在のフォルダ-----") print(dir_name) # get names of csv files path = 'CSV/' + dir_name files = os.listdir(path) files_file = [f for f in files if os.path.isfile(os.path.join(path, f))] csv_name_tmp = files_file print("-----csvのリスト-----") print(csv_name_tmp) print('-----csvファイルを結合します-----') for i in range(len(csv_name_tmp)): # load data target_file_name = path + '/' + csv_name_tmp[i] print(target_file_name) df = pd.read_csv(target_file_name,encoding='cp932',header = None) # split csv_data into head and data df_head = df[:14].rename(columns={0: 'data'}) df_data = df[14:].rename(columns={0: 'data'}) # extract data threshold or below tmp_data = df_data['data'].astype(float) tmp_data = [a for a in tmp_data if a>=threshold] df_data = pd.DataFrame({'data':tmp_data}) # merge data if i==0: # header df_head_all = df_head # create df_data_all df_data_all = df_data #print(len(df_data_all)) else: # concat data df_data_all = pd.concat([df_data_all,df_data]) #print(len(df_data_all)) # save merged data df_all = pd.concat([df_head_all,df_data_all]) path = 'CSV_MERGED/' + dir_name + '.csv' df_all.to_csv(path,header=False,index=False,encoding='cp932') print('-----CSVファイルが保存されました-----') print(path) print("\n")
実行は
>python main.py 閾値 =
のようになるので、好きな値を入力すればフィルタリングされます。
5. exe化
今回はpyinstallerを用いてmain.pyをexe化します。 これについてはたった一行
> pyinstaller main.py --onefile
とコマンドラインで入力すれば終わりです。
6. ご質問・ご相談
coconalaでご質問・ご相談を受け付けておりますので、こちらまでご連絡ください。
ModuleNotFoundError: No module named 'numpy.core._dtype_ctypes'
pyinstallerでpandasやnumpyをimportするさいに
ModuleNotFoundError: No module named 'numpy.core._dtype_ctypes'
というエラーに遭遇
ググったところ、ヒットしたのが以下の一件のみ
import numpy.core._dtype_ctypes
を追加したところ成功
ImportError: Missing required dependencies ['numpy']
pyinstallerでpandasを含むスクリプトを実行した際に
ImportError: Missing required dependencies ['numpy']
pandasがnumpyを参照できないと怒られた。
【解決策】
一応これで解決
pip install -U numpy pandas