0

I'm fairly new to Python, but I've tried dozens of variations to get this to work, no luck so far.

Background: I'm writing a simple number slide game, as a practice project, using PyQt5. The gui displays 15 number tiles, and I want the player to be able to click a tile and it will move into the blank spot (none of the game logic is here yet, I'm still prototyping the gui). If it matters, I'm coding in PyCharm 2022.1.2 (community).

I'm not getting any errors when I run the code, but when I click a tile it doesn't move and then the game exits with "Process finished with exit code -1073740791" (no errors)

I know clickable QLabels are not really a thing, you have to do an override. But I'm not sure where my code is failing. I suspect it has something to do with the override (ClicableQLabel), or my move_tile function. Or even how I'm doing QGridLayout. I tried all of the answers in this question but none of them worked for me.

class ClickableQLabel(QLabel):
    def __init__(self, when_clicked, parent=None):
        QLabel.__init__(self, parent)
        self._when_clicked = when_clicked

    def mousePressEvent(self, ev):
        self._when_clicked(ev)

class NewGame(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Number Slide Game")
        self.gameTiles = []

        for tile_no in range(0, 15):
            tile_no_img_num = tile_no + 1
            num_img = QPixmap('images\\numTile{0}.png'.format(str(tile_no_img_num)))
            num_label = ClickableQLabel(self.move_tile)
            num_label.setPixmap(num_img)
            self.gameTiles.append(num_label)

        random.shuffle(self.gameTiles)

        game_layout = QGridLayout()
        game_layout.setHorizontalSpacing(0)
        game_layout.setVerticalSpacing(0)

        tile_num = 0
        for rowNum in range(0, 4):
            for colNum in range(0, 4):
                if tile_num < 15:
                    game_layout.addWidget(self.gameTiles[tile_num], rowNum, colNum)
                    tile_num += 1

        self.setLayout(game_layout)

    def move_tile(self, tile_to_move):
        game_tile_to_move = self.gameTiles[tile_to_move]
        game_tile_to_move.anim = QPropertyAnimation(game_tile_to_move, b"pos")
        game_tile_to_move.anim.setEndValue(QPoint(220, 221))
        game_tile_to_move.anim.setDuration(200)
        game_tile_to_move.anim.start()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    gameWindow = NewGame()
    gameWindow.show()
    sys.exit(app.exec_())
Jake Munson
  • 306
  • 3
  • 12
  • 1
    When I run that code and click I do get an error `Traceback (most recent call last): File "C:\Python_Scripts\testing\test.py", line 16, in mousePressEvent self._when_clicked(ev) File "C:\Python_Scripts\testing\test.py", line 48, in move_tile game_tile_to_move = self.gameTiles[tile_to_move] TypeError: list indices must be integers or slices, not QMouseEvent` – Andew Jun 23 '22 at 20:34
  • You should not try to reference a function into another object and then try to call it, as it violates OOP principles. Besides, you want to get the widget from a list, so you obviously need an (integer) index, but you're trying to do that using the `event` argument of `mousePressEvent`. You *could* add the`tile_no_img_num` argument to the `ClickableQLabel` constructor, make it an instance attribute and then call the function with that value, but that would be still *very wrong*. A better implementation would use a custom signal (emitted in the event handler) or an event filter. – musicamante Jun 23 '22 at 21:36
  • Also, you shall not use `setGeometry()` when using a layout manager, because sooner or later that manager will *reset* the widget geometry based on its grid ("cell") coordinates. Unless you *move* the widget(s) to the new cells as soon as the animation has finished, but this shows another flow: you have to *first* understand the logic for object movement (since it's a number slide game, you may need to move *groups* of tiles). – musicamante Jun 23 '22 at 21:39
  • @musicamante can you provide some code showing how I'd do the custom signal? I tried to do something like that but didn't do it right (I guess) because it didn't work. I'm trying to learn OOP as I go as well, so I'm sure I've hosed plenty up here in that regards. – Jake Munson Jun 24 '22 at 17:53
  • @JakeMunson Please [edit] your post and add that attempt in using signals. We prefer to answer on existing code attempts instead of providing "the job already done": it's more useful to you (so that you can understand what you did wrong - which is much better than a "that's how it's done") and to anybody else that could face a similar problem. – musicamante Jun 24 '22 at 21:59

0 Answers0