Не работает корректно код (pyqt5)
Не работает корректно кнопка загрузки если использовать ее из первого окна.
Первая кнопка в главном окне - сохранение, вторая -- загрузка, третья -- создать новое поле. Не работает функция загрузки только из первого окна(диалога), хотя сама функция вызывается в основном окне (gg) так же как и его рабочий брат из основного окна, но вот он работает как надо.
import random, sys, pymorphy2, webbrowser
from PyQt5 import QtGui
from PyQt5.QtGui import QPainter, QIcon
from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget, QInputDialog, QPushButton, QFileDialog, \
QHBoxLayout, QVBoxLayout, QDialog, QLabel, QFormLayout
from PyQt5.QtCore import QSize, Qt, QRect
class Start(QDialog):
def __init__(self, root):
super().__init__(root)
self.main = root
self.resize(200, 150)
self.setWindowTitle('Start menu')
self.size_widget = QWidget(self)
self.size_widget.setGeometry(QRect(30, 30, 351, 175))
self.layout = QFormLayout(self.size_widget)
self.layout.setContentsMargins(0, 0, 0, 0)
self.new_label = QLabel('Новая игра', self)
self.load_label = QLabel('Загрузить поле', self)
self.new_button = QPushButton(self)
self.new_button.setFixedSize(50, 50)
self.new_button.clicked.connect(self.new_clicked)
self.new_button.setIcon(QIcon('new_im.png'))
self.new_button.setIconSize(QSize(40, 40))
self.load_btn = QPushButton(self)
self.load_btn.setFixedSize(50, 50)
self.load_btn.clicked.connect(self.load_clicked)
self.load_btn.setIcon(QIcon('load_im.png'))
self.load_btn.setIconSize(QSize(40, 40))
self.layout.setWidget(0, QFormLayout.FieldRole, self.new_button)
self.layout.setWidget(0, QFormLayout.LabelRole, self.new_label)
self.layout.setWidget(1, QFormLayout.LabelRole, self.load_label)
self.layout.setWidget(1, QFormLayout.FieldRole, self.load_btn)
def new_clicked(self):
self.main.start_arg = 'new'
self.close()
def load_clicked(self):
self.main.start_arg = 'load'
#fname = QFileDialog.getOpenFileName(self, 'Open file')
#f = open(fname[0], 'r').read().split('], ')
#self.main.matrix = []
#for i in f:
# if i == f[-1]:
# i = i[1:-1].split(', ')
# else:
# i = i[1:].split(', ')
# lst = [int(j) for j in i]
# self.main.matrix.append(lst)
#self.main.size = len(self.main.matrix[0])
#self.main.load_fl = True
self.close()
class gg(QWidget):
def __init__(self):
super().__init__()
self.load_fl = False
self.have_size = False
self.field = False
self.start_arg = 'new'
Start(self).exec()
self.setupUI()
def setupUI(self):
self.setWindowTitle('Пятнашки')
self.cell_size = 100
if self.start_arg == 'load' and self.load_fl is False:
self.load()
elif self.have_size:
self.matrix = []
self.have_size = False
elif self.load_fl is False:
self.matrix = []
self.new_field_dialog()
self.empty = self.size * self.size
if len(self.matrix) == 0:
self.matrix_create()
self.setFixedSize(self.cell_size * self.size + 62, self.cell_size * self.size)
self.save_btn = QPushButton(self)
self.save_btn.setFixedSize(50, 50)
self.save_btn.setIcon(QIcon('save_im.png'))
self.save_btn.setIconSize(QSize(40, 40))
self.save_btn.clicked.connect(self.save)
self.load_btn = QPushButton(self)
self.load_btn.setFixedSize(50, 50)
self.load_btn.setIcon(QIcon('load_im.png'))
self.load_btn.setIconSize(QSize(40, 40))
self.load_btn.clicked.connect(self.load)
self.doc_btn = QPushButton(self)
self.doc_btn.setFixedSize(50, 50)
self.doc_btn.setIcon(QIcon('doc_im.png'))
self.doc_btn.setIconSize(QSize(40, 40))
self.doc_btn.clicked.connect(lambda: webbrowser.open('https://www.logozavr.ru/1640/'))
self.new_btn = QPushButton(self)
self.new_btn.setFixedSize(50, 50)
self.new_btn.setIcon(QIcon('new_im.png'))
self.new_btn.setIconSize(QSize(40, 40))
self.new_btn.clicked.connect(self.new_f)
vbox = QVBoxLayout()
vbox.addStretch(-1)
vbox.setSpacing(0)
vbox.addWidget(self.save_btn)
vbox.addWidget(self.load_btn)
vbox.addWidget(self.new_btn)
vbox.addWidget(self.doc_btn)
hbox = QHBoxLayout()
hbox.addStretch(0)
hbox.addLayout(vbox)
self.setLayout(hbox)
def new_f(self):
cancel = self.new_field_dialog()
if cancel:
self.have_size = True
self.setupUI()
def save(self):
try:
fileName = QFileDialog.getSaveFileName(self, 'Save file')
if fileName:
f = open(fileName[0], 'w')
f.write(str(self.matrix)[1:-1])
except Exception:
pass
def load(self):
try:
fname = QFileDialog.getOpenFileName(self, 'Open file')
f = open(fname[0], 'r').read().split('], ')
self.matrix = []
for i in f:
if i == f[-1]:
i = i[1:-1].split(', ')
else:
i = i[1:].split(', ')
lst = [int(j) for j in i]
self.matrix.append(lst)
self.size = len(self.matrix[0])
self.load_fl = True
self.setupUI()
except Exception:
pass
def matrix_create(self):
self.n = 0
cells_value = list(range(1, self.size * self.size))
random.shuffle(cells_value)
cells_value.append(self.empty)
self.matrix = []
for i in range(self.size):
lst = []
for j in range(self.size):
lst.append(cells_value.pop(0))
self.matrix.append(lst)
def mouseReleaseEvent(self, event):
pos = event.pos()
y = pos.x() // self.cell_size
x = pos.y() // self.cell_size
def cell_find(x, y):
try:
if x < 0 or y < 0:
raise IndexError
return self.matrix[x][y], x, y
except IndexError:
return None
try:
near_cells = [
cell_find(x - 1, y),
cell_find(x + 1, y),
cell_find(x, y - 1),
cell_find(x, y + 1)]
empty_cell = []
for i in near_cells:
if i is not None and i[0] == self.empty:
empty_cell.append(i)
if len(empty_cell) > 0:
value = cell_find(x, y)[0]
empty_value, x2, y2 = empty_cell[0]
self.matrix[x][y] = empty_value
self.matrix[x2][y2] = value
lst = []
for row in self.matrix:
for j in row:
lst.append(j)
lst.pop()
self.n += 1
word = pymorphy2.MorphAnalyzer().parse('ход')[0]
w = word.make_agree_with_number(self.n).word
if lst == list(range(1, self.size * self.size)):
vict_massage = QMessageBox(self)
vict_massage.information(self, 'Victory', 'Ура, вы сделали это,' + '\n'
'на это у вас ушло ' + str(
self.n) + ' ' + w + '!')
self.matrix_create()
self.update()
except IndexError:
pass
def new_field_dialog(self):
try:
in_d = QInputDialog.getText(self, 'Ввод размера', 'Введи число от 3 до 10 (размер поля)')
text, ok = in_d
if ok:
self.size = int(text)
if self.size < 3 or self.size > 10:
raise ValueError
elif self.field is False:
exit()
else:
return False
return True
except ValueError:
error_m = QMessageBox(self)
error_m.information(self, 'error', 'Неверный ввод, попробуйте снова.')
self.new_field_dialog()
def paintEvent(self, event):
self.field = True
qp = QPainter(self)
qp.setPen(QtGui.QColor('black'))
for i, row in enumerate(self.matrix):
y = i * self.cell_size
for j, value in enumerate(row):
x = j * self.cell_size
if value == self.empty:
qp.setBrush(QtGui.QColor('white'))
else:
qp.setBrush(QtGui.QColor('green'))
qp.drawRect(x, y, self.cell_size, self.cell_size)
if value != self.empty:
text = str(value)
else:
text = ''
qp.drawText(x, y, self.cell_size, self.cell_size, Qt.AlignCenter, text)
app = QApplication(sys.argv)
ex = gg()
ex.show()
exit(app.exec_())
Ответы (2 шт):
Автор решения: S. Nick
→ Ссылка
Мне тяжело понять логику вашей программы, но я вам покажу один из вариантов игры "Пятнашки"
import sys
from random import randint
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QLabel, QMessageBox
from PyQt5.QtCore import Qt, QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
class Game15(QWidget):
def __init__(self):
QWidget.__init__(self, None, Qt.MSWindowsFixedSizeDialogHint)
self.buttons = []
for i in range(15):
self.buttons.append(exec(f'self._{i+1} = ...'))
self.buttons[i] = QPushButton(self)
self.buttons[i].clicked.connect(self._clicked)
self.buttons[i].setText(str(i + 1))
self.poss, self.font = [], QFont()
self.steps, self.msg_win = QLabel('st. : 0', self), QMessageBox()
self.reload_btn = QPushButton('reload', self)
self.reload_btn.clicked.connect(self.reload)
self.MV = ...
self.mv(self, 0, 0, 'win')
self.set_ui()
self.reload()
def set_ui(self):
self.resize(280, 400)
self.steps.setGeometry(0, 370, 60, 30)
self.font.setBold(1)
self.font.setPointSize(12)
self.reload_btn.setGeometry(180, 370, 100, 30)
self.msg_win.setStandardButtons(QMessageBox.Ok)
self.msg_win.setFont(self.font)
self.msg_win.setText('win')
_x, _y = 0, 0
for i in self.buttons:
i.setFont(self.font)
i.setGeometry(_x, _y, 70, 70)
self.poss.append([_x, _y])
_x, _y = (lambda a, b: (a+70, b) if a <= 140 else (0, b+70))(_x, _y)
def _clicked(self):
for btn in self.buttons:
if btn.hasFocus():
k, l, c = self.ch_m(btn)
if k:
self.steps.setText('st. : {}'.format(
int(self.steps.text()[self.steps.text().find(':') + 1:]) + 1 )
)
self.mv(btn, l, c)
def ch_m(self, obj:QPushButton):
if len([x.x() for x in self.buttons if x.y() == obj.y()]) < 4:
for i in [0, 70, 140, 210]:
if i not in [x.x() for x in self.buttons if x.y() == obj.y()] and \
obj.x() in [i+70, i-70]:
return [True, i, obj.y()]
elif len([x.y() for x in self.buttons if x.x() == obj.x()]) < 4:
for i in [0, 70, 140, 210]:
if i not in [x.y() for x in self.buttons if x.x() == obj.x()] and \
obj.y() in [i+70, i-70]:
return [True, obj.x(), i]
return [False, 0, 0]
def mv(self, obj: QPushButton, a, b, ty='btn'):
if ty == 'btn':
self.MV_obj = QPropertyAnimation(obj, b'geometry')
self.MV_obj.setDuration(100)
self.MV_obj.setStartValue(QRect(obj.x(), obj.y(), obj.width(), obj.height()))
self.MV_obj.setEndValue(QRect(a, b, obj.width(), obj.height()))
self.MV_obj.finished.connect(self.check)
self.MV_obj.start()
elif ty == 'win':
self.MV_obj = QPropertyAnimation(obj, b'windowOpacity')
self.MV_obj.setDuration(2000)
self.MV_obj.setStartValue(0)
self.MV_obj.setEndValue(10)
self.MV_obj.start()
obj.show()
def reload(self):
s_l: list = self.poss.copy()
for i in self.buttons:
r = randint(0, len(s_l) - 1)
p = s_l.pop(r)
i.setGeometry(p[0], p[1], 70, 70)
def check(self):
if [[a.x(), a.y()] for a in self.buttons] == self.poss:
self.msg_win.setText('win\n\n steps: {}'.format(
int(self.steps.text()[self.steps.text().find(':') + 1:]))
)
self.mv(self.msg_win, 0, 0, 'win')
self.msg_win.finished.connect(self.reload)
self.steps.setText('st. : 0')
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Game15()
sys.exit(app.exec_())
Автор решения: S. Nick
→ Ссылка
я отметил для вас строки, в которые внес изменения и переставил местами. Уберите текст, который я добавил на кнопки для отладки. Пробуйте:
import sys
import random
import pymorphy2 # pip install pymorphy2
import webbrowser
from PyQt5 import QtGui
from PyQt5.QtGui import QPainter, QIcon
from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget, QInputDialog, \
QPushButton, QFileDialog, QHBoxLayout, QVBoxLayout, QDialog, QLabel, QFormLayout
from PyQt5.QtCore import QSize, Qt, QRect
class Start(QDialog):
def __init__(self, root=None):
# super().__init__(root)
super(Start, self).__init__()
self.main = root
self.resize(200, 150)
self.setWindowTitle('Start menu')
self.size_widget = QWidget(self)
self.size_widget.setGeometry(QRect(30, 30, 351, 175))
# self.layout = QFormLayout(self.size_widget)
# self.layout.setContentsMargins(0, 0, 0, 0)
self.new_label = QLabel('Новая игра', self)
self.load_label = QLabel('Загрузить поле', self)
self.new_button = QPushButton('Start\nnew', self)
self.new_button.setFixedSize(50, 50)
self.new_button.clicked.connect(self.new_clicked)
self.new_button.setIcon(QIcon('new_im.png'))
self.new_button.setIconSize(QSize(40, 40))
self.load_btn = QPushButton('Start\nload', self)
self.load_btn.setFixedSize(50, 50)
self.load_btn.clicked.connect(self.load_clicked)
self.load_btn.setIcon(QIcon('load_im.png'))
self.load_btn.setIconSize(QSize(40, 40))
self.layout = QFormLayout(self.size_widget) # +
self.layout.setContentsMargins(0, 0, 0, 0) # +
self.layout.setWidget(0, QFormLayout.FieldRole, self.new_button)
self.layout.setWidget(0, QFormLayout.LabelRole, self.new_label)
self.layout.setWidget(1, QFormLayout.LabelRole, self.load_label)
self.layout.setWidget(1, QFormLayout.FieldRole, self.load_btn)
def new_clicked(self):
self.main.start_arg = 'new'
self.close()
def load_clicked(self):
self.main.start_arg = 'load'
self.close()
# была ошибка !
# QWidget::setLayout: Attempting to set QLayout "" on gg "", which already has a layout
class Game(QWidget): # - gg, + Game
def __init__(self):
super().__init__()
self.load_fl = False
self.have_size = False
self.field = False
self.start_arg = 'new'
self.n = 0 # +++
start_arg = Start(self)
start_arg.exec_()
self.setupUI()
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
self.save_btn = QPushButton("save", self) # save
self.save_btn.setFixedSize(50, 50)
self.save_btn.setIcon(QIcon('save_im.png'))
self.save_btn.setIconSize(QSize(40, 40))
self.save_btn.clicked.connect(self.save)
self.load_btn = QPushButton("load", self) # load
self.load_btn.setFixedSize(50, 50)
self.load_btn.setIcon(QIcon('load_im.png'))
self.load_btn.setIconSize(QSize(40, 40))
self.load_btn.clicked.connect(self.load)
self.doc_btn = QPushButton("doc", self) # doc
self.doc_btn.setFixedSize(50, 50)
self.doc_btn.setIcon(QIcon('doc_im.png'))
self.doc_btn.setIconSize(QSize(40, 40))
self.doc_btn.clicked.connect(lambda: webbrowser.open('https://www.logozavr.ru/1640/'))
self.new_btn = QPushButton('new', self) # 'new'
self.new_btn.setFixedSize(50, 50)
self.new_btn.setIcon(QIcon('new_im.png'))
self.new_btn.setIconSize(QSize(40, 40))
self.new_btn.clicked.connect(self.new_f)
vbox = QVBoxLayout()
vbox.addStretch(-1)
vbox.setSpacing(0)
vbox.addWidget(self.save_btn)
vbox.addWidget(self.load_btn)
vbox.addWidget(self.new_btn)
vbox.addWidget(self.doc_btn)
self.hbox = QHBoxLayout(self)
self.hbox.addStretch(0)
self.hbox.addLayout(vbox)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
def setupUI(self):
self.setWindowTitle('Пятнашки')
self.cell_size = 100
if self.start_arg == 'load' and self.load_fl is False:
self.load()
elif self.have_size:
self.matrix = []
self.have_size = False
elif self.load_fl is False:
self.matrix = []
self.new_field_dialog()
### TypeError: unsupported operand type(s) for *: 'builtin_function_or_method' and 'builtin_function_or_method'
self.empty = self._size * self._size # +++ замените `size` на `_size` ВЕЗДЕ!!!
if len(self.matrix) == 0:
self.matrix_create()
self.setFixedSize(self.cell_size * self._size + 62, self.cell_size * self._size)
''' перенес в конструктор !!!
self.save_btn = QPushButton("save", self) # save
...
self.hbox.addLayout(vbox)
'''
def new_f(self):
cancel = self.new_field_dialog()
if cancel:
self.have_size = True
self.setupUI()
def save(self):
try:
fileName = QFileDialog.getSaveFileName(self, 'Save file')
if fileName:
f = open(fileName[0], 'w')
f.write(str(self.matrix)[1:-1])
except Exception:
pass
def load(self):
try:
fname = QFileDialog.getOpenFileName(self, 'Open file')
f = open(fname[0], 'r').read().split('], ') # ???
self.matrix = []
for i in f:
if i == f[-1]:
i = i[1:-1].split(', ')
else:
i = i[1:].split(', ')
lst = [int(j) for j in i]
self.matrix.append(lst)
self._size = len(self.matrix[0])
self.load_fl = True
self.setupUI()
except Exception:
pass
def matrix_create(self):
self.n = 0
cells_value = list(range(1, self._size * self._size))
random.shuffle(cells_value)
cells_value.append(self.empty)
self.matrix = []
for i in range(self._size):
lst = []
for j in range(self._size):
lst.append(cells_value.pop(0))
self.matrix.append(lst)
def mouseReleaseEvent(self, event):
pos = event.pos()
y = pos.x() // self.cell_size
x = pos.y() // self.cell_size
def cell_find(x, y):
try:
if x < 0 or y < 0:
raise IndexError
return self.matrix[x][y], x, y
except IndexError:
return None
try:
near_cells = [
cell_find(x - 1, y),
cell_find(x + 1, y),
cell_find(x, y - 1),
cell_find(x, y + 1)]
empty_cell = []
for i in near_cells:
if i is not None and i[0] == self.empty:
empty_cell.append(i)
if len(empty_cell) > 0:
value = cell_find(x, y)[0]
empty_value, x2, y2 = empty_cell[0]
self.matrix[x][y] = empty_value
self.matrix[x2][y2] = value
lst = []
for row in self.matrix:
for j in row:
lst.append(j)
lst.pop()
self.n += 1
word = pymorphy2.MorphAnalyzer().parse('ход')[0]
w = word.make_agree_with_number(self.n).word
if lst == list(range(1, self._size * self._size)):
vict_massage = QMessageBox(self)
vict_massage.information(self, 'Victory', 'Ура, вы сделали это,' + '\n'
'на это у вас ушло ' + str(
self.n) + ' ' + w + '!')
self.matrix_create()
self.update()
except IndexError:
pass
def new_field_dialog(self):
try:
in_d = QInputDialog.getText(self, 'Ввод размера', 'Введи число от 3 до 10 (размер поля)')
text, ok = in_d
if ok:
self._size = int(text)
if self._size < 3 or self._size > 10:
raise ValueError
elif self.field is False:
exit()
else:
return False
return True
except ValueError:
error_m = QMessageBox(self)
error_m.information(self, 'error', 'Неверный ввод, попробуйте снова.')
self.new_field_dialog()
def paintEvent(self, event):
self.field = True
qp = QPainter(self)
qp.setPen(QtGui.QColor('black'))
for i, row in enumerate(self.matrix):
y = i * self.cell_size
for j, value in enumerate(row):
x = j * self.cell_size
if value == self.empty:
qp.setBrush(QtGui.QColor('white'))
else:
qp.setBrush(QtGui.QColor('green'))
qp.drawRect(x, y, self.cell_size, self.cell_size)
if value != self.empty:
text = str(value)
else:
text = ''
qp.drawText(x, y, self.cell_size, self.cell_size, Qt.AlignCenter, text)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Game()
ex.show()
sys.exit(app.exec_())

