Related
I have a question about using pyqt5 and pygame. I have already made a pygame script and a pyqt5 script. The problem is that when I want to make pygame excute the game, it shows a ranking board in pyqt5 and plays game by a pygame script.
This is my pyqt UI code:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QMovie
import rankingUI
import sys
import main
import pickle
import subprocess
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setFixedSize(800,400)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
# create label
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.move(0,0)
# start button
self.button = QtWidgets.QPushButton(self.centralwidget)
self.button.setGeometry(320,300,150,100)
self.button.setStyleSheet("border-image:url(./assets/ui/start_btn.png); border:0px;")
self.button.clicked.connect(self.game_start)
# title
self.title = QtWidgets.QLabel(self.centralwidget)
self.title.setGeometry(250, 10, 300, 100)
self.title.setStyleSheet("border-image:url(./assets/ui/dinotitle.png); border:0px;")
# input nick
self.nick_inp = QtWidgets.QLineEdit("ENTER YOUR NICK",self.centralwidget)
self.nick_inp.setAlignment(QtCore.Qt.AlignCenter)
self.nick_inp.setGeometry(320,290, 150 ,20)
#ranking
self.ranking_btn = QtWidgets.QPushButton(self.centralwidget)
self.ranking_btn.setStyleSheet("border-image:url(./assets/ui/rank_btn.png); border:0px;")
self.ranking_btn.setGeometry(730, 325, 50, 50)
self.ranking_btn.clicked.connect(self.popup_ranking)
# add popup
self.add_dia = QtWidgets.QDialog()
self.rank_dia = QtWidgets.QDialog()
# add label to main window
MainWindow.setCentralWidget(self.centralwidget)
# set qmovie as label
self.movie = QMovie("assets/ui/dinogif.gif")
self.label.setMovie(self.movie)
self.movie.start()
def game_start(self):
player_nick = self.nick_inp.text()
if(len(player_nick)==0):
self.nick_inp.setText("ENTER YOUR NICK")
return
main.game_start(player_nick)
def popup_ranking(self):
# ui init
self.rank_dia.setWindowModality(QtCore.Qt.ApplicationModal)
self.rank_dia.setWindowTitle("RANKING")
self.rank_dia.setFixedSize(500,330)
rank_label = QtWidgets.QLabel("RANKKING")
rank_label.setAlignment(QtCore.Qt.AlignCenter)
rank_label.setFont(QtGui.QFont('Arial', 30))
output = QtWidgets.QTextEdit()
output.setFont(QtGui.QFont('Ubuntu',15))
window = QtWidgets.QVBoxLayout()
window.addWidget(rank_label)
window.addWidget(output)
# read data
rank_list = []
ranking_dat = open("ranking.dat", 'rb')
try:
rank_list = pickle.load(ranking_dat)
except:
pass
ranking_dat.close()
# write data
strFormat = '%-18s%-18s%-18s\n'
strOut = strFormat % ('RANK', 'SCORE', 'NICK')
rank_num = 1
strFormat = '%-20s%-20s%-20s\n'
for x in sorted(rank_list, key=lambda s: s["Score"], reverse=True):
tmp = []
tmp.append(str(rank_num))
rank_num += 1
for y in x:
tmp.append(str(x[y]))
strOut += strFormat % (tmp[0], tmp[2], tmp[1])
if rank_num == 10:
break
output.setText(strOut)
self.rank_dia.setLayout(window)
self.rank_dia.show()
# def score_reg(self):
# # popup UI setting
# self.add_dia.setWindowTitle("score registration")
# self.add_dia.setWindowModality(QtCore.Qt.ApplicationModal)
# self.add_dia.setFixedSize(300,70)
#
# # add widget
# nick_label = QtWidgets.QLabel("Insert Nickname :")
# self.nick_input = QtWidgets.QLineEdit()
# score_label = QtWidgets.QLabel("Your Score : ")
# self.score_input = QtWidgets.QLabel("333")
# reg_btn = QtWidgets.QPushButton("register")
# reg_btn.clicked.connect(self.register)
#
# h_box1 = QtWidgets.QHBoxLayout()
# h_box1.addWidget(nick_label)
# h_box1.addWidget(self.nick_input)
#
# h_box2 = QtWidgets.QHBoxLayout()
# h_box2.addWidget(score_label)
# h_box2.addWidget(self.score_input)
# h_box2.addStretch()
# h_box2.addWidget(reg_btn)
#
# v_box = QtWidgets.QVBoxLayout()
# v_box.addLayout(h_box1)
# v_box.addLayout(h_box2)
#
# self.add_dia.setLayout(v_box)
# self.add_dia.show()
#
# def register(self):
# print(self.nick_input.text())
# print(self.score_input.text())
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
This is the pygame code:
import pygame as pyg
import os
import random
import sys
import pickle
import pygame.time
import ui
nickname = ...
# 화면 크기
SCREEN_HEIGHT = 600
SCREEN_WIDTH = 1600
SCREEN = ...
# 달리는 모션 (running1, running2)
RUNNING_MOTIONS = [pyg.image.load(os.path.join("assets/Dino", "DinoRun1.png")),
pyg.image.load(os.path.join("assets/Dino", "DinoRun2.png"))]
# 뛰는 모션, 숙이는 모션 (stooping1, stooping2)
JUMPING_MOTION = pyg.image.load(os.path.join("assets/Dino", "DinoJump.png"))
STOOPING_MOTIONS = [pyg.image.load(os.path.join("assets/Dino", "DinoStoop1.png")),
pyg.image.load(os.path.join("assets/Dino", "DinoStoop2.png"))]
# 선인장
SMALL_CACTUS_IMG = [pyg.image.load(os.path.join("assets/Cactus", "SmallCactus1.png")),
pyg.image.load(os.path.join("assets/Cactus", "SmallCactus2.png")),
pyg.image.load(os.path.join("assets/Cactus", "SmallCactus3.png"))]
LARGE_CACTUS_IMG = [pyg.image.load(os.path.join("assets/Cactus", "LargeCactus1.png")),
pyg.image.load(os.path.join("assets/Cactus", "LargeCactus2.png")),
pyg.image.load(os.path.join("assets/Cactus", "LargeCactus3.png"))]
# 새 모션
BIRD_MOTIONS = [pyg.image.load(os.path.join("assets/Bird", "Bird1.png")),
pyg.image.load(os.path.join("assets/Bird", "Bird2.png"))]
# 기타 (구름, 바닥) -> 하트 추가 예정
CLOUD = pyg.image.load(os.path.join("assets/Other", "Cloud.png"))
GROUND = pyg.image.load(os.path.join("assets/Other", "Track.png"))
global points
class Dinosaur():
X_Dino = 80
Y_Dino = 310
Y_DinoStoop = 340
Jump_height = 8.5
hitScale = 0.5
def __init__(self):
self.stoop_img = STOOPING_MOTIONS
self.run_img = RUNNING_MOTIONS
self.jump_img = JUMPING_MOTION
self.dino_stoop = False
self.dino_run = True
self.dino_jump = False
self.step_index = 0 # 움직임 인덱스
self.jump_height = self.Jump_height
self.image = self.run_img[0] # 0, 1 인덱스 반복하여 애니메이션 구현
self.dino_hitbox = self.image.get_rect() # 공룡 히트박스 설정
self.dino_hitbox.x = self.X_Dino * self.hitScale
self.dino_hitbox.y = self.Y_Dino * self.hitScale
def update(self, Input):
if self.dino_stoop:
self.stoop()
if self.dino_run:
self.run()
if self.dino_jump:
self.jump()
if self.step_index >= 10:
self.step_index = 0
# 공룡 동작
# 점프
if Input[pyg.K_UP] and not self.dino_jump:
self.dino_stoop = False
self.dino_run = False
self.dino_jump = True
# 숙이기
elif Input[pyg.K_DOWN] and not self.dino_jump:
self.dino_stoop = True
self.dino_run = False
self.dino_jump = False
# 달리기
elif not (self.dino_jump or Input[pyg.K_DOWN]):
self.dino_stoop = False
self.dino_run = True
self.dino_jump = False
def stoop(self):
self.image = self.stoop_img[self.step_index // 5]
self.dino_hitbox = self.image.get_rect()
self.dino_hitbox.x = self.X_Dino
self.dino_hitbox.y = self.Y_DinoStoop
self.step_index += 1
def run(self):
self.image = self.run_img[self.step_index // 5] # 5로 해야 속도 맞음
self.dino_hitbox = self.image.get_rect()
self.dino_hitbox.x = self.X_Dino
self.dino_hitbox.y = self.Y_Dino
self.step_index += 1
def jump(self):
self.image = self.jump_img
if self.dino_jump:
self.dino_hitbox.y -= self.jump_height * 4
self.jump_height -= 0.8
if self.jump_height < - self.Jump_height:
self.dino_jump = False
self.jump_height = self.Jump_height
def draw(self, SCREEN):
SCREEN.blit(self.image, (self.dino_hitbox.x, self.dino_hitbox.y))
class Cloud():
def __init__(self):
self.x = SCREEN_WIDTH + random.randint(800, 1000)
self.y = random.randint(50, 100)
self.image = CLOUD
self.width = self.image.get_width()
def update(self):
self.x -= game_speed
if self.x < - self.width:
self.x = SCREEN_WIDTH + random.randint(2600, 3000)
self.y = random.randint(50, 100)
def draw(self, SCREEN):
SCREEN.blit(self.image, (self.x, self.y))
class Obstacle():
def __init__(self, image, type):
self.image = image
self.type = type
self.rect = self.image[self.type].get_rect()
self.rect.x = SCREEN_WIDTH
def update(self):
self.rect.x -= game_speed
if self.rect.x < - self.rect.width:
obstacles.pop()
def draw(self, SCREEN):
SCREEN.blit(self.image[self.type], self.rect)
class SmallCactus(Obstacle):
def __init__(self, image):
self.type = random.randint(0, 2)
super().__init__(image, self.type)
self.rect.y = 325
class LargeCactus(Obstacle):
def __init__(self, image):
self.type = random.randint(0, 2)
super().__init__(image, self.type)
self.rect.y = 300
class Bird(Obstacle):
def __init__(self, image):
self.type = 0
super().__init__(image, self.type)
self.rect.y = 250
self.index = 0
def draw(self, SCREEN):
if self.index >= 9:
self.index = 0
SCREEN.blit(self.image[self.index // 5], self.rect)
self.index += 1
def main():
global game_speed, x_ground, y_ground, points, obstacles
run = True
clock = pyg.time.Clock()
cloud = Cloud()
player = Dinosaur()
game_speed = 14
x_ground = 0
y_ground = 380
points = 0
font = pyg.font.Font('freesansbold.ttf', 20)
obstacles = []
death_cnt = 0
def score():
global points, game_speed
points += 1
if points % 100 == 0:
game_speed += 1
text = font.render("points: " + str(points), True, (0,0,0))
text_rect = text.get_rect()
text_rect.center = (1000, 40)
SCREEN.blit(text, text_rect)
def ground():
global x_ground, y_ground
image_width = GROUND.get_width()
SCREEN.blit(GROUND, (x_ground, y_ground))
SCREEN.blit(GROUND, (image_width + x_ground, y_ground))
if x_ground <= - image_width:
SCREEN.blit(GROUND, (image_width + x_ground, y_ground))
x_ground = 0
x_ground -= game_speed
while run:
for pyEvent in pyg.event.get():
if pyEvent.type == pyg.QUIT:
sys.exit()
SCREEN.fill((255,255,255))
userInput = pyg.key.get_pressed()
player.draw(SCREEN)
player.update(userInput)
if len(obstacles) == 0:
if random.randint(0, 2) == 0:
obstacles.append(SmallCactus(SMALL_CACTUS_IMG))
elif random.randint(0, 2) == 1:
obstacles.append(LargeCactus(LARGE_CACTUS_IMG))
elif random.randint(0, 2) == 2:
obstacles.append(Bird(BIRD_MOTIONS))
for ob in obstacles:
ob.draw(SCREEN)
ob.update()
if player.dino_hitbox.colliderect(ob.rect):
pyg.time.delay(500)
death_cnt += 1
menu(death_cnt)
ground()
cloud.draw(SCREEN)
cloud.update()
score()
clock.tick(30)
pyg.display.update()
def menu(death_cnt):
global points
run = True
if death_cnt == 0:
points = 0
while run:
update(points)
SCREEN.fill((255,255,255))
font = pyg.font.Font('freesansbold.ttf', 30) # 폰트 적용 오류......
if death_cnt == 0:
text = font.render("Press any key to Start", True, (0,0,0)) # 한글 "시작하기" 로 변경 예정
text1 = font.render("DinoSaurGame", True, (0,0,0)) # "공룡게임"으로 변경 예정
elif death_cnt > 0:
text = font.render("Press any key to Restart", True, (0,0,0))
score = font.render("Your Score : " + str(points), True, (0,0,0))
scoreRect = score.get_rect()
scoreRect.center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 50)
SCREEN.blit(score, scoreRect)
textRect = text.get_rect()
textRect.center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
SCREEN.blit(text, textRect)
SCREEN.blit(RUNNING_MOTIONS[0], (SCREEN_WIDTH // 2 - 20, SCREEN_HEIGHT // 2 - 140))
pyg.display.update()
for pyEvent in pyg.event.get():
if pyEvent.type == pyg.QUIT:
sys.exit()
if pyEvent.type == pyg.KEYDOWN:
main()
def update(score):
pass
def game_start(nick):
pyg.init()
global SCREEN
global nickname
nickname = nick
SCREEN = pyg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
menu(death_cnt=0)
When I quit the pygame window, pyqt5 quits too. How can I only quit the pygame window?
Do not mix frameworks, mixing frameworks always means some kind of undefined behavior. The frameworks may interact poorly or completely conflict with one another. Getting it to work on your system doesn't mean it will work on another system or with a different version of any of the frameworks.
If you use Qt, then I suggest to develop the game with Qt as well (see Qt Based Games).
In ursina, How can I save the render frames as a sequence of images or a video? Ursina cheat sheet has nothing on this.
You can see VideoRecorder :
from ursina import *
import os, shutil
import numpy as np
# import imageio # gets imported in convert_to_gif
# from panda3d.core import PNMImage
class VideoRecorder(Entity):
def __init__(self, duration=5, name='untitled_video', **kwargs):
super().__init__()
self.recording = False
self.file_path = Path(application.asset_folder) / 'video_temp'
self.i = 0
self.duration = duration
self.fps = 30
self.video_name = name
self.t = 0
for key, value in kwargs.items():
setattr(self, key, value)
self.max_frames = int(self.duration * self.fps)
self.frames = []
def start_recording(self):
print('start recording,', self.duration, self.file_path)
window.fps_counter.enabled = False
window.exit_button.visible = False
self.frames = []
self.max_frames = self.duration * self.fps
if not self.file_path.exists():
self.file_path.mkdir()
base.movie(namePrefix=f'\\video_temp\\{self.video_name}', duration=2.0, fps=30, format='png', sd=4)
self.recording = True
invoke(self.stop_recording, delay=self.duration)
def stop_recording(self):
self.recording = False
window.fps_counter.enabled = True
window.exit_button.visible = True
print('stop recording')
self.convert_to_gif()
def update(self):
if not self.recording:
return
self.t += time.dt
if self.t >= 1/30:
base.screenshot(
namePrefix = '\\video_temp\\' + self.video_name + '_' + str(self.i).zfill(4) + '.png',
defaultFilename = 0,
)
self.t = 0
# # self.frames.append(self.renderToPNM())
# image = base.win.getScreenshot()
# data = image.getRamImageAs("RGB").getData()
# # from PIL import Image
# # image = Image.fromarray(data)
# # img = data.convert("RGBA")
# data = np.array(data)
#
# # image = deepcopy(camera.render_texture)
# self.frames.append(data)
self.i += 1
# store screenshot in memory
# def renderToPNM(self):
# base.graphicsEngine.renderFrame()
# if hasattr(camera, 'render_texure'):
# return copy(camera.render_texure)
# # image = PNMImage()
# # dr = base.camNode.getDisplayRegion(0)
# # dr.getScreenshot(image)
# # win.setupRenderTexture()
# return None
def convert_to_gif(self):
import imageio
images = []
if not os.path.exists(self.file_path):
return
for filename in os.listdir(self.file_path):
images.append(imageio.imread(self.file_path/filename))
imageio.mimsave(Path(f'{self.file_path.parent}/{self.video_name}.gif'), images)
shutil.rmtree(self.file_path) # delete temp folder
print('saved gif to:', Path(f'{self.file_path.parent}/{self.video_name}.gif'))
class VideoRecorderUI(WindowPanel):
def __init__(self, **kwargs):
self.duration_label = Text('duration:')
self.duration_field = InputField(default_value='5')
self.fps_label = Text('fps:')
self.fps_field = InputField(default_value='30')
self.name_label = Text('name:')
self.name_field = InputField(default_value='untitled_video')
self.start_button = Button(text='Start Recording [Shift+F12]', color=color.azure, on_click=self.start_recording)
super().__init__(
title='Video Recorder [F12]',
content=(
self.duration_label,
self.duration_field,
self.fps_label,
self.fps_field,
self.name_label,
self.name_field,
Space(1),
self.start_button,
),
)
self.y = .5
self.scale *= .75
self.visible = False
def input(self, key):
if key == 'f12':
self.visible = not self.visible
if held_keys['shift'] and key == 'f12':
self.start_button.on_click()
def start_recording(self):
print(self.name_field)
if self.name_field.text == '':
self.name_field.blink(color.color(0,1,1,.5), .5)
print('enter name')
return
# self.start_button.color=color.lime
self.visible = False
application.video_recorder.duration = float(self.duration_field.text)
application.video_recorder.video_name = self.name_field.text
application.video_recorder.frame_skip = 60 // int(self.fps_field.text)
application.video_recorder.recording = True
if __name__ == '__main__':
app = Ursina()
# window.size = (1600/3,900/3)
# cube = primitives.RedCube()
# cube.animate_x(5, duration=5, curve=curve.linear)
# cube.animate_x(0, duration=5, curve=curve.linear, delay=5)
# vr = VideoRecorder()
# invoke(setattr, vr, 'recording', True, delay=1)
# invoke(os._exit, 0, delay=6)
# vr.recording = True
window.size *= .5
from ursina.prefabs.first_person_controller import FirstPersonController
from ursina.shaders import lit_with_shadows_shader
random.seed(0)
Entity.default_shader = lit_with_shadows_shader
ground = Entity(model='plane', collider='box', scale=64, texture='grass', texture_scale=(4,4))
editor_camera = EditorCamera(enabled=False, ignore_paused=True)
player = FirstPersonController(model='cube', z=-10, color=color.orange, origin_y=-.5, speed=8)
player.collider = BoxCollider(player, Vec3(0,1,0), Vec3(1,2,1))
gun = Entity(model='cube', parent=camera, position=(.5,-.25,.25), scale=(.3,.2,1), origin_z=-.5, color=color.red, on_cooldown=False)
shootables_parent = Entity()
mouse.traverse_target = shootables_parent
for i in range(16):
Entity(model='cube', origin_y=-.5, scale=2, texture='brick', texture_scale=(1,2),
x=random.uniform(-8,8),
z=random.uniform(-8,8) + 8,
collider='box',
scale_y = random.uniform(2,3),
color=color.hsv(0, 0, random.uniform(.9, 1))
)
sun = DirectionalLight()
sun.look_at(Vec3(1,-1,-1))
Sky()
vr = VideoRecorder(duration=10)
def input(key):
if key == '5':
vr.start_recording()
if key == '6':
vr.stop_recording()
app.run()
This code will convert the recording to mp4 video:
from ursina import *
import os, shutil
import numpy as np
# import imageio # gets imported in convert_to_gif
# from panda3d.core import PNMImage
class VideoRecorder(Entity):
def __init__(self, duration=5, name='untitled_video', **kwargs):
super().__init__()
self.recording = False
self.file_path = Path(application.asset_folder) / 'video_temp'
self.i = 0
self.duration = duration
self.fps = 30
self.video_name = name
self.t = 0
for key, value in kwargs.items():
setattr(self, key, value)
self.max_frames = int(self.duration * self.fps)
self.frames = []
def start_recording(self):
print('start recording,', self.duration, self.file_path)
window.fps_counter.enabled = False
window.exit_button.visible = False
self.frames = []
self.max_frames = self.duration * self.fps
if not self.file_path.exists():
self.file_path.mkdir()
base.movie(namePrefix=f'\\video_temp\\{self.video_name}', duration=2.0, fps=30, format='png', sd=4)
self.recording = True
invoke(self.stop_recording, delay=self.duration)
def stop_recording(self):
self.recording = False
window.fps_counter.enabled = True
window.exit_button.visible = True
print('stop recording')
# self.convert_to_gif()
self.convert_to_vid()
def update(self):
if not self.recording:
return
self.t += time.dt
if self.t >= 1/30:
base.screenshot(
namePrefix = '\\video_temp\\' + self.video_name + '_' + str(self.i).zfill(4) + '.png',
defaultFilename = 0,
)
self.t = 0
self.i += 1
def convert_to_gif(self):
import imageio
images = []
if not os.path.exists(self.file_path):
return
for filename in os.listdir(self.file_path):
images.append(imageio.imread(self.file_path/filename))
imageio.mimsave(Path(f'{self.file_path.parent}/{self.video_name}.gif'), images)
shutil.rmtree(self.file_path) # delete temp folder
print('saved gif to:', Path(f'{self.file_path.parent}/{self.video_name}.gif'))
def convert_to_vid(self):
import imageio
images = []
if not os.path.exists(self.file_path):
return
writer = imageio.get_writer('test.mp4', fps=self.fps)
for file in os.listdir(self.file_path):
im = imageio.imread(self.file_path/file)
writer.append_data(im)
writer.close()
print('Video saved!!')
class VideoRecorderUI(WindowPanel):
def __init__(self, **kwargs):
self.duration_label = Text('duration:')
self.duration_field = InputField(default_value='5')
self.fps_label = Text('fps:')
self.fps_field = InputField(default_value='30')
self.name_label = Text('name:')
self.name_field = InputField(default_value='untitled_video')
self.start_button = Button(text='Start Recording [Shift+F12]', color=color.azure, on_click=self.start_recording)
super().__init__(
title='Video Recorder [F12]',
content=(
self.duration_label,
self.duration_field,
self.fps_label,
self.fps_field,
self.name_label,
self.name_field,
Space(1),
self.start_button,
),
)
self.y = .5
self.scale *= .75
self.visible = False
def input(self, key):
if key == 'f12':
self.visible = not self.visible
if held_keys['shift'] and key == 'f12':
self.start_button.on_click()
def start_recording(self):
print(self.name_field)
if self.name_field.text == '':
self.name_field.blink(color.color(0,1,1,.5), .5)
print('enter name')
return
# self.start_button.color=color.lime
self.visible = False
application.video_recorder.duration = float(self.duration_field.text)
application.video_recorder.video_name = self.name_field.text
application.video_recorder.frame_skip = 60 // int(self.fps_field.text)
application.video_recorder.recording = True
if __name__ == '__main__':
app = Ursina()
# window.size = (1600/3,900/3)
# cube = primitives.RedCube()
# cube.animate_x(5, duration=5, curve=curve.linear)
# cube.animate_x(0, duration=5, curve=curve.linear, delay=5)
# vr = VideoRecorder()
# invoke(setattr, vr, 'recording', True, delay=1)
# invoke(os._exit, 0, delay=6)
# vr.recording = True
window.size *= .5
from ursina.prefabs.first_person_controller import FirstPersonController
from ursina.shaders import lit_with_shadows_shader
random.seed(0)
Entity.default_shader = lit_with_shadows_shader
ground = Entity(model='plane', collider='box', scale=64, texture='grass', texture_scale=(4,4))
editor_camera = EditorCamera(enabled=False, ignore_paused=True)
player = FirstPersonController(model='cube', z=-10, color=color.orange, origin_y=-.5, speed=8)
player.collider = BoxCollider(player, Vec3(0,1,0), Vec3(1,2,1))
gun = Entity(model='cube', parent=camera, position=(.5,-.25,.25), scale=(.3,.2,1), origin_z=-.5, color=color.red, on_cooldown=False)
shootables_parent = Entity()
mouse.traverse_target = shootables_parent
for i in range(16):
Entity(model='cube', origin_y=-.5, scale=2, texture='brick', texture_scale=(1,2),
x=random.uniform(-8,8),
z=random.uniform(-8,8) + 8,
collider='box',
scale_y = random.uniform(2,3),
color=color.hsv(0, 0, random.uniform(.9, 1))
)
sun = DirectionalLight()
sun.look_at(Vec3(1,-1,-1))
Sky()
vr = VideoRecorder(duration=10)
def input(key):
if key == '5':
vr.start_recording()
if key == '6':
vr.stop_recording()
app.run()
I am working on bacterial counter, but when i am executing i am facing a 'NameError: name 'Ui_Form' is not defined'. Can anyone gives an idea, where is the issue. I am attaching a whole code here. How to resolve that error specifically. Is there any problem with PyQt5 version or UI library issues. If i wants to apply that same code using streamlit, how i can convert this code in streamlit graphical user interface.
import sys
import cv2 as cv
import os
import numpy as np
from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog, QMainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
from ui import *
class MainWindow(QDialog, Ui_Form):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setupUi(self)
# Variables for initialization statistics
self.path_list = []
self.path_list_i = 0
self.count = 0
self.bias_sum = 0
# Define control parameters
self.CENTER_X = 900
self.CENTER_Y = 900
self.RADIUS = 680
# Define image parameters
self.THRESH = 170
self.MAXVAL = 255
# Initializing auxiliary lines
self.left_line = 600
self.right_line = 1200
self.up_line = 600
self.down_line = 1200
# Initialization signal and slot connection
##Initialization open file operation button
self.open_folder_button.clicked.connect(self.get_file_path)
self.next_button.clicked.connect(self.press_next)
self.pre_button.clicked.connect(self.press_pre)
## Initialize gray value adjustment connection
self.min_spin.valueChanged.connect(self.change_min_grayscale_spin)
self.max_spin.valueChanged.connect(self.change_max_grayscale_spin)
self.min_slider.valueChanged.connect(self.change_min_grayscale_slider)
self.max_slider.valueChanged.connect(self.change_max_grayscale_slider)
## Initialization guide line, mask connection
self.left_spin.valueChanged.connect(self.change_left)
self.right_spin.valueChanged.connect(self.change_right)
self.up_spin.valueChanged.connect(self.change_up)
self.down_spin.valueChanged.connect(self.change_down)
self.center_x_spin.valueChanged.connect(self.change_center_x)
self.center_y_spin.valueChanged.connect(self.change_center_y)
self.r_spin.valueChanged.connect(self.change_r)
##Initialize nine offset connections
self.bias_1.valueChanged.connect(self.bias_change)
self.bias_2.valueChanged.connect(self.bias_change)
self.bias_3.valueChanged.connect(self.bias_change)
self.bias_4.valueChanged.connect(self.bias_change)
self.bias_5.valueChanged.connect(self.bias_change)
self.bias_6.valueChanged.connect(self.bias_change)
self.bias_7.valueChanged.connect(self.bias_change)
self.bias_8.valueChanged.connect(self.bias_change)
self.bias_9.valueChanged.connect(self.bias_change)
def get_file_path(self):
dir_choose = QFileDialog.getExistingDirectory(self, "Select Folder", os.getcwd())
temp_list = os.listdir(dir_choose)
for i in temp_list:
self.path_list.append(dir_choose + "/" + i)
self.path_list_i = 0
self.shulaibao()
def press_next(self):
if self.path_list_i == len(self.path_list) - 1:
pass
else:
self.path_list_i += 1
self.shulaibao()
def press_pre(self):
if self.path_list_i == 0:
pass
else:
self.path_list_i -= 1
self.shulaibao()
def change_min_grayscale_slider(self):
self.THRESH = self.min_slider.value()
self.min_spin.setValue(self.THRESH)
self.shulaibao()
def change_min_grayscale_spin(self):
self.THRESH = self.min_spin.value()
self.min_slider.setValue(self.THRESH)
self.shulaibao()
def change_max_grayscale_slider(self):
self.MAXVAL = self.max_slider.value()
self.max_spin.setValue(self.MAXVAL)
self.shulaibao()
def change_max_grayscale_spin(self):
self.MAXVAL = self.max_spin.value()
self.max_slider.setValue(self.MAXVAL)
self.shulaibao()
def change_center_x(self):
self.CENTER_X = self.center_x_spin.value()
self.shulaibao()
def change_center_y(self):
self.CENTER_Y = self.center_y_spin.value()
self.shulaibao()
def change_r(self):
self.RADIUS = self.r_spin.value()
self.shulaibao()
def change_left(self):
self.left_line = self.left_spin.value()
self.shulaibao()
def change_right(self):
self.right_line = self.right_spin.value()
self.shulaibao()
def change_down(self):
self.right_line = self.right_spin.value()
self.shulaibao()
def change_up(self):
self.right_line = self.right_spin.value()
self.shulaibao()
def bias_change(self):
self.bias_sum = self.bias_1.value() + self.bias_2.value() + self.bias_3.value() + self.bias_4.value() + \
self.bias_5.value() + self.bias_6.value() + self.bias_7.value() + self.bias_8.value() + \
self.bias_9.value()
self.count_label.setText(f"The total is:{self.count + self.bias_sum}")
def shulaibao(self):
cv.destroyAllWindows()
img = cv.imread(self.path_list[self.path_list_i])
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
img_gray = cv.blur(img_gray, (3, 3))
# The circular mask is drawn and the target image is synthesized with gray image
mask = np.zeros_like(img_gray)
mask = cv.circle(mask, (self.CENTER_X, self.CENTER_Y), self.RADIUS, (255, 255, 255), -1)
mask = mask // 255
img_with_mask = mask * img_gray
# Binarization
_, img_threshold = cv.threshold(img_with_mask, self.THRESH, self.MAXVAL, cv.THRESH_BINARY)
# Connect the region to get the border
contours, _ = cv.findContours(img_threshold, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
img_1 = cv.drawContours(img, contours, -1, (0, 0, 255))
img_1 = cv.circle(img_1, (self.CENTER_X, self.CENTER_Y), self.RADIUS, (0, 255, 0), 5)
img_1 = cv.putText(img_1, "{}".format(len(contours)), (100, 100), cv.FONT_HERSHEY_SIMPLEX, 2, (255, 255, 255),5)
# Draw guides
cv.line(img_1, (self.left_line, 0), (self.left_line, 1800), (0, 255, 0), 3, 8)
cv.line(img_1, (self.right_line, 0), (self.right_line, 1800), (0, 255, 0), 3, 8)
cv.line(img_1, (0, self.up_line), (1800, self.up_line), (0, 255, 0), 3, 8)
cv.line(img_1, (0, self.down_line), (1800, self.down_line), (0, 255, 0), 3, 8)
# Display picture, record number
img_1 = cv.resize(img_1, (0, 0), fx=0.5, fy=0.5)
self.count = len(contours)
self.bias_change()
cv.imshow("COUNT", img_1)
cv.waitKey(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
cv.destroyAllWindows()
sys.exit()
I am trying to get a ball(QPixmap inside a QLabel) to rotate while bouncing off the edges of the screen. But the ball, even though it does rotate seems to be moving along the axis inside the QLabel so after a few movements of the timer it moves outside the borders of the QLabel and therefore does not appear any longer.
Please see my code below.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import random
x = 0
y = 00
velX = 2
velY = 1
randX = random.choice([1, 2, 3])
randY = random.choice([1, 2, 3])
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle('ball move')
self.setMinimumWidth(800)
self.setMaximumWidth(800)
self.setMinimumHeight(500)
self.setMaximumHeight(500)
self.setStyleSheet('background-color: black;border:none;')
self.ballLabel = QLabel(self)
self.ballPixmap = QPixmap('ball.png')
self.resizedBallPixmap = self.ballPixmap.scaled(50, 50, Qt.KeepAspectRatio, Qt.FastTransformation)
self.ballLabel.setFixedSize(50, 50)
self.ballRotation = 10
self.ballLabel.setPixmap(self.resizedBallPixmap)
self.ballLabel.setStyleSheet('border:1px solid red;')
self.ballLabel.show()
self.ballLabel.move(0, 0)
def rotateBall(self):
self.resizedBallPixmap = self.resizedBallPixmap.transformed(
QTransform().rotate(self.ballRotation), Qt.SmoothTransformation)
# self.resizedBallPixmap = self.resizedBallPixmap.transformed(QTransform().translate(self.resizedBallPixmap.size().width()/2, self.resizedBallPixmap.size().height()/2))
self.ballLabel.setPixmap(self.resizedBallPixmap)
def ballMove():
global x, y, velX, velY, randX, randY
if (main_window.ballLabel.pos().x() + 50) > 800:
velX = -1
randX = random.choice([1, 2, 3])
randY = random.choice([1, 2, 3])
elif main_window.ballLabel.pos().x() < 0:
velX = 1
randX = random.choice([1, 2, 3])
randY = random.choice([1, 2, 3])
elif (main_window.ballLabel.pos().y() + 50) > 500:
velY = -1
randX = random.choice([1, 2, 3])
randY = random.choice([1, 2, 3])
elif main_window.ballLabel.pos().y() < 0:
velY = 1
randX = random.choice([1, 2, 3])
randY = random.choice([1, 2, 3])
x += velX*randX
y += velY*randY
main_window.rotateBall()
main_window.ballLabel.move(x, y)
if __name__ == "__main__":
app = QApplication([])
main_window = MainWindow()
main_window.show()
timer = QTimer()
timer.timeout.connect(ballMove)
timer.start(1000)
app.exec_()
Explanation:
To understand the problem then the size of self.resizedBallPixmap must be analyzed using the following code:
def rotateBall(self):
print(self.resizedBallPixmap.size())
# ...
Output:
PyQt5.QtCore.QSize(50, 50)
PyQt5.QtCore.QSize(59, 58)
PyQt5.QtCore.QSize(70, 68)
PyQt5.QtCore.QSize(81, 80)
PyQt5.QtCore.QSize(94, 93)
PyQt5.QtCore.QSize(110, 108)
PyQt5.QtCore.QSize(128, 126)
PyQt5.QtCore.QSize(149, 147)
PyQt5.QtCore.QSize(173, 171)
PyQt5.QtCore.QSize(201, 199)
PyQt5.QtCore.QSize(233, 231)
PyQt5.QtCore.QSize(271, 268)
PyQt5.QtCore.QSize(314, 311)
...
As you can see, the size of the QPixmap is changing, and why is it changing? because when rotating a rectangle the ex-inscribed rectangle must be bigger, and what causes the rectangle to be bigger? Well, the size of the QLabel is not enough to draw the QPixmap and it only paints the left part, making the user observe that the ball advances.
Solution:
The solution is that when the QPixmap is rotated it is cut and only the necessary part is kept. In addition, each rotation transformation generates distortion, so it is not recommended to iterate over the same QPixmap but to maintain the original QPixmap and increase the angle of rotation.
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
# ...
self.ballLabel.move(0, 0)
self.angle = 0
def rotateBall(self):
self.angle += self.ballRotation
pixmap = self.resizedBallPixmap.transformed(
QTransform().rotate(self.angle), Qt.FastTransformation
)
r = QtCore.QRect(self.resizedBallPixmap.rect())
r.moveCenter(pixmap.rect().center())
pixmap = pixmap.copy(r)
self.ballLabel.setPixmap(pixmap)
A better solution is to use elements of the Qt Graphics Framework such as the QGraphicsItems that implements rotation and translation.
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("ball move")
self.setFixedSize(800, 500)
scene = QGraphicsScene()
scene.setSceneRect(QRectF(QPointF(), QSizeF(self.size())))
view = QGraphicsView(scene)
self.setCentralWidget(view)
self.setStyleSheet("background-color: black;border:none;")
pixmap = QPixmap("ball.png").scaled(
50, 50, Qt.KeepAspectRatio, Qt.FastTransformation
)
self.ballLabel = scene.addPixmap(pixmap)
self.ballLabel.setTransformOriginPoint(self.ballLabel.boundingRect().center())
class BallManager(QObject):
positionChanged = pyqtSignal(QPointF)
angleChanged = pyqtSignal(float)
def __init__(self, parent=None):
super(BallManager, self).__init__(parent)
self.pos = QPointF(0, 0)
self.angle = 0
self.vel = QPointF(2, 1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
self.step_angle = 10
self.timer = QTimer(interval=1000, timeout=self.ballMove)
self.timer.start()
def ballMove(self):
if (self.pos.x() + 50) > 800:
self.vel.setX(-1)
self.randX = QPointF(*random.sample([1, 2, 3], 2))
elif self.pos.x() < 0:
self.vel.setX(1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
elif (self.pos.y() + 50) > 500:
self.vel.setY(-1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
elif self.pos.y() < 0:
self.vel.setY(1)
self.rand = QPointF(*random.sample([1, 2, 3], 2))
self.pos += QPointF(self.vel.x() * self.rand.x(), self.vel.y() * self.rand.y())
self.angle += self.step_angle
self.positionChanged.emit(self.pos)
self.angleChanged.emit(self.angle)
if __name__ == "__main__":
app = QApplication([])
main_window = MainWindow()
main_window.show()
manager = BallManager()
manager.positionChanged.connect(main_window.ballLabel.setPos)
manager.angleChanged.connect(main_window.ballLabel.setRotation)
app.exec_()
I used animator class to generate ellipseobject and also add animation to them, the goal is only change the scale (from double size to normal size) of the dot, but not do the translate. Right now what I am facing is the dot does shrink, but it moves from the location where (x y value are double with its original x y value) to its original x y location.
Here is the animator class
class Animator:
def __init__(self, animation_config, num_rows, num_cols, background_colour, parent, user_idx = 0, resolution_width = 1920,
resolution_height = 1200, log_file_path = "coordinates.txt"):
with open(log_file_path, "w") as log_file:
log_file.write("")
circle = animation_config["circle"]
self.__cur_circle = None
self.__cur_colour = None
self.__animated_colour = QColor(*circle["colour"])
self.__log_file_path = log_file_path
# Initialize the circle table
diamond_square = DiamondSquare()
self.__user_idx = user_idx % 64
shift_xn = diamond_square.dx[user_idx]
shift_yn = diamond_square.dy[user_idx]
intv_x = (resolution_width - 20) / 10
intv_y = (resolution_height - 20) / 10
print(shift_xn,shift_yn)
self.__circle_table = []
y = 0
for i in range (11):
circles = []
x = 0
for j in range (11):
cir_x = (j * intv_x) + shift_xn
cir_y = (i * intv_y) + shift_yn
print(cir_x,cir_y)
if cir_x <= resolution_width and cir_y <= resolution_height:
circles.append(EllipseObject(parent,cir_x,cir_y, x, y, intv_x, intv_y,
hidden_colour = background_colour,
display_colour=self.__animated_colour))
x += 1
y += 1
self.__circle_table.append(circles)
# Initalize the first animation
self.__first = QPropertyAnimation()
self.__first.setPropertyName(b"scale")
self.__first.setDuration(animation_config["animation_duration"])
self.__first.setStartValue(2)
self.__first.setEndValue(1)
and here is my EllipseObject class
class EllipseObject(QGraphicsWidget):
def __init__(
self,
parent,
x = 0,
y = 0,
ind_x = 0,
ind_y = 0,
intv_x = 0,
intv_y = 0,
width = 20,
height = 20,
hidden = True,
hidden_colour = QColor(Qt.white),
display_colour = QColor(Qt.black)
):
super().__init__(parent)
self.__x = x
self.__y = y
self.__ind_x = ind_x
self.__ind_y = ind_y
self.__intv_x = intv_x
self.__intv_y = intv_y
self.__height = height
self.__width = width
self.hidden = hidden
self.hidden_colour = hidden_colour
self.display_colour = display_colour
def paint(self, painter, option, widget = None):
colour = QColor(Qt.white) if self.hidden else self.display_colour
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(colour)
painter.setBrush(QBrush(colour))
# painter.drawEllipse(self.__x, self.__y, self.__width, self.__height)
painter.drawEllipse(self.boundingRect())
# point = self.mapToScene(self.boundingRect().center())
# print("Draw this ",point.x(), point.y())
def get_coordinates(self):
point = self.mapToScene(self.boundingRect().center())
return (point.x(), point.y())
def boundingRect(self):
return QRectF(self.__x,
self.__y,
self.__height, self.__width)
What you are probably observing is that it is rising with respect to the upper left corner and will give you the appearance that it is moving. The QGraphicsItem has a property called transformOriginPoint with respect to which transformations, such as rotation and scaling, are performed and which is found at point (0, 0). In your case your code has several errors, you must set the position with setPos() and not through boundingRect(), so that the scaling is with respect to the center of the item establishes that the boundingRect() is symmetric.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class EllipseObject(QGraphicsWidget):
def __init__(
self,
parent=None,
x = 0,
y = 0,
ind_x = 0,
ind_y = 0,
intv_x = 0,
intv_y = 0,
width = 20,
height = 20,
hidden = True,
hidden_colour = QColor(Qt.white),
display_colour = QColor(Qt.black)
):
super().__init__(parent)
self.__x = x
self.__y = y
self.__ind_x = ind_x
self.__ind_y = ind_y
self.__intv_x = intv_x
self.__intv_y = intv_y
self.__height = height
self.__width = width
self.hidden = hidden
self.hidden_colour = hidden_colour
self.display_colour = display_colour
self.setPos(self.__x, self.__y)
def paint(self, painter, option, widget = None):
colour = QColor(Qt.white) if self.hidden else self.display_colour
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(colour)
painter.setBrush(QBrush(colour))
# painter.drawEllipse(self.__x, self.__y, self.__width, self.__height)
painter.drawEllipse(self.boundingRect())
def get_coordinates(self):
return (self.pos().x(), self.pos().y())
def boundingRect(self):
return QRectF(-0.5*self.__width,
-0.5*self.__height,
self.__height, self.__width)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = QGraphicsView()
scene = QGraphicsScene(w)
w.setScene(scene)
it = EllipseObject(x=100, y=100, hidden=False)
scene.addItem(it)
animation = QPropertyAnimation(it, b"scale")
animation.setDuration(2000)
animation.setStartValue(2)
animation.setEndValue(1)
animation.start()
w.show()
sys.exit(app.exec_())
Note:
Instead of using flag called hidden, use setVisible(boolean), show() or hide() directly. Qt already has many methods implemented, the wheel does not reinvent.