Question

I'm currently writing up some GUI code for a small project I'm working on and I've come to the point where I need to implement scroll bars and their associated containers. For ease of execution, I would love to be able to draw all elements within the "scroll box" (the window that the scroll bar will affect) to a separate surface from my main display surface. The separate surface would then be cropped as need be and then drawn to the display surface in the render loop. I'm having trouble getting this to work, however.

In the draw() method of my ScrollBox class, I have the following code.

def draw(self):
    self.subSurface.blit(self.image, (x, y)) 
    #subSurface is, naturally, a Surface, and image is a pygame.Image; x and y are whatever
    self.displaySurface.blit(self.subSurface, (x,y))

As with all drawable GUI elements in my code, draw() is called every pass through the main render loop. What the above code gives me is the default filled-in black Rect and self.image is not displayed in any capacity. I tried replacing the first line with

pygame.draw.rect(self.subSurface, color, rect)

but it yielded the same results. From my reading up on other Pygame GUI libraries, it seems what I want to do is possible but I don't think I'm executing it properly. How do I attach other sources/surfaces to subSurface and then have subSurface be drawn (with the sources attached) by displaySurface?

Any help would be much appreciated. Thanks.

Was it helpful?

Solution

For people visiting this question in the future:

Remember that the dest argument for Surface.blit() is relative to the upper-left corner of the destination surface. So if you're assembling an image on a subsurface, remember to use coordinates relative to the top-left corner of the object you're assembling, rather than absolute display coordinates.

So to assemble a scrollbar and draw it somewhere:

class ScrollBar:
    # ... code ...
    def render(self, display, x, y):
        self.subSurface.blit(self.handle_image, (0, self.handle_pos))
        self.subSurface.blit(self.upbtn_image, (0, 0))
        self.subSurface.blit(self.dnbtn_image, (0, self.height - self.btn_height))
        # ... other rendering operations
        display.blit(self.subSurface, (x, y))

Adjust all numbers and variable names to taste, but you get the idea. Notice that all the scrollbar elements are positioned in "scrollbar-local" coordinates, with only the final blit to the display surface positioned in screen/application coordinates.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top