Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Child nodes are not anchored within their parent node
-
The docs say that
After a child is added to the node tree, it is positioned inside its parent’s coordinate system by setting its position attribute
but clearly that is not the case... The BoardSquare at position 0, 0 is not placed at the 0, 0 pixel of its parent, the CheckerBoard.""" CheckersScene contains: One CheckersBoard ShapeNode painted White contains: 64 CheckersSquare ShapeNodes painted Red and Blue """ from scene import * colorWhite = (1, 1, 1) colorRed = (1, 0, 0) colorBlue = (0, 0, 1) class CheckersScene(Scene): def setup(self): self.board = CheckersBoard(self) def squareAtCenterOfScreen(self): theMin = min(self.size.w, self.size.h) theRect = Rect(0, 0, theMin, theMin) theOffset = abs(self.size.w - self.size.h) / 2 if self.size.w > self.size.h: theRect.x = theOffset # landscape else: theRect.y = theOffset # portrait return theRect class CheckersBoard(ShapeNode): def __init__(self, parent, inSquaresPerRow = 8): x, y, w, h = parent.squareAtCenterOfScreen() super().__init__(ui.Path.rect(x, y, w, h), fill_color='white', # anchor_point=(0, 0), parent=parent, position=parent.bounds.center()) # self.anchor_point = (0, 0) sq_size = w / inSquaresPerRow for i in range(inSquaresPerRow): for j in range(inSquaresPerRow): frame = (j * sq_size, i * sq_size, sq_size, sq_size) theSquare = BoardSquare(self, frame, (i, j)) class BoardSquare(ShapeNode): def __init__(self, parent, frame, inLocation): x, y, w, h = frame print(frame) super().__init__(ui.Path.rect(x, y, w, h), # anchor_point = (0, 0), parent=parent, position=(x, y)) # self.anchor_point = (0, 0) odd = (inLocation[0] + inLocation[1]) % 2 self.fill_color = colorRed if odd else colorBlue run(CheckersScene())
-
Your CheckerBoard class is sitting at
position=parent.bounds.center()
, so I do not understand what you do mean with 'is not placed at the 0, 0 pixel', it seems to be working asintendedexpected. If you want the board to sit whithin screen bounds you have to choose your Board center somewhere in the lower left corner. -
Please reread the question. Placing a Node within a Scene is not the problem. Placing a Node within a Node is the problem. CheckersBoard is properly placed in CheckersScene but the BoardSquares are not properly placed in CheckersBoard.
-
@ccc The (0, 0) coordinate within a node is its center by default. You can set the
anchor_point
property to change that – it defaults to (0.5, 0.5). -
@omz. Thanks but I tried that in four different locations in this code without success. Can you please provide me more precision on where in the code above to place
anchor_point = (0, 0)
.I updated the code above to show the four places where I tried
anchor_point = (0, 0)
. The first two moved the CheckersBoard offscreen :-( without moving the BoardSquares. The second two had no effect at all. -
The confusing bit is that anchor_point not only defines how a node is placed within its parent, but also defines the origin of the node as children relate to it.
This works fine if everybody's anchor_point is the same, but may be confusing when you want a node centered on the scene, but subnodes referenced from corner.
For your code, the easiest fix is when the board is anchored at (.5,.5), to center it in the scene, you need to subtract size/2 from the square positions (anchored at 0,0)
class BoardSquare(ShapeNode): def __init__(self, parent, frame, inLocation): x, y, w, h = frame print(frame) super().__init__(ui.Path.rect(0,0, w, h), parent=parent, position=(x,y)-parent.size/2,anchor_point = (0.0, 0.0)) odd = (inLocation[0] + inLocation[1]) % 2 self.fill_color = colorRed if odd else colorBlue
Ideally, there would have been something like a "frame anchor" and "bounds anchor".
-
@JonB Thanks. Now it makes sense to me.
I think the approach that I will take is to just anchor_point all Nodes to (0, 0) because that seems to fit my brain better for complex layouts.
""" CheckersScene contains: One CheckersBoard ShapeNode painted White contains: 64 CheckersSquare ShapeNodes painted Red and Blue """ from scene import * colorWhite = (1, 1, 1) colorRed = (1, 0, 0) colorBlue = (0, 0, 1) class CheckersScene(Scene): def setup(self): self.board = CheckersBoard(self) def squareAtCenterOfScreen(self): theMin = min(self.size.w, self.size.h) theRect = Rect(0, 0, theMin, theMin) theOffset = abs(self.size.w - self.size.h) / 2 if self.size.w > self.size.h: theRect.x = theOffset # landscape else: theRect.y = theOffset # portrait return theRect class CheckersBoard(ShapeNode): def __init__(self, parent, squares_per_row=8): x, y, w, h = parent.squareAtCenterOfScreen() super().__init__(ui.Path.rect(x, y, w, h), anchor_point=(0, 0), fill_color='white', parent=parent, position=(x, y)) sq_size = w / squares_per_row for i in range(squares_per_row): for j in range(squares_per_row): frame = (j * sq_size, i * sq_size, sq_size, sq_size) BoardSquare(self, frame, (i, j)) class BoardSquare(ShapeNode): def __init__(self, parent, frame, inLocation): x, y, w, h = frame fill = colorRed if (inLocation[0] + inLocation[1]) % 2 else colorBlue super().__init__(ui.Path.rect(x, y, w, h), anchor_point=(0, 0), fill_color=fill, parent=parent, position=(x, y)) run(CheckersScene())