Python Forum
Libraries/Tools to create an editor similar to Tiled
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Libraries/Tools to create an editor similar to Tiled
#1
Hello python forum,

I am working on a tile map builder project. I am attempting to create a GUI editor which would help the user create a tile map. I am storing all data in a dictionary in a file. Do you guys have any suggestions as to how to create such an editor, such as what libs to use?

Thank you so much.
Tim
Reply
#2
I was not to clear on the design of the program. On the left side, there will be a grid, on which you can drag and click to insert images into a specific box on the grid. On the left will be a collection of images which you can select to use. The user should also then be able to export this as a transparent png.
Reply
#3
Could anyone tell me why no body is answering my question?
Reply
#4
I'm not answering because I don't know the answer. I suppose that most of Python's GUI frameworks could be used for that, and PIL for image manipulation, but I don't have a more specific answer to offer.
Reply
#5
Quote:Could anyone tell me why no body is answering my question?
your question is similar to 'What's your favorite ice cream and how do I start making it.' Find one you love and practice, practice practice. Then when you get stuck post your script and ask for help.
Reply
#6
I would design this as a grid of buttons. Clicking a button pops up a dialog containing all the tiles. Select a tile and it appears as the label for the button. Dragging is certainly possible, but more work. Having the tile choices visible all the time makes the program window larger than it has to be. I would use the right button or mouse wheel to rotate the tiles.

I would use the Python Image Library (PIL) for manipulating images (resizing to tiles, rotating, stitching together).

The user interface could be done using any GUI.
Reply
#7
Thank you for your suggestion.
That is what I will do.
Reply
#8
I think I will make every button press add to a dictionary which would contain the coords and the image path or name.
Reply
#9
This is an app written with Qt. It uses a custom button that draws an image as the button background. Multiple tile buttons create a TileControl that uses a signal to call a function when one of the image buttons is pressed.
"""Mosaic image generator"""
import sys
import math
import pathlib
from functools import partial
from PIL import Image, ImageQt
from PySide2.QtWidgets import QApplication, QPushButton, QWidget, QDialog, QGridLayout, QVBoxLayout
from PySide2.QtGui import QPainter, QPainterPath, QCursor
from PySide2.QtCore import Qt, QRect, Signal

TILE_SIZE = (60, 60)
TILE_RECT = QRect(2, 2, 56, 56)

class Tile(QPushButton):
    """A button for displaying images"""
    def __init__(self, parent):
        super().__init__(parent)
        self.setFixedSize(*TILE_SIZE)
        self.image = None
        self.image_file = None

    def paintEvent(self, _):
        """Paint widget.  Fill with image or draw a rounded rectangle"""
        painter = QPainter(self)
        if self.image:
            painter.drawImage(0, 0, ImageQt.ImageQt(self.image))
        else:
            path = QPainterPath()
            path.addRoundedRect(TILE_RECT, 4, 4)
            painter.fillPath(path, Qt.lightGray)
        painter.end()

    def load_image(self, image):
        """Load image from a file"""
        self.image_file = image
        if self.image_file:
            self.image = Image.open(image).resize(TILE_SIZE)
        else:
            self.image = None
        self.update()

class TileControl(QWidget):
    """A matrix of tiles.  Use clicked signal to be notified when a tile is selected"""

    clicked = Signal(Tile)

    def __init__(self, parent, rows, columns):
        super().__init__(parent)
        layout = QGridLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setHorizontalSpacing(0)
        layout.setVerticalSpacing(0)
        self.rows = rows
        self.columns = columns
        self.tiles = []
        for row in range(rows):
            for column in range(columns):
                tile = Tile(self)
                tile.clicked.connect(partial(self.select_tile, tile))
                layout.addWidget(tile, row, column)
                self.tiles.append(tile)

    def select_tile(self, tile):
        """Callback when tile is pressed.  Send signal with tile as arg"""
        self.clicked.emit(tile)


class TileDialog(QDialog):
    """Dialog for selecting a tile"""
    def __init__(self, images):
        super().__init__()
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.tile = None
        tile_count = len(images) + 1
        columns = int(math.ceil(math.sqrt(tile_count)))
        rows = int(math.ceil(tile_count / columns))
        self.tiles = TileControl(self, rows, columns)
        for tile, image in zip(self.tiles.tiles, images):
            tile.load_image(image)
        self.tiles.clicked.connect(self.select_tile)
 
        reject_button = QPushButton('Cancel')
        reject_button.clicked.connect(self.reject)

        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(2, 2, 2, 2)
        self.layout.setSpacing(2)
        self.layout.addWidget(self.tiles)
        self.layout.addWidget(reject_button)

    def select_tile(self, tile):
        """Tile was selected.  Save and accept"""
        self.tile = tile
        self.accept()

class TileWindow(QWidget):
    """Make a pretty mosaic.  Set tile images by selecting image from dialog
    that pops up when tile is pressed.
    def"""
    def __init__(self, rows, columns, images):
        super().__init__()
        self.dialog = TileDialog(images)

        self.tiles = TileControl(self, rows, columns)
        self.tiles.clicked.connect(self.select_tile)

        self.layout = QVBoxLayout(self)
        self.layout.addWidget(self.tiles)

    def select_tile(self, tile):
        """A tile was pressed.  Get an image from the dialog"""
        self.dialog.move(QCursor.pos())
        if self.dialog.exec_():
            tile.load_image(self.dialog.tile.image_file)

# Get list of image files in same directory as program
PATH = pathlib.Path(sys.path[0])
IMAGES = [PATH/file for file in PATH.iterdir() if file.suffix in ('.png', '.PNG', '.jpg', '.JPG')]

APP = QApplication()
WINDOW = TileWindow(10, 10, IMAGES)
WINDOW.show()
sys.exit(APP.exec_())
This was a good excuse to learn more about painting in Qt. I'm not sure if I can work up enough interest to stitch all the images together to make a new image.
Reply
#10
I am using Tkinter, but thank you. I will see about taking some ideas and reshaping them to tkinter code.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020