-2

I'm writing a program that should display a chessboard on request from the console, here's skeleton QGraphicsView

class TableView(QGraphicsView):
    def __init__(self, item):
        super().__init__(item)
        self.num = 1
        self.Size = self.size() - QtCore.QSize(2, 2)
        scene = QtWidgets.QGraphicsScene()
        self.setScene(scene)
        self.RenderBoard()

    def UpdateTable(self, **kwargs):
        for key, val in kwargs.items():
            setattr(self, key, val)
        self.RenderBoard()

    def LoadImage(self, path, size, pos=None, flip=False):
        print(path, size, pos, flip)
        picture = QtGui.QImage(path)
        picture = picture.scaled(size)
        if flip:
            my_transform = QtGui.QTransform()
            my_transform.rotate(180)
            picture = picture.transformed(my_transform)

        pic = QtWidgets.QGraphicsPixmapItem()
        pic.setPixmap(QtGui.QPixmap.fromImage(picture))
        if pos is not None:
            pic.setPos(*pos)
        self.scene().addItem(pic)

    def RenderBoard(self):
        self.scene().clear()
        self.LoadImage('img/board.png', self.Size, flip=(self.num % 2 == 0))

    def resizeEvent(self, event):
        self.Size = self.size() - QtCore.QSize(2, 2)
        self.RenderBoard()
        super().resizeEvent(event)

The program works and outputs the board, but as soon as I call UpdateTable from QtCore.QThread, which accepts requests from the console, the screen turns white. But, if i change the size of the program, the resizeEvent event is called and the program comes to life again and shows exactly what I wanted.

Do you have any idea what the problem might be?

P.S. the update that I call changes one of the arrays from which the reading occurs during rendering, I printing it during the Update call and during the Resize call, in both cases, it is the same.

Other functions

class UpdaterThread(QtCore.QThread):
    def __init__(self, table):
        QtCore.QThread.__init__(self)
        self.table = table

    def run(self):
        sleep(1)
        self.table.UpdateTable(**{'num': 2})

class Ui_ChessHelper(object):
    def setupUi(self, ChessHelper):
        self.table = TableView(self.centralwidget)
        self.table.setMinimumSize(QtCore.QSize(350, 350))
        self.table.setObjectName("table")

        self.thread = UpdaterThread(self.table)
        self.thread.start()
  • Beware of naming rules when using a double leading underscore: https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name – Passerby Dec 31 '21 at 01:35
  • The answer I posted addresses one problem with the code. However, you need to show more code for it to be clear what you are doing. In particular, the RenderBoard function looks suspicious. You clear all existing items, then (guessing) you might be doing some painting, but that is not how the Graphics View framework is intended to work. – Passerby Dec 31 '21 at 01:43
  • @Passerby, thanks for beware, I used underscores on purpose because I didn't want to call these functions from the outside. For the sake of experiment, I removed them, but nothing was fixed – Stella Galaxy Dec 31 '21 at 01:44
  • Widgets are not thread-safe. You cannot create ***nor*** access them from external threads, you can only use signals and slots. For future reference, always try to provide a [mre]. – musicamante Dec 31 '21 at 02:14
  • @musicamante yes, this is what I was looking for, thank you very much – Stella Galaxy Dec 31 '21 at 02:26

1 Answers1

0

QGraphicsView has a method scene() that returns the current scene. When you write

self.scene = QtWidgets.QGraphicsScene()
self.setScene(self.scene)

you are clobbering that method's name with your new scene object. Instead

scene = QtWidgets.QGraphicsScene()
self.setScene(scene)

then use self.scene() to access it later when needed.

Passerby
  • 808
  • 1
  • 5
  • 9