I have pygame based video player, it has berkelium browser used for GUI,
under that are VLC libraries for playing streams. I did not make the player, but I would
like to add a "resize" option, which is not currently present.
The application is made for OS X.
On initialization of the player, pygame.set_mode(screensize,OPENGL|DOUBLEBUF|RESIZABLE) is called, problem is when I resize the window more than the screen size, these parts are not visible(shown bugged), if I try pygame.set_mode again, it causes the app to crash because of dependencies (browser and VLC).
So I decided to initialize screen using:
pygame.set_mode(screenresolution, OPENGL|DOUBLEBUF|RESIZABLE)
Which should set it to the max and then switch back to original, smaller resolution (like resize with the mouse).
How to do that? how to simulate the RESIZABLE flag and mouse move action?
The player works nice resizing to smaller sizes, it is only bigger sizes that are a problem.
class InputAndDisplay:
def init(self, fullscreen=False):
global pygame, sys
# if 'darwin' in sys.platform:
# import sys
# sys.argv = ['Core.py']
# import pygame.macosx
# pygame.macosx.init()
pygame.init()
global screenSize
self.screenSize = screenSize
if fullscreen:
try: self.screenSize = pygame.display.list_modes()[0]
except Exception, e: print e
flags = OPENGL|DOUBLEBUF|FULLSCREEN
else:
flags = RESIZABLE|OPENGL|DOUBLEBUF
print 'screenSize:', self.screenSize
try:
povrsina = pygame.display.set_mode(self.screenSize, flags)
except Exception, e:
print e
self.screenSize = screenSize
povrsina = pygame.display.set_mode(self.screenSize, RESIZABLE|OPENGL|DOUBLEBUF)
pygame.display.set_caption('NetTVBox-WebPlayer')
pygame.mouse.set_pos(list(self.screenSize))
if 'darwin' not in sys.platform:
pygame.mouse.set_visible(False)
#pygame.key.set_repeat(300, 100)
if 'darwin' not in sys.platform:
pygame.mixer.quit()
if 'linux' in sys.platform: # try to turn off vsyncing
import ctypes
libgl = ctypes.cdll.LoadLibrary('libGL.so.1')
proc = libgl.glXGetProcAddressARB('glXSwapIntervalMESA')
_glXSwapIntervalMESA = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(proc)
_glXSwapIntervalMESA(0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
#gluPerspective(45.0, 640/480.0, 0.1, 100.0)
glOrtho(-0.5, 0.5, -0.5, 0.5, -5, 5)
#glTranslatef(0.0, 0.0, -3.0)
#glRotatef(25, 1, 0, 0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_TEXTURE_2D)
glShadeModel(GL_FLAT)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
self.textures = glGenTextures(2)
self.threeDmode = MODE_3D_OFF
that's init in inputAndDisplay.py
And main file is Core.py which calls it, and a lot of other stuff as well. Thats why I didnt put all the code here, there is a lot of it and not all important
Here is part of Core.py:
input_and_display = InputAndDisplay()
input_and_display.init(self.fullscreen)
rc = RemoteControl()
rc.init()
media = Media()
if 1: # !
media.config = {
'buffering': state.mediaplayer_buffering,
'contrast': state.mediaplayer_contrast,
'saturation': state.mediaplayer_saturation,
}
media.init()
browser = Browser()
browser.init()
Thanks in advance for the help
It sounds like you're missing the VIDEORESIZE event to detect resizing.
( See related events : VIDEOEXPOSE, ACTIVEEVENT http://www.pygame.org/docs/ref/event.html )
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
" Then the display mode is set, several events are placed on the pygame event queue. pygame.QUIT is sent when the user has requested the program to shutdown. The window will receive pygame.ACTIVEEVENT events as the display gains and loses input focus. If the display is set with the pygame.RESIZABLE flag, pygame.VIDEORESIZE events will be sent when the user adjusts the window dimensions. Hardware displays that draw direct to the screen will get pygame.VIDEOEXPOSE events when portions of the window must be redrawn. "
Related
I'm making this space invaders type game with pygame and I have this issue where, enemies keep spawning while the time is stopped. I need a fix that removes those enemies from the window ( I use .blit to display my surfaces) right after the time is started again.
E.G:
def draw_on_window(enemy):
window.blit(enemy)
def main():
# Command that clears the window of "Enemy surfaces" somehow?? :
# window.remove(enemy) ??
run = True
while run:
draw_on_window(blue_enemy)
#game
In pygame you don't remove something from a surface like the window. window.blit(image) draws an image to the window surface.
To clear everything you have to fill the window black.
In pygame you do the following things your main loop normally:
fill the screen black window.fill((0, 0, 0))
draw everything again
handle all events (eg. QUIT, MOUSEBUTTONDOWN...)
let the clock tick at a specified frame rate
enemy_coords = [(5, 9), (3, 4)] # just an example
clock = pygame.time.Clock()
max_fps = 60
while run:
window.fill((0, 0, 0)) # fill the window with black
for coord in enemy_coords:
window.blit(enemy_image, coord)
do_events...
pygame.display.update()
clock.tick(max_fps)
All you need to do is manage the enemies in a list and remove the enemies from the list (see How to remove items from a list while iterating?). Draw only the enemies that are in the list.
e.g.: represent the enemies by pygame.Rect objects and remove them when they are out of the window:
def draw_on_window(enemies):
for enemy_rect in enemies:
window.blit(enemy_image, enemy_rect)
def main():
enemies = []
enemies.append(pygame.Rect(x1, y1, w, h))
enemies.append(pygame.Rect(x2, y2, w, h))
run = True
while run:
# [...]
for enemy in enemies[:]:
if not enemies.colliderect(window.get_rect())
enemies.remove(enemy)
# [...]
draw_on_window(enemies)
pygame.dispaly.update()
You can remove all items from a list with the clear() method:
enemies.clear()
Hello I am tring to implement simple image widget with zoom to mouse position. I combined the example at Zooming in/out on a mouser point ? and https://doc.qt.io/qt-5/qtwidgets-widgets-imageviewer-example.html. However the image do not scale as expected and the scale bars do not update appropriately either. Here is my code:
import sys
from PySide6 import QtWidgets
from PySide6.QtCore import Qt
from PIL.ImageQt import ImageQt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import QDialog, QVBoxLayout, QLabel, QScrollArea
class MyScrollArea(QScrollArea):
def __init__(self, imageWidget):
# initialize widget
super().__init__()
self.setWidget(imageWidget)
self.myImageWidget = imageWidget
self.oldScale = 1
self.newScale = 1
def wheelEvent(self, event) -> None:
if event.angleDelta().y() < 0:
# zoom out
self.newScale = 0.8
else:
# zoom in
self.newScale = 1.25
# compute scrollbar positions
scrollBarPosHorizontal = self.horizontalScrollBar().value()
scrollBarPosVertical = self.verticalScrollBar().value()
deltaToPos = (event.position() / self.oldScale) - (self.myImageWidget.pos() / self.oldScale)
delta = deltaToPos * self.newScale - deltaToPos * self.oldScale
# resize image
self.myImageWidget.resize(self.myImageWidget.size() * self.newScale)
# set scrollbars
self.horizontalScrollBar().setValue(scrollBarPosHorizontal+delta.x())
self.verticalScrollBar().setValue(scrollBarPosVertical+delta.y())
# save old scale
self.oldScale = self.newScale
class ImageViewer(QDialog):
def __init__(self, img):
# initialize widget
super().__init__()
self.setWindowTitle('Zoom example')
self.imageWidget = QLabel()
self.imageWidget.installEventFilter(self)
self.imageWidget.setAlignment(Qt.AlignCenter)
self.pixmap = QPixmap.fromImage(img)
self.imageWidget.setPixmap(self.pixmap)
# create scroll area
self.scrollArea = MyScrollArea(self.imageWidget)
# insert to layout
self.layout = QVBoxLayout()
self.layout.addWidget(self.scrollArea)
self.setLayout(self.layout)
if __name__ == '__main__':
# prepare app
app = QtWidgets.QApplication(sys.argv)
# prepare image
image = ImageQt("test.png")
# create viewer widget
MyWidget = ImageViewer(image)
MyWidget.show()
# close app
sys.exit(app.exec())
The image do not scale to mouse point at all. What am I doing wrong?
The main problem is that by default the pixmap is not resized when QLabel is resized, so setScaledContents(True) must be used.
Note that the algorithm used for the zoom and translation doesn't work very well, as it doesn't consider the change in the range of the scroll bars correctly.
I propose an alternate version that actually zooms on the mouse similarly to what happens in common image viewers/editors and map viewers. The trick is to map the mouse position to the label, and get the delta based on the scaled position:
class MyScrollArea(QScrollArea):
def __init__(self, imageWidget):
# ...
imageWidget.setScaledContents(True)
# ...
def wheelEvent(self, event) -> None:
if event.angleDelta().y() < 0:
# zoom out
self.newScale = 0.8
else:
# zoom in
self.newScale = 1.25
widgetPos = self.myImageWidget.mapFrom(self, event.position())
# resize image
self.myImageWidget.resize(self.myImageWidget.size() * self.newScale)
delta = widgetPos * self.newScale - widgetPos
self.horizontalScrollBar().setValue(
self.horizontalScrollBar().value() + delta.x())
self.verticalScrollBar().setValue(
self.verticalScrollBar().value() + delta.y())
self.oldScale = self.newScale
Note that QLabel is not well suited for such purposes (especially for big images and high zoom values). I strongly suggest you to consider switching to the Graphics View Framework.
When i was making background with screen.fill, my code was checking collision of hero with a lot of projectiles - and program still wasn't lagging. But when i decided to add drawn background (3600x1200 pix) as sprite, and fps fell down to about 20 fps. I removed all projectiles, but fps is still enormously low. Such big background was chosen for moving it, instead of moving main hero. Here is my code and the problematic line displaying the background (everything works fine without it).
#import modules
import pygame as pg
from hero import Hero
#self-made classes
from obstruction import Obstruction
from setting import Settings
import gf
from time import sleep
**from back_ground import Background**
from command_block import Command_Line
#main function
def run_game():
#pygame activation
pg.init()
#window settings
settings = Settings()
screen = pg.display.set_mode((settings.screen_width,settings.screen_height))
pg.display.set_caption(settings.caption)
hero = Hero(0, 0, "Right", 1/240, pg.image.load('images/hero/hero1.png'), 128, 16, 15, 0.08, 0.2, settings,27)
bg = Background('images/sky.png', [0,0])
cl = Command_Line(hero)
#class creating
projectiles = []
#here was some projectile creating
#variables initialization etc.
work=True
myfont = pg.font.SysFont('TimesNewRoman',int(settings.screen_width*0.025))
#main loop
while work:
sleep()
hero.is_running = False
hero.idle = True
gf.check_events(hero, projectiles, settings, cl)
gf.jump(hero, projectiles)
#updating hero rect due to coordinate changing and hero image due to direction changing
hero.update_rect()
hero.orientation()
#screen filling with backgroung color
screen.fill([255, 255, 255])
screen.blit(bg.image, bg.rect)
#displaying projectiles(walls,floor,etc.)
for projectile in projectiles:
projectile.display(screen)
#displaying hero image and all his atributes
hero.display(screen, myfont)
gf.command_block_draw(settings,myfont,screen,cl)
#test string for displaying problematic variables
gf.test_string_draw(settings,myfont,hero,screen)
#display updating
pg.display.flip()
#quit
pg.quit()
#running game
run_game()
Line:
screen.blit(bg.image, bg.rect)
BackGround class:
import pygame as pg
class Background(pg.sprite.Sprite):
def __init__(self, image_file, location):
pg.sprite.Sprite.__init__(self)
self.image = pg.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
Make sure to convert() the image.
Changing this one line of code should increase your performance substantially.
It processes the Surface into a format pygame likes up front, speeding up all the consequent blits.
self.image = pg.image.load(image_file).convert()
I am working on this project to move a sprite, but I can't seem to figure out how to move a sprite to the right as well as move it downwards. Any thoughts?
Here is my program:
import pygame
import time
import sys
pygame.init()
# Set up window
screen = pygame.display.set_mode((320, 240))
# Load an image
rocket = pygame.image.load("rocket.png")
rocketrect = rocket.get_rect()
x_coord = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
screen.fill((0,0,0))
screen.blit(rocket, rocketrect)
pygame.display.flip()
x_coord += 1
rocketrect.centerx = x_coord
In your method of mving the sprite, you change the coordinatses (x) and then assign it to the centerx of the images rectangle. If you want to keep this kind of method (changing and assigning), and also move the image down, you will need to give a y value. For example
# Define y variable
y_coord = 0
# Your code
…
y_coords += 1
rocketrect.centery = y_coord
This works similarly to how you moved your x_coords, but in total, the program is a bit basic and is not how programmers (or at least me) usually code. Another person might used a tuple for the location, along with making a rocket class. There are also some other ways to move the sprite, such as the .move() or .move_ip() that I would suggest. But it's up to you.
I have the following function that processes a buffer object containing a video frame supplied by GStreamer
def __handle_videoframe(self, appsink):
"""
Callback method for handling a video frame
Arguments:
appsink -- the sink to which gst supplies the frame (not used)
"""
buffer = self._videosink.emit('pull-buffer')
(w,h) = buffer.get_caps[0]["width"],buffer.get_caps[0]["height"]
reqBufferLength = w * h * 3 #Required buffer lenght for a raw rgb image of these dimensions
print "Buffer length: " + str(len(buffer.data))
print "Needed length: " + str(reqBufferLength)
img = pygame.image.frombuffer(buffer.data, self.vidsize, "RGB")
self.screen.blit(img, self.vidPos)
pygame.display.flip()
When running this code however, pygame crashes because the supplied buffer is larger than required and this size needs to match. I know this is probably caused by a faulty encoding of the movie that is played (as most movies do run fine), but is there a way to account for this contingency? Is there a way to resize the buffer on the go to a correct size? I have tried to just cut-off the tail of the buffer at the required length and then the movie does play, but the output is corrupted.
ok, a better solution was to use bufferproxies. They are less fuzzy about the length of the buffer.
img_sfc = pygame.Surface(video_dimensions, pygame.SWSURFACE, 24, (255, 65280, 16711680, 0))
img_buffer = img_sfc.get_buffer()
Then for each new frame:
img_buffer.write(buffer.data, 0)
pygame.display.get_surface().blit(img_sfc.copy(), vid_pos)
And voila, even incorrectly formatted buffers appear on screen without problems