Не работает корректно код (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_())

введите сюда описание изображения

→ Ссылка