From 1a4b7a730a3254c763fa2a5ecb7b81ecb10b3bce Mon Sep 17 00:00:00 2001 From: En Yi Date: Fri, 6 Jul 2018 18:25:55 +0800 Subject: [PATCH] Refactor sudoku graphic components --- graphic_components/board.py | 184 +------------------------- graphic_components/sudoku_graphics.py | 178 ++++++++++++++++++++++++- main.py | 30 +---- 3 files changed, 185 insertions(+), 207 deletions(-) diff --git a/graphic_components/board.py b/graphic_components/board.py index 50ca655..f9a7ac5 100644 --- a/graphic_components/board.py +++ b/graphic_components/board.py @@ -1,15 +1,11 @@ from PyQt5.QtGui import QPainter, QBrush, QPen, QColor, QFont -from PyQt5.Qt import QApplication, QTimer from PyQt5.QtWidgets import (QGraphicsScene, QGraphicsWidget, QGraphicsItem, QGraphicsLineItem, QGraphicsRectItem, QGraphicsObject, QGraphicsItemGroup, QGraphicsPathItem) from PyQt5.QtCore import (QAbstractAnimation, QObject, QPointF, Qt, QRectF, QLineF, QPropertyAnimation, pyqtProperty, pyqtSignal, QSizeF) -from graphic_components import buttons -from general.extras import bound_value -from gameplay import sudoku_gameplay as sdk -import numpy as np -import sys, math + +from graphic_components import sudoku_graphics as sdk_grap class BoxBoard(QGraphicsWidget): @@ -46,7 +42,7 @@ class BoxBoard(QGraphicsWidget): painter.drawLine(line) def sizeHint(self, which, constraint=None): - return(QSizeF(self.width+10, self.height+10)) + return QSizeF(self.width+10, self.height+10) class GameBoard(BoxBoard): @@ -54,11 +50,11 @@ class GameBoard(BoxBoard): def __init__(self, width, height, parent=None): super().__init__(width, height, parent) - self.gamegrid = SudokuGrid(self.width, self.height, parent=self) - self.numring = NumberRing(parent=self) + self.gamegrid = sdk_grap.SudokuGrid(self.width, self.height, parent=self) + self.numring = sdk_grap.NumberRing(parent=self) - self.gamegrid.update() - self.numring.update() + self.gamegrid.buttonClicked.connect(self.show_number_ring) + self.numring.connect_button_signals(self.select_ring_number) def show_number_ring(self, x=0, y=0): if not self.gamegrid.selected: @@ -74,169 +70,3 @@ class GameBoard(BoxBoard): val = 0 self.gamegrid.replace_cell_number(int(val)) self.show_number_ring() - -class SudokuGrid(QGraphicsObject): - # Prepare the signal - buttonClicked = pyqtSignal(float, float) - - def __init__(self, width, height, parent=None): - super().__init__(parent) - self.width = width - self.height = height - self.default_pen = QPen() - self.default_pen.setColor(Qt.white) - self.default_pen.setWidth(1) - - self.thick_pen = QPen() - self.thick_pen.setColor(Qt.white) - self.thick_unit = 5 - self.thick_pen.setWidth(self.thick_unit) - - self.horiz_gridlines = [] - self.vert_gridlines = [] - - self.thinlines = [] - self.thicklines = [] - - self.cell_width = self.width / 9 - self.cell_height = self.height /9 - - for i in range(1, 9): - delta_h = self.cell_height * i - delta_w = self.cell_width * i - if i%3 == 0: - self.thicklines.append(QLineF(0, delta_h, self.width, delta_h)) - self.thicklines.append(QLineF(delta_w, 0, delta_w, self.height)) - else: - self.thinlines.append(QLineF(0, delta_h, self.width, delta_h)) - - self.thinlines.append(QLineF(delta_w, 0, delta_w, self.height)) - - self.sudoku_grid = sdk.SudokuSystem() - self.grid_painter = NumberPainter(self, self.sudoku_grid) - - self.mouse_w = 0 - self.mouse_h = 0 - self.selection_unit = 8 - self.selection_pen = QPen() - self.selection_pen.setColor(Qt.white) - self.selection_pen.setWidth(self.selection_unit) - self.selection_box = QRectF(0, 0, self.cell_width, self.cell_height) - - self.setAcceptHoverEvents(True) - self.setAcceptedMouseButtons(Qt.LeftButton) - - self.selected = False - - def replace_cell_number(self, val): - self.sudoku_grid.replace_cell_number(self.mouse_h, self.mouse_w, val) - self.grid_painter.update() - - def boundingRect(self): - return QRectF(-5, -5, self.width+10, self.height+10) - - # Reimplemented paint - def paint(self, painter, style, widget=None): - painter.setPen(self.default_pen) - for line in self.thinlines: - painter.drawLine(line) - - painter.setPen(self.thick_pen) - for line in self.thicklines: - painter.drawLine(line) - - painter.setPen(self.selection_pen) - painter.drawRect(self.selection_box) - - def hoverMoveEvent(self, event): - box_w = bound_value(0, int(event.pos().x()/self.cell_width), 8) - box_h = bound_value(0, int(event.pos().y() / self.cell_height), 8) - if not self.selected: - if box_w != self.mouse_w or box_h != self.mouse_h: - self.mouse_w = box_w - self.mouse_h = box_h - self.selection_box.moveTopLeft(QPointF(box_w*self.cell_width, box_h*self.cell_height)) - self.update() - - def mousePressEvent(self, event): - w = (self.mouse_w + 0.5) * self.cell_width - 5 - h = (self.mouse_h + 0.5) * self.cell_height + 5 - - if not self.sudoku_grid.get_cell_status(self.mouse_h, self.mouse_w) == sdk.FIXED: - self.buttonClicked.emit(w, h) - - -class NumberPainter(QGraphicsItem): - def __init__(self, parent, grid): - super().__init__(parent=parent) - self.parent = parent - self.sudoku_grid = grid - self.default_pen = QPen() - self.default_pen.setColor(Qt.white) - self.default_pen.setWidth(1) - - self.invalid_pen = QPen() - self.invalid_pen.setColor(Qt.lightGray) - self.invalid_unit = 8 - self.invalid_pen.setWidth(self.invalid_unit) - - def paint(self, painter, style, widget=None): - for i in range(9): - for j in range(9): - self._draw_number_cell(i, j, painter) - - def boundingRect(self): - return QRectF(-5, -5, self.parent.width+10, self.parent.height+10) - - def _draw_number_cell(self, w, h, painter): - val = self.sudoku_grid.get_cell_number(h, w) - if val == 0: - val = '' - else: - if self.sudoku_grid.get_cell_status(h, w) == sdk.VALID: - painter.setPen(self.default_pen) - else: - painter.setPen(self.invalid_pen) - - painter.drawText((w+0.5)*self.parent.cell_width-5, - (h+0.5)*self.parent.cell_height+5, - str(val)) - - -class NumberRing(QGraphicsItem): - - def __init__(self, parent= None): - super().__init__(parent = parent) - - self.setVisible(False) - self.radius = 48 - self.cell_width = 24 - self.cell_height = 24 - - self.cell_buttons = [] - for i in range(10): - cell_x = self.radius * np.sin(np.deg2rad(360/10*i)) - self.cell_width/2 - cell_y = - self.radius * np.cos(np.deg2rad(360 / 10 * i)) - self.cell_height/2 - if i == 0: - cell_string = 'X' - else: - cell_string = str(i) - btn = buttons.animBox(cell_x, cell_y, self.cell_width, - self.cell_height, cell_string, self) - - self.cell_buttons.append(btn) - - def boundingRect(self): - return QRectF(-5, -5, self.cell_width+self.radius*2+10, - self.cell_height + self.radius * 2 + 10) - - # Reimplemented paint - def paint(self, painter, style, widget=None): - pass - - def connect_button_signals(self, func): - for btn in self.cell_buttons: - btn.buttonClicked.connect(func) - - #def mousePressEvent(self, event): - # print('Yes') diff --git a/graphic_components/sudoku_graphics.py b/graphic_components/sudoku_graphics.py index d30bd08..5526c72 100644 --- a/graphic_components/sudoku_graphics.py +++ b/graphic_components/sudoku_graphics.py @@ -1 +1,177 @@ -# Put all Sudoku related graphics here \ No newline at end of file +# Put all Sudoku related graphics here +from PyQt5.QtGui import QPainter, QBrush, QPen, QColor, QFont +from PyQt5.QtWidgets import QGraphicsItem, QGraphicsObject +from PyQt5.QtCore import (QAbstractAnimation, QPointF, Qt, QRectF, QLineF, + QPropertyAnimation, pyqtProperty, pyqtSignal) + +from gameplay import sudoku_gameplay as sdk +from general.extras import bound_value +from graphic_components import buttons +import numpy as np + + +class NumberPainter(QGraphicsItem): + def __init__(self, parent, grid): + super().__init__(parent=parent) + self.parent = parent + self.sudoku_grid = grid + self.default_pen = QPen() + self.default_pen.setColor(Qt.white) + self.default_pen.setWidth(1) + + self.invalid_pen = QPen() + self.invalid_pen.setColor(Qt.lightGray) + self.invalid_unit = 8 + self.invalid_pen.setWidth(self.invalid_unit) + + def paint(self, painter, style, widget=None): + for i in range(9): + for j in range(9): + self._draw_number_cell(i, j, painter) + + def boundingRect(self): + return QRectF(-5, -5, self.parent.width+10, self.parent.height+10) + + def _draw_number_cell(self, w, h, painter): + val = self.sudoku_grid.get_cell_number(h, w) + if val == 0: + val = '' + else: + if self.sudoku_grid.get_cell_status(h, w) == sdk.VALID: + painter.setPen(self.default_pen) + else: + painter.setPen(self.invalid_pen) + + painter.drawText((w+0.5)*self.parent.cell_width-5, + (h+0.5)*self.parent.cell_height+5, + str(val)) + + +class SudokuGrid(QGraphicsObject): + # Prepare the signal + buttonClicked = pyqtSignal(float, float) + + def __init__(self, width, height, parent=None): + super().__init__(parent) + self.width = width + self.height = height + self.default_pen = QPen() + self.default_pen.setColor(Qt.white) + self.default_pen.setWidth(1) + + self.thick_pen = QPen() + self.thick_pen.setColor(Qt.white) + self.thick_unit = 5 + self.thick_pen.setWidth(self.thick_unit) + + self.horiz_gridlines = [] + self.vert_gridlines = [] + + self.thinlines = [] + self.thicklines = [] + + self.cell_width = self.width / 9 + self.cell_height = self.height / 9 + + for i in range(1, 9): + delta_h = self.cell_height * i + delta_w = self.cell_width * i + if i%3 == 0: + self.thicklines.append(QLineF(0, delta_h, self.width, delta_h)) + self.thicklines.append(QLineF(delta_w, 0, delta_w, self.height)) + else: + self.thinlines.append(QLineF(0, delta_h, self.width, delta_h)) + + self.thinlines.append(QLineF(delta_w, 0, delta_w, self.height)) + + self.sudoku_grid = sdk.SudokuSystem() + self.grid_painter = NumberPainter(self, self.sudoku_grid) + + self.mouse_w = 0 + self.mouse_h = 0 + self.selection_unit = 8 + self.selection_pen = QPen() + self.selection_pen.setColor(Qt.white) + self.selection_pen.setWidth(self.selection_unit) + self.selection_box = QRectF(0, 0, self.cell_width, self.cell_height) + + self.setAcceptHoverEvents(True) + self.setAcceptedMouseButtons(Qt.LeftButton) + + self.selected = False + + def replace_cell_number(self, val): + self.sudoku_grid.replace_cell_number(self.mouse_h, self.mouse_w, val) + self.grid_painter.update() + + def boundingRect(self): + return QRectF(-5, -5, self.width+10, self.height+10) + + # Reimplemented paint + def paint(self, painter, style, widget=None): + painter.setPen(self.default_pen) + for line in self.thinlines: + painter.drawLine(line) + + painter.setPen(self.thick_pen) + for line in self.thicklines: + painter.drawLine(line) + + painter.setPen(self.selection_pen) + painter.drawRect(self.selection_box) + + def hoverMoveEvent(self, event): + box_w = bound_value(0, int(event.pos().x()/self.cell_width), 8) + box_h = bound_value(0, int(event.pos().y() / self.cell_height), 8) + if not self.selected: + if box_w != self.mouse_w or box_h != self.mouse_h: + self.mouse_w = box_w + self.mouse_h = box_h + self.selection_box.moveTopLeft(QPointF(box_w*self.cell_width, box_h*self.cell_height)) + self.update() + + def mousePressEvent(self, event): + w = (self.mouse_w + 0.5) * self.cell_width - 5 + h = (self.mouse_h + 0.5) * self.cell_height + 5 + + if not self.sudoku_grid.get_cell_status(self.mouse_h, self.mouse_w) == sdk.FIXED: + self.buttonClicked.emit(w, h) + + +class NumberRing(QGraphicsItem): + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setVisible(False) + self.radius = 48 + self.cell_width = 24 + self.cell_height = 24 + + self.cell_buttons = [] + for i in range(10): + cell_x = self.radius * np.sin(np.deg2rad(360/10*i)) - self.cell_width/2 + cell_y = - self.radius * np.cos(np.deg2rad(360 / 10 * i)) - self.cell_height/2 + if i == 0: + cell_string = 'X' + else: + cell_string = str(i) + btn = buttons.animBox(cell_x, cell_y, self.cell_width, + self.cell_height, cell_string, self) + + self.cell_buttons.append(btn) + + def boundingRect(self): + return QRectF(-5, -5, self.cell_width+self.radius*2+10, + self.cell_height + self.radius * 2 + 10) + + # Reimplemented paint + def paint(self, painter, style, widget=None): + pass + + def connect_button_signals(self, func): + for btn in self.cell_buttons: + btn.buttonClicked.connect(func) + + #def mousePressEvent(self, event): + # print('Yes') \ No newline at end of file diff --git a/main.py b/main.py index 584b59d..7b7547f 100644 --- a/main.py +++ b/main.py @@ -18,54 +18,26 @@ class SudokuWindow(QGraphicsView): # Set up the Scene to manage the GraphicItems self.scene = QGraphicsScene(0, 0, 400, 500, self) - self.setScene(self.scene) self.setSceneRect(self.scene.sceneRect()) self.gameboard = board.GameBoard(400, 400) self.menuboard = board.BoxBoard(400, 50) - self.gamegrid = board.SudokuGrid(450, 450) - self.numring = board.NumberRing() self.layout = QGraphicsLinearLayout(Qt.Vertical) self.layout.addItem(self.gameboard) self.layout.addItem(self.menuboard) self.form = QGraphicsWidget() self.form.setLayout(self.layout) - #self.layout.addItem(self.gamegrid) - #self.button1 = buttons.animBox(0, 0, 20, 20, 'a') - #self.scene.addItem(self.button1) - - #self.scene.addItem(self.gameboard) self.scene.addItem(self.form) - #self.scene.addItem(self.gamegrid) - #self.scene.addItem(self.numring) self.setBackgroundBrush(QBrush(Qt.black)) self.setRenderHint(QPainter.Antialiasing) self.setGeometry(0, 0, 600, 600) - self.gamegrid.buttonClicked.connect(self.show_number_ring) - self.numring.connect_button_signals(self.select_ring_number) - - self.ensureVisible(self.scene.sceneRect(), 50, 50) + self.ensureVisible(self.scene.sceneRect(), 10, 10) self.fitInView(self.gameboard.boundingRect(), Qt.KeepAspectRatio) self.show() - def show_number_ring(self, x=0, y=0): - if not self.gamegrid.selected: - self.numring.setPos(x, y) - self.numring.setVisible(True) - self.gamegrid.selected = True - else: - self.numring.setVisible(False) - self.gamegrid.selected = False - - def select_ring_number(self, val): - if val == 'X': - val = 0 - self.gamegrid.replace_cell_number(int(val)) - self.show_number_ring() - if __name__ == "__main__": app = 0