Pyglet copy and paste a text in an IncrementalTextLayout() object - python

Is there a way to make a simple "copy and paste" in Pyglet?
I need to copy a text (ctrl + c) and paste (ctrl + v) it into a IncrementalTextLayout() object in Pyglet, is this possible?
I'm using Python 3.4, Pyglet 1.2.4 and I run on Windows.
Code example:
import pyglet
if __name__ == "__main__":
window = pyglet.window.Window(617, 200)
batch = pyglet.graphics.Batch()
document = pyglet.text.document.FormattedDocument("Colar texto aqui!")
document.set_style(0, len(document.text), dict(font_name='Arial', font_size=25, color=(255, 255, 255, 255)))
layout = pyglet.text.layout.IncrementalTextLayout(document, 300, 50, batch=batch)
caret = pyglet.text.caret.Caret(layout, color=(255, 255, 255))
window.push_handlers(caret)
#window.event
def on_draw():
"""Desenha a tela."""
window.clear()
batch.draw()
window.push_handlers(caret)
pyglet.app.run()

Another developer resolved this with the Pyperclip and put your functions in the on_key_press method of the Window in Pyglet. Follow the code bellow:
def on_key_press(self, symbol, modifiers):
if modifiers is 18 and pyglet.window.key.MOD_CTRL and int(symbol) is pyglet.window.key.V:
if self.input_text:
self.on_text(pyperclip.paste())
elif modifiers is 18 and pyglet.window.key.MOD_CTRL and int(symbol) is pyglet.window.key.C:
pyperclip.copy(self.input_text.document.text)

Related

Pyglet render into texture

