I've been wondering this for a while, why can't I make 1x1 rects in Pygame? There are no errors. It doesn't display. If I switch it to 2x2, it displays fine. (And no, it is not my eyesight.)
According to the pygame docs, the area covered by a Rect does not include the right- and bottom-most edge of pixels. If one Rect’s bottom border is another Rect’s top border (i.e., rect1.bottom==rect2.top), the two meet exactly on the screen but do not overlap, and rect1.colliderect(rect2) returns false. (formatting mine)
In context, this means that, since rect1.bottom == rect1.top, rect1.colliderect(rect1) == false, so the rect is empty.
Related
I am making a game, with pygame, and i want it to be that when the mouse hovers over my text, the box gets shaded.
here is what I have so far:
in the event-handling loop:
(tuples in CheckToUnshadeBoxes are pairs of text-surfaces and their boxes (from get_rect method))
elif event.type == MOUSEMOTION:
CheckToShadeBoxes(event, LERect, LoadRect, PlayRect)
CheckToUnshadeBoxes(event, (LERect, LESurf),
(LoadRect, LoadSurf), (PlayRect, PlaySurf))
here is CheckToShadeBoxes:
def CheckToShadeBoxes(event, *args):
'''
shade the box the mouse is over
'''
for rect in args:
s = pg.Surface((rect.width, rect.height))
s.set_alpha(50)
print(rect.x, rect.y)
s.fill(COLOURS['gray'])
x, y = event.pos
if rect.collidepoint(x, y):
SURFACE.blit(s, (rect.x, rect.y))
and CheckToUnshadeBoxes:
def CheckToUnshadeBoxes(event, *args):
''' if the mouse moves out of the box, the box will become unshaded.'''
for (rect, TextSurf) in args:
x, y = event.pos
if not rect.collidepoint(x, y):
SURFACE.blit(TextSurf, (rect.x, rect.y))
This works fine! except that when I move the mouse inside of the box, the box will continue to get darker and darker until you cant even see the text! I know it is a small detail, but it has been bugging me for a long time and I don't know how to fix it.
by the way, if it is not evident enough, COLOURS is a dictionary with string keys and RGB tuple values, and SURFACE is my main drawing surface.
If you have any questions about my code, or anything I have done just comment!
If the rects you are passing are your own derived class, then I recommend making a .is_shaded class variable and checking to make sure the variable is false before shading it.
If these rects aren't your own class extending another, then I recommend you make one, as it would make it much simpler
The problem with your code is that you keep adding in dark rectangles when the mouse is hovered over. No wonder it gets darker and darker.
All that is needed is for your code to be shuffled around a little.
Inside your event handling, you should call a function to check if it should shade the text. This should return a Boolean value. Store this in a variable. Most of the code from the CheckToShadeBoxes function will do the trick.
In your render section, you should render just one surface on top of your text, based on whether the Boolean value is true or not. The code that creates a gray surface in the CheckToShadeBoxes function will work but make sure it is only one surface. Don't create a new surface in every iteration. Define it outside once and blit it to the screen inside the loop.
This should fix your problem!
I hope this answer helps you! If you have any further questions please feel free to post a comment below!
In TkInter, we can draw several shapes. But what if we just want to draw a pixel instead ?
After creating a Canvas object, you can draw a line that spans a single pixel.
your_canvas_widget.create_line(x, y, x + 1, y)
To create a single pixel with co-ordinates x, y on a canvas, you can use a rectangleobject:
canvas.create_rectangle( (x, y)*2 )
By default, the rectangle object has a one-pixel wide black border, which when one-pixel wide will just be black, regardless of the colour. To give the pixel your desired colour, you can use outline="", so you can then specify your fill colour.
I prefer this method as you only need to provide the x, y co-ordinates, no x+1 is needed.
This topic is already answered and quite old but I'd like to add a comment, maybe it is of interest:
your_canvas_widget.create_line(x, y, x + 1, y)
Is what I have also tried and it works for me. I used it for creating an image of a Mandelbrot-set. It works quite fine for small resoltions, e.g. 200 x 200 pixel. But for larger resolutions, the TK engine seems to have problems to render those many "micro lines". the calculation of the mandelbrot set is finished, but the Tk window seems to hang without rendering anything.
A better solution for drawing pixels, I have found in python-mandelbrot-fractal-with-tkinter. There the pixels are put one by one into a tkinter PhotoImage which is afterwards rendered all in one, very fast.
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.
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.
I'm trying to simulate an American traffic light, with 3 circles on a rectangle, all drawn on a set Canvas. The simulation is supposed to mirror "animation" by changing which light is displayed every 2 seconds in the following order: green > yellow > red > green, etc forever.
The only way I can think of to do this is by using a canvas.move(), canvas.after(), canvas.update() pattern to move a filled oval object to superimpose one unfilled circle at a time. I've gotten the logic down to move a circle at the proper speed and in the correct order. The thing is, I just instantiate a circle filled with "green", but I can't change it to be "yellow" or "red" using this method. It seems silly to have to canvas.delete("filled") and redraw it in a new place with a different fill every 2 seconds, because that's a lot to do for such a simple program.
Question 1: Is there a way I can just alter the fill option for my filled Canvas object at will, using some method or other means?
Question 2: Am I approaching this scenario incorrectly? Is there a better way to simulate this?
Yes you should be able to change settings of the canvas with config().
Likewise, use itemconfig() to change items on the canvas. This does require that you save a handle to the item or tag them.
Example based on tkinterbook:
item = canvas.create_line(xy, fill="red")
canvas.coords(item, new_xy) # change coordinates
canvas.itemconfig(item, fill="blue") # change color
In Python for Symbian60 blit() is defined as:
blit(image [,target=(0,0), source=((0,0),image.size), mask=None, scale=0 ])
In the optional parameter source what is the significance of image.size?
My guess is that blit() will automatically use the result of image.size when you don't specify anything else (and thus blitting the whole image from (0,0) to (width,height)).
If you want only a smaller part of the image copied, you can use the source parameter to define a different rectangle to copy.
Think that source=((0,0)) is the top left corner and image.size is the bottom right corner. You blit whatever is between those two points.
Similar for target, btw.