I'm writing a drawing program using pyglet, and I want to be able to have the image being created as separate from the window's buffer (for instance, the image could be larger than the window, or may want to draw to this image at a different rate than the main window is being re-drawn). I want to be able to draw into this off-screen image, then display it in the window, but pyglet doesn't allow drawing to anything else than a window. Is there any simple way I can do this?
I've tried creating a second hidden pyglet window, but this gets rendered at the same rate as the main window which I definitely don't want.
The closest I found was Pyglet draw text into texture, but the code there isn't complete, and also no longer works as the opengl version used by pyglet has moved on.
The following code works for me, perhaps someone else can improve on my answer:
import pyglet
from pyglet.gl import *
from ctypes import byref
W, H = 800, 600
image = pyglet.image.create(W, H)
texture = image.get_texture()
window = pyglet.window.Window(width=W, height=H)
fbo_id = gl.GLuint(0)
glGenFramebuffers(1, byref(fbo_id))
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
glBindTexture(GL_TEXTURE_2D, texture.id)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0)
rect1 = pyglet.shapes.Rectangle(0, 0, W, H, (255, 0, 0) )
rect2 = pyglet.shapes.Rectangle(W//4, H//4, W//2, H//2, (0, 0, 255) )
label = pyglet.text.Label("Hello World", font_name="Times New Roman", font_size=36,
x=W//2, y=H//2, anchor_x="center", anchor_y="center")
rect1.draw()
rect2.draw()
label.draw()
#window.event
def on_mouse_drag(x, y, dx, dy, xxx, modifiers):
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
line = pyglet.shapes.Line(x-dx, y-dy, x, y, 3, (0, 255, 255))
line.draw()
#window.event
def on_draw():
glBindFramebuffer(GL_FRAMEBUFFER, 0)
window.clear()
texture.blit(0, 0)
pyglet.app.run()

Python Pyglet, new sprites in batch

Python, pyglet
I want to add sprites to my window after it was drawn.
i try to use batch, becouse i want to to have lot of sprites.
my simple testing code is:
import pyglet
import random
from pyglet.window import key, mouse
from pyglet import image
from PIL import Image, ImageDraw, ImageFont
#function return pyglet image 10x10px triangle, random color. Instead of loading a file, work fine
def pyimg():
background = Image.new('RGBA', (10,10), (255,255,255,0) )
img = Image.new('RGBA', (10,10), (0,0,0,0) )
draw = ImageDraw.Draw(img)
draw.polygon([(0,0), (0,10), (10,0)], fill=(random.randint(0,255),random.randint(0,255),random.randint(0,255)))
im= Image.alpha_composite(background, img)
return pyglet.image.ImageData(im.width, im.height, 'RGBA', im.tobytes(), pitch=-im.width * 4)
screenWidth=1280
window = pyglet.window.Window(screenWidth, 720, resizable=True)
batch=pyglet.graphics.Batch()
sprites=[]
sprites.append(pyglet.sprite.Sprite(pyimg(), x=50, y=50, batch=batch))
sprites.append(pyglet.sprite.Sprite(pyimg(), x=150, y=50, batch=batch))
i=30
#window.event
def on_draw():
window.clear()
batch.draw()
#window.event
def on_key_press(symbol, modifiers):
global i
if symbol == key.RETURN:
print("Return key pressed")
sprites.append(pyglet.sprite.Sprite(pyimg(), x=150+i, y=50))
i+=15
pyglet.app.run()
App displays two sprites, and should add one more after enter key pressed. How to update display?
This line: sprites.append(pyglet.sprite.Sprite(pyimg(), x=150+i, y=50)) you aren't specifying the batch to add sprites into.
It needs to be sprites.append(pyglet.sprite.Sprite(pyimg(), x=150+i, y=50, batch=batch))

Two Surfaces not bliting pygame

I'm trying to render some font onto my Pygame screen but it never shows up. I think I have everything set-up right and my programs not throwing any errors so I'm not sure what's wrong. This is the code I'm using to try and create the text:
pygame.init()
pygame.display.set_caption("MyGame")
font = SysFont("Times", 24) #Create a new font using times if it exists, else use system font.
white = (255, 255, 255)
while True: #Game loop
label = font.render("Score: " + str(score), 1, white)
self.surface.blit(label, (100, 100))
# Do other game things....
self.board.draw()
pygame.display.update()
self.clock.tick(60)
and in my init function:
def __init__(self):
self.surface = pygame.display.set_mode((400, 500)) #Set dimensions of game window. Creates a Surface
self.clock = pygame.time.Clock()
self.board = Board(self.surface) # Board is an object in my game
What am I doing wrong? I've looked all over the Pygame documentation and SO but I can't see anything wrong in my code. I've also tried setting the font explicitly with
font = pygame.font.Font("/System/Library/Fonts/Helvetica.dfont", 24)
but nothing seems to work.
As furas suggested, the problem was caused by me filling in the surface after drawing.

Pygame: Rect Objects Don't Render Properly in For Loops

I'm currently using Pygame to develop a game and I've decided that I'd group all my GUI objects together in a dictionary like so:
gui_objects = {
# The GuiObject parameters define a rect (for positioning) and background colour.
"healthbar" : GuiObject((10, 10, 100, 20), Colour.BLUE),
"mini_map" : GuiObject((10, 400, 50, 50), Colour.WHITE)
}
The reason I'm grouping GUI objects like this is so I can easily modify them like:
gui_objects.get("mini_map").set_enabled(false)
Now, when I want to render my GUI objects to the screen, I simply did this:
for key, value in gui_objects.iteritems():
value.render(screen)
This works, but for some reason, the white "mini_map" GuiObject gets rendered underneath the "healthbar" GuiObject. I decided to put the "mini_map" above the "healthbar" in the dictionary, but that changed nothing. But now here's the weird part. If I render the GUI objects separately, that is, by calling their render() functions separately, like this:
gui_objects.get("healthbar").render(screen)
gui_objects.get("mini_map" ).render(screen)
Then the GuiObjects overlap properly. My question now is, why do my GuiObjects not overlap properly when I render them using the for loop? Yet they overlap just fine when rendered separately?
Unfortunately, I can't upload images because I don't have enough reputation ¬_¬ But, here's the source code:
import pygame
# Just a definition of a few colours
class Colour(object):
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
BLUE = ( 64, 128, 255)
# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
def __init__(self, rect, colour):
self.rect = rect
self.colour = colour
def render(self, screen):
pygame.draw.rect(screen, self.colour, self.rect)
def main():
############################################################################
# Initialise
pygame.init()
screen = pygame.display.set_mode((800, 600))
# if render_type = 0 then render GuiObjects using a for loop
# if render_type = 1 then render GuiObjects separately.
render_type = 1
gui_objects = {
"hpbar_bg" : GuiObject(( 0, 0, 150, 600), (Colour.BLUE)),
"enemy_hpbar" : GuiObject((10, 10, 200, 400), (Colour.WHITE)),
}
############################################################################
# Main loop
while True:
########################################################################
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
########################################################################
# Render
screen.fill((0, 0, 0))
# Here, I render the GuiObjects.
if render_type == 0:
# This for loop messes up overlapping.
for key, value in gui_objects.iteritems():
value.render(screen)
elif render_type == 1:
# This works fine.
gui_objects.get("hpbar_bg").render(screen)
gui_objects.get("enemy_hpbar").render(screen)
pygame.display.flip()
if __name__ == "__main__":
main()
Has anyone got a clue as to why overlapping GuiObjects doesn't work properly when using the for loop?
I hope I've explained myself clearly enough. If not, just ask and I'll try to clarify.
Because dictionaries aren't ordered and it is drawing the objects in a different order than your other method.
A dictionary is just not designed for holding objects that need to stay in order.
You can either:
Use a pygame render group instead.
This would be the pygame-recommended way to store groups of objects that are going to be drawn, however you would have to convert your GUI objects into sprites I believe. EDIT: Also, pygame render groups are still not ordered so this wouldn't solve your particular problem.
Use a list of tuples [(name,value),...] instead (this will be the most similar to your current method because that's actually what the iteritems() dictionary method returns).
Here is your code re-written using method 2:
import pygame
# Just a definition of a few colours
class Colour(object):
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
BLUE = ( 64, 128, 255)
# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
def __init__(self, rect, colour):
self.rect = rect
self.colour = colour
def render(self, screen):
pygame.draw.rect(screen, self.colour, self.rect)
def main():
############################################################################
# Initialise
pygame.init()
screen = pygame.display.set_mode((800, 600))
# if render_type = 0 then render GuiObjects using a for loop
# if render_type = 1 then render GuiObjects separately.
render_type = 0
gui_objects = [
("hpbar_bg", GuiObject(( 0, 0, 150, 600), (Colour.BLUE))),
("enemy_hpbar", GuiObject((10, 10, 200, 400), (Colour.WHITE))),
]
############################################################################
# Main loop
while True:
########################################################################
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
########################################################################
# Render
screen.fill((0, 0, 0))
# Here, I render the GuiObjects.
if render_type == 0:
# This for loop no longer messes up overlapping.
for key, value in gui_objects:
value.render(screen)
pygame.display.flip()
if __name__ == "__main__":
main()
Because you would like to be able to do things like gui_objects.hpbar_bg.set_enabled(False) then I would look into a third option:
Restructuring your code to contain the GUI within a class itself, and then order the drawing of its components within its draw method.
Here is an example of 3 that doesn't deviate too far from what you've got:
import pygame
# Just a definition of a few colours
class Colour(object):
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
BLUE = ( 64, 128, 255)
# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
def __init__(self, rect, colour):
self.rect = rect
self.colour = colour
self.enabled = True
def render(self, screen):
if self.enabled:
pygame.draw.rect(screen, self.colour, self.rect)
class Gui(object):
def __init__(self):
self.hpbar_bg = GuiObject(( 0, 0, 150, 600), (Colour.BLUE))
self.enemy_hpbar = GuiObject((10, 10, 200, 400), (Colour.WHITE))
self.enabled = True
def render(self, screen):
#render my gui in the order i want
if self.enabled:
self.hpbar_bg.render(screen)
self.enemy_hpbar.render(screen)
def main():
############################################################################
# Initialise
pygame.init()
screen = pygame.display.set_mode((800, 600))
gui = Gui()
#uncomment to get the enabled/disabled behavior
#gui.hpbar_bg.enabled = False
#or disable the whole gui
#gui.enabled = False
############################################################################
# Main loop
while True:
########################################################################
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
########################################################################
# Render
screen.fill((0, 0, 0))
# Render GUI
gui.render(screen)
pygame.display.flip()
if __name__ == "__main__":
main()

How to display text in pygame? [duplicate]

This question already has answers here:
pygame - How to display text with font & color?
(7 answers)
Closed 2 years ago.
I can't figure out to display text in pygame.
I know I can't use print like in regular Python IDLE but I don't know how.
import pygame, sys
from pygame.locals import *
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = ( 255, 0, 0)
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
DISPLAYSURF = pygame.display.set_mode((400, 300))
pygame.display.set_caption('P.Earth')
while 1: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.display.update()
import time
direction = ''
print('Welcome to Earth')
pygame.draw.rect(screen, RED, [55,500,10,5], 0)
time.sleep(1)
This is only the beginning part of the whole program.
If there is a format that will allow me to show the text I type in the pygame window that'd be great. So instead of using print I would use something else. But I don't know what that something else is.
When I run my program in pygame it doesn't show anything.
I want the program to run in the pygame window instead of it just running in idle.
You can create a surface with text on it. For this take a look at this short example:
pygame.font.init() # you have to call this at the start,
# if you want to use this module.
my_font = pygame.font.SysFont('Comic Sans MS', 30)
This creates a new object on which you can call the render method.
text_surface = my_font.render('Some Text', False, (0, 0, 0))
This creates a new surface with text already drawn onto it.
At the end you can just blit the text surface onto your main screen.
screen.blit(text_surface, (0,0))
Bear in mind, that every time the text changes, you have to recreate the surface again, to see the new text.
There's also the pygame.freetype module which is more modern, works with more fonts and offers additional functionality.
Create a font object with pygame.freetype.SysFont() or pygame.freetype.Font if the font is inside of your game directory.
You can render the text either with the render method similarly to the old pygame.font.Font.render or directly onto the target surface with render_to.
import pygame
import pygame.freetype # Import the freetype module.
pygame.init()
screen = pygame.display.set_mode((800, 600))
GAME_FONT = pygame.freetype.Font("your_font.ttf", 24)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((255,255,255))
# You can use `render` and then blit the text surface ...
text_surface, rect = GAME_FONT.render("Hello World!", (0, 0, 0))
screen.blit(text_surface, (40, 250))
# or just `render_to` the target surface.
GAME_FONT.render_to(screen, (40, 350), "Hello World!", (0, 0, 0))
pygame.display.flip()
pygame.quit()
When displaying I sometimes make a new file called Funk. This will have the font, size etc. This is the code for the class:
import pygame
def text_to_screen(screen, text, x, y, size = 50,
color = (200, 000, 000), font_type = 'data/fonts/orecrusherexpand.ttf'):
try:
text = str(text)
font = pygame.font.Font(font_type, size)
text = font.render(text, True, color)
screen.blit(text, (x, y))
except Exception, e:
print 'Font Error, saw it coming'
raise e
Then when that has been imported when I want to display text taht updates E.G score I do:
Funk.text_to_screen(screen, 'Text {0}'.format(score), xpos, ypos)
If it is just normal text that isn't being updated:
Funk.text_to_screen(screen, 'Text', xpos, ypos)
You may notice {0} on the first example. That is because when .format(whatever) is used that is what will be updated. If you have something like Score then target score you'd do {0} for score then {1} for target score then .format(score, targetscore)
This is slighly more OS independent way:
# do this init somewhere
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
font = pygame.font.Font(pygame.font.get_default_font(), 36)
# now print the text
text_surface = font.render('Hello world', antialias=True, color=(0, 0, 0))
screen.blit(text_surface, dest=(0,0))

Categories