Issue with Kivy movement - python-3.x

I've been trying to work this out for a while now. Below, is the python/kivy code for the early stages of a kivy app. The issue lies in player movement. Kivy is overcompensating the dx and dy movements and it is causing the player movement to constantly shake. I don't know how to fix this issue. Any ideas?
Note:
Much of this code is incomplete, but the player movement is mostly done. The movement issue is happening in the "Player" class.
EDIT: Here is what I tried following the advice of the post below
import kivy
kivy.require('1.1.1')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty, NumericProperty
import math
from kivy.clock import Clock
import time
import random
PLAYER_SPEED = 10
ENEMY_SPAWN = 3
UPDATE_SPEED = .01
MIN_INITIAL_PLAYER_MINION_DISTANCE = 200
class Player(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
target = ListProperty([])
speed = NumericProperty(PLAYER_SPEED)
def __init__(self, **kwargs):
Widget.__init__(self)
self.target = [399.0, 399.0]
def update_target(self, new_target):
self.target = new_target
def move(self):
dx = self.target[0] - self.center[0]
dy = self.target[1] - self.center[1]
x_1 = self.pos[0] - self.center[0]
y_1 = self.pos[1] - self.center[1]
total = math.sqrt(dx ** 2 + dy**2)
self.velocity_x = (dx / total) * self.speed
self.velocity_y = (dy / total) * self.speed
if math.sqrt(x_1** 2 + y_1**2) < self.speed:
self.pos = self.center
else:
new_x = self.pos[0] + self.velocity_x
new_y = self.pos[1] + self.velocity_y
self.pos = (new_x,new_y)
class Enemy(Player):
velocity_y = NumericProperty(PLAYER_SPEED)
def __init__(self, **kwargs):
Widget.__init__(self)
self.center = kwargs.get('start_pos',[0,0])
def move(self):
self.pos = (self.pos[0], self.pos[1] + self.velocity_y)
def distance(widget1, widget2):
dist = math.sqrt((widget1.pos[0]-widget2.pos[0])**2 + \
(widget1.pos[1]-widget2.pos[1])**2)
return dist
class Game(Widget):
player1 = ObjectProperty(None)
enemies = ListProperty([])
decoys = ListProperty([])
def setup(self):
self.enemies = []
self.decoys = []
self.player1.center = self.center
self.setup_schedules()
#Don't forget about good code organization!
def setup_schedules(self):
Clock.schedule_interval(self.update, UPDATE_SPEED)
Clock.schedule_interval(self.spawn_enemy, ENEMY_SPAWN)
def update(self,dt):
self.player1.move()
def spawn_enemy(self, dt):
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy = Enemy(start_pos = (x,y))
while distance(enemy, self.player1)< MIN_INITIAL_PLAYER_MINION_DISTANCE:
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy.pos = (x,y)
self.enemies.append(enemy)
self.add_widget(enemy)
def score(self):
zero_score = time.time()
player_score = zero_score + 1
#on_touch_move vs on_touch_down
def on_touch_move(self, touch):
self.player1.update_target([touch.x, touch.y])
#Entry Point into app
class GameApp(App):
def build(self):
game = Game()
game.setup()
return game
def main():
GameApp().run()
main()

In your player class, and within move(), before you update pos, you would check if the distance between pos and center is smaller than speed. if it is, then simply set pos to be equal to center. If it is not, then increment pos as you already do.

Related

Turtle screen gets closed when .onclick() or onscreenclick() is used

I have a global variable, 'is_game_on' set to 'False' to start with. I have a turtle which responds to .ondrag() function. My program works perfectly fine if I change the 'is_game_on' variable to 'True' (The main program runs in a while loop when 'is_game_on' is 'True').
In the same Screen I have created turtle (a text- 'Click to start') in the top right of the screen, which I want to return 'is_game_on' = 'True' when the mouse is clicked on it so that the rest of my program starts working there after. However, my screen gets closed when I click the mouse. I think this is because of the command screen.exitonclick() at the end. Appreciate any suggestions how to avoid this problem.
Below is my code. I want to start with 'is_game_on == False' and with the output a static display. Then when I click the mouse on 'Click to Start', a mechanism to trigger 'is_game_on" as True and then the ball starts bouncing up and down.
from turtle import Screen, Turtle
import time
# is_game_on = False
is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
screen.update()
screen.exitonclick()
After lot of trial and errors and lot of web searches, I found the solution.
The screen closing problem can be simply avoided by importing turtle and adding turtle.done() command just before screen.exitonclick() command. The complete code will be.
from turtle import Screen, Turtle
import time
import turtle
is_game_on = False
# is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
screen.update()
turtle.done()
screen.exitonclick()
The animation can work by moving the while loop into the click() function. The code will be as follows.
from turtle import Screen, Turtle
import time
import turtle
is_game_on = False
# is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
screen.update()
turtle.done()
screen.exitonclick()

How to use rubber band to zoom in and out in pyqt5

I would like to use the RubberBand to zoom in and out relative to the size of the box I would like to zoom in the view to fit whatever is inside the block to the full view.
Can anyone help?
The zoom in and out with the mouse works as expected.
You can see in the code the rubberband works but I don't know how to make the zoom relative to the size of the box.
code:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
from math import sqrt
class Point(QGraphicsItem):
def __init__(self, x, y):
super(Point, self).__init__()
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.rectF = QRectF(0, 0, 30, 30)
self.x=x
self.y=y
self._brush = QBrush(Qt.black)
def setBrush(self, brush):
self._brush = brush
self.update()
def boundingRect(self):
return self.rectF
def paint(self, painter=None, style=None, widget=None):
painter.fillRect(self.rectF, self._brush)
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
print(point)
QGraphicsItem.hoverMoveEvent(self, event)
class Viewer(QGraphicsView):
photoClicked = pyqtSignal(QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(Viewer, self).__init__(parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
self._zoom = 0
self._empty = True
self._scene = QGraphicsScene(self)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.area = float()
self.setPoints()
def setItems(self):
self.data = {'x': [-2414943.8686, -2417160.6592, -2417160.6592, -2417856.1783, -2417054.7618, -2416009.9966, -2416012.5232, -2418160.8952, -2418160.8952, -2416012.5232, -2417094.7694, -2417094.7694], 'y': [10454269.7008,
10454147.2672, 10454147.2672, 10453285.2456, 10452556.8132, 10453240.2808, 10455255.8752, 10455183.1912, 10455183.1912, 10455255.8752, 10456212.5959, 10456212.5959]}
maxX = max(self.data['x'])
minX = min(self.data['x'])
maxY = max(self.data['y'])
minY = min(self.data['y'])
distance = sqrt((maxX-minX)**2+(maxY-minY)**2)
self.area = QRectF(minX, minY, distance, distance)
for i,x in enumerate(self.data['x']):
x = self.data['x'][i]
y = self.data['y'][i]
p = Point(x,y)
p.setPos(x,y)
self._scene.addItem(p)
self.setScene(self._scene)
def fitInView(self, scale=True):
rect = QRectF(self.area)
if not rect.isNull():
self.setSceneRect(rect)
unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def setPoints(self):
self._zoom = 0
self.setItems()
self.setDragMode(True)
self.fitInView()
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.fitInView()
else:
self._zoom = 0
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
return
#QGraphicsView.mousePressEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ClosedHandCursor)
self.original_event = event
handmade_event = QMouseEvent(QEvent.MouseButtonPress,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mousePressEvent(self,handmade_event)
super(Viewer, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.changeRubberBand = False
QGraphicsView.mouseReleaseEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.OpenHandCursor)
handmade_event = QMouseEvent(QEvent.MouseButtonRelease,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mouseReleaseEvent(self,handmade_event)
super(Viewer, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self,event)
super(Viewer, self).mouseMoveEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = Viewer(self)
self.btnLoad = QToolButton(self)
self.btnLoad.setText('Load Points')
self.btnLoad.clicked.connect(self.loadPoints)
VBlayout = QVBoxLayout(self)
VBlayout.addWidget(self.viewer)
HBlayout = QHBoxLayout()
HBlayout.setAlignment(Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
VBlayout.addLayout(HBlayout)
def loadPoints(self):
self.viewer.setPoints()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())

How can I bind a function to the return key when my Tk frames are generated?

I am trying to bind the function validateSubmit to the enter key so the test may be taken at faster speeds, however I cannot figure out where or what to try to bind it to. Inside of the main at the bottom, I commented out the bind that I feel I get the closest results with, however I've been at this long enough to know that its currently beyond my scope of knowledge. This program is my foray into OOP. I also receive a strange error from validateSubmit, however it seems to be caused by tkinter's internal type-casting and has not seemed to do anything more than echo an error back in the terminal.
##########################################################################################
#Imports
import tkinter as tk
from tkinter import ttk
from tkinter import Tk
from random import randint
##########################################################################################
class Storage():
def __init__(self):
self.timeChoice = 0
self.gameScore = 0
self.answer = 0
self.highScore = 0
def set_timeChoice(self,x):
self.timeChoice = x
def set_gameScore(self,x):
self.gameScore = x
def set_answer(self,x):
self.answer = x
def set_highScore(self,x):
self.highScore = x
def save_highScore(self):
timeChoiceVar = str(self.timeChoice)
with open('data' + timeChoiceVar + '.txt',mode='w') as file:
file.write(str(self.highScore))
def get_highScore(self):
timeChoiceVar = str(self.timeChoice)
try:
with open('data' + timeChoiceVar + '.txt',mode='r') as file:
self.highScore = file.read()
except:
with open('data' + timeChoiceVar + '.txt',mode='w') as file:
file.write('0')
##########################################################################################
class AdditionApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.switch_frame(SetTimePage)
def switch_frame(self, frame_class):
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.grid(column=0,row=0,sticky=tk.W)
##########################################################################################
class SetTimePage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.timeVar = tk.IntVar()
data.set_timeChoice(60)
time_frame = ttk.LabelFrame(self,text=' Test Timer Selection ')
time_frame.grid(column=0,row=0,padx=6,pady=8,sticky='WE')
radio1 = tk.Radiobutton(time_frame,text='1 Minute',variable=self.timeVar,value=60,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio1.grid(column=0,row=0,sticky=tk.W)
radio1.select()
radio2 = tk.Radiobutton(time_frame,text='2 Minutes',variable=self.timeVar,value=120,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio2.grid(column=0,row=1,sticky=tk.W)
radio5 = tk.Radiobutton(time_frame,text='5 Minutes',variable=self.timeVar,value=300,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio5.grid(column=0,row=2,sticky=tk.W)
radio10 = tk.Radiobutton(time_frame,text='10 Minutes',variable=self.timeVar,value=600,command=lambda: data.set_timeChoice(self.timeVar.get()))
radio10.grid(column=0,row=3,sticky=tk.W)
start_button = ttk.Button(self,text=' Start ',command=lambda: master.switch_frame(TestPage))
start_button.grid(column=0,row=1,sticky='WE',pady=4)
##########################################################################################
class TestPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.answer = tk.IntVar()
self.scoreVar = 0
data.set_gameScore(0)
data.get_highScore()
self.test_frame = tk.Label(self,text=data.timeChoice)
self.test_frame.grid(column=3,row=0,sticky=tk.N)
self.score_frame = tk.Label(self,text='Score: %d' % data.gameScore)
self.score_frame.grid(column=3,row=1,sticky=tk.N)
self.high_score_frame = tk.Label(self,text='High Score: %s' % data.highScore)
self.high_score_frame.grid(column=3,row=2,sticky=tk.N)
self.solve_frame = ttk.LabelFrame(self,text=' Solve: ')
self.solve_frame.grid(column=0,row=1,columnspan=2,padx=12,sticky=tk.W)
self.equation_label = tk.Label(self.solve_frame,text='')
self.equation_label.grid(column=0,row=0,padx=6,sticky=tk.W)
self.answer_box = ttk.Entry(self.solve_frame,width=2,textvariable=self.answer)
self.answer_box.grid(column=1,row=0,padx=12,sticky=tk.W)
self.answer_box.bind('<Return>', self.validateSubmit)
self.back_button = ttk.Button(self.solve_frame,text=' Back ',command=lambda: master.switch_frame(SetTimePage))
self.back_button.grid(column=3,row=0,padx=12,sticky=tk.N)
self.countdown(data.timeChoice)
def countdown(self, remaining = None):
if remaining is not None:
self.remaining = remaining
self.generateEquation()
if self.remaining < 0:
self.test_frame.configure(text=" Time's up! ")
self.submit_answer.configure(state='disabled')
self.answer_box.configure(state='disabled')
else:
self.test_frame.configure(text="Seconds remaining: %d" % self.remaining)
self.high_score_frame.configure(text='High Score: %s' % data.highScore)
self.submit_answer.bind('<Return>', self.validateSubmit)
self.remaining = self.remaining - 1
self.after(1000, self.countdown)
def generateEquation(self):
self.x = randint(0,10)
self.y = randint(0,10)
self.z = 0
self.equation_label.configure(text='%d + %d' % (self.x , self.y))
self.answer_box.delete(0,3)
self.answer_box.focus()
self.submit_answer = ttk.Button(self.solve_frame,text=' Submit ',command=self.validateSubmit)
self.submit_answer.grid(column=2,row=0,padx=12,sticky=tk.E)
def validateSubmit(self,event=None):
while self.remaining >= 0:
self.z = self.answer.get()
if self.x + self.y == self.z:
self.scoreVar += 1
data.set_gameScore(self.scoreVar)
self.score_frame.configure(text='Score: %d' % data.gameScore)
self.generateEquation()
if int(data.highScore) < data.gameScore:
data.set_highScore(data.gameScore)
data.save_highScore()
elif self.x + self.y != self.z :
self.generateEquation()
##########################################################################################
if __name__ == "__main__":
data = Storage()
program = AdditionApp()
program.title(' Addition Test ')
#program.bind('<Return>', TestPage.validateSubmit)
program.mainloop()
data.save_highScore
If you want the user to be able to press return after entering an answer instead of pressing the Submit button, then the binding needs to go on the entry widget since that is the widget with keyboard focus.
self.answer_box.bind('<Return>', self.validateSubmit)
Also, you need to make sure that validateSubmit can accept the event option that is passed in. Since you want to use it both for a binding and a button click, the easiest way to do that is to make the event argument optional:
def validateSubmit(self, event=None):

How to change a QImage that is already set up and shown within QWidget?

I want to change an image with my mouse. So, everytime I click somewhere, the image should change. I can show an image only one time. So I need to separate the initialization of everything that is needed to show an image from the part of code that is responsable for building an image.
Here is what I have got by far
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.gx=1
self.gy=1
self.tlb=QLabel()
self.lbl=QLabel()
self.image = QImage(512, 512, QImage.Format_RGB32)
self.hbox = QHBoxLayout()
self.pixmap = QPixmap()
self.initUI()
def mousePressEvent(self, QMouseEvent):
px = QMouseEvent.pos().x()
py = QMouseEvent.pos().y()
size = self.frameSize()
self.gx = px-size.width()/2
self.gy = py-size.height()/2
self.fillImage()
def initUI(self):
self.hbox = QHBoxLayout(self)
self.pixmap = QPixmap()
size = self.frameSize()
self.fillImage()
self.lbl = QLabel(self)
self.lbl.setPixmap(self.pixmap)
self.hbox.addWidget(self.lbl)
self.setLayout(self.hbox)
self.move(300, 200)
self.setWindowTitle('Red Rock')
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
self.tlb.move(12,3)
self.show()
def fillImage(self):
for x in range(0, 512):
t = -1+(x/512)*2
color = (1 - (3 - 2*abs(t))*t**2)
for y in range(0, 512):
t1 = -1+(y/512)*2
color1 = (1 - (3 - 2*abs(t1))*t1**2)
result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
self.image.setPixel(x, y, qRgb(result, result, result))
self.pixmap = self.pixmap.fromImage(self.image)
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
print(self.gx)
self.update()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The print(self.gx) shows me that self.gx is changed, but the image isn't changed at all.
What do I do wrong?
You will have to tell the GUI that it needs to refresh the image.
In QT it seems you will need to call the update() or repaint() methods of the widget.
I've added self.lbl.setPixmap(self.pixmap) into fillImage before self.repaint() and self.update() and now it works, then i changed a little the code and now it looks like this
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.gx=1
self.gy=1
self.lbl=QLabel()
self.tlb = None
self.image = QImage(512, 512, QImage.Format_RGB32)
self.hbox = QHBoxLayout()
self.pixmap = QPixmap()
self.length = 1
self.initUI()
def mousePressEvent(self, QMouseEvent):
px = QMouseEvent.pos().x()
py = QMouseEvent.pos().y()
size = self.frameSize()
self.gx = px-size.width()/2
self.gy = py-size.height()/2
h = (self.gx**2+self.gy**2)**0.5
self.gx/=h
self.gy/=h
self.gx*=self.length
self.gy*=self.length
self.fillImage()
def wheelEvent(self,event):
self.length+=(event.delta()*0.001)
print(self.length)
def initUI(self):
self.hbox = QHBoxLayout(self)
self.pixmap = QPixmap()
self.move(300, 200)
self.setWindowTitle('Red Rock')
self.addedWidget = None
self.fillImage()
self.setLayout(self.hbox)
self.show()
def fillImage(self):
for x in range(0, 512):
t = -1+(x/512)*2
color = (1 - (3 - 2*abs(t))*t**2)
for y in range(0, 512):
t1 = -1+(y/512)*2
color1 = (1 - (3 - 2*abs(t1))*t1**2)
result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
self.image.setPixel(x, y, qRgb(result, result, result))
self.pixmap = self.pixmap.fromImage(self.image)
if self.lbl == None:
self.lbl = QLabel(self)
else:
self.lbl.setPixmap(self.pixmap)
if self.addedWidget == None:
self.hbox.addWidget(self.lbl)
self.addedWidget = True
if self.tlb==None:
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
self.tlb.move(12,3)
else:
self.tlb.setText(str(self.gx)+" : "+str(self.gy))
self.repaint()
self.update()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Adding scrollbar in pyqt4

I have some large images to be inserted in window and my window size is defined. If my image size is greater than window, there must be scroll bars else not. I have also panning and zooming features implemented so that i can resize image to any size. Thanks antiearth for this sample code
from PyQt4 import QtCore, QtGui
import sys
class Annotator(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.image = None
self.scale = 1.0
self.position = (100, 100)
self.pressed = None
self.anchor = None
self.load('Some LArge Image/Images.png')
def load(self, filename):
self.image = QtGui.QImage(filename)
def mousePressEvent(self, event):
print 'PRESSED : ',event.pos()
self.pressed = event.pos()
self.anchor = self.position
def mouseReleaseEvent(self, event):
self.pressed = None
def mouseMoveEvent(self, event):
if (self.pressed):
dx, dy = event.x() - self.pressed.x(), event.y() - self.pressed.y()
self.position = (self.anchor[0] - dx, self.anchor[1] - dy)
self.repaint()
def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
screenpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = screenpoint.x(), screenpoint.y()
oldpoint = (screenpoint.x() + self.position[0], screenpoint.y() + self.position[1])
newpoint = (oldpoint[0] * (self.scale/oldscale),
oldpoint[1] * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)
self.repaint()
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.drawImage(0, 0,
self.image.scaled(
self.image.width() * self.scale,
self.image.height() * self.scale,
QtCore.Qt.KeepAspectRatio),
self.position[0], self.position[1])
painter.end()
app = QtGui.QApplication(sys.argv)
annotator = Annotator()
annotator.show()
sys.exit(app.exec_())
I want to insert scrollbars here. Hope I made this clear.
In PyQt4 have QtGui.QScrollArea to allow your resize with scroll bars, So your have to implement this class and in your def paintEvent (self, eventQPaintEvent) your have calculate new position and resize your widget with QWidget.setFixedSize (self, QSize)
Full example;
from PyQt4 import QtCore, QtGui
import sys
class Annotator (QtGui.QLabel):
def __init__(self, parentQExampleScrollArea, parentQWidget = None):
QtGui.QLabel.__init__(self, parentQWidget)
self.parentQExampleScrollArea = parentQExampleScrollArea
self.image = None
self.scale = 1.0
self.position = (0, 0)
self.pressed = None
self.anchor = None
self.load('myImage.jpg')
def load (self, filename):
self.image = QtGui.QImage(filename)
def mousePressEvent (self, eventQMouseEvent):
self.pressed = eventQMouseEvent.pos()
self.anchor = self.position
def mouseReleaseEvent (self, eventQMouseEvent):
self.pressed = None
def mouseMoveEvent (self, eventQMouseEvent):
if (self.pressed):
dx, dy = eventQMouseEvent.x() - self.pressed.x(), eventQMouseEvent.y() - self.pressed.y()
self.position = (self.anchor[0] - dx, self.anchor[1] - dy)
self.repaint()
def wheelEvent (self, eventQWheelEvent):
oldscale = self.scale
self.scale += eventQWheelEvent.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
screenpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = screenpoint.x(), screenpoint.y()
oldpoint = (screenpoint.x() + self.position[0], screenpoint.y() + self.position[1])
newpoint = (oldpoint[0] * (self.scale/oldscale), oldpoint[1] * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)
self.repaint()
def paintEvent (self, eventQPaintEvent):
scaledQImage = self.image.scaled (
self.image.width() * self.scale,
self.image.height() * self.scale,
QtCore.Qt.KeepAspectRatio)
painter = QtGui.QPainter()
painter.begin(self)
painter.drawImage (
0,
0,
scaledQImage,
0 if self.position[0] > 0 else self.position[0],
0 if self.position[1] > 0 else self.position[1])
painter.end()
scaledWidth = self.parentQExampleScrollArea.size().width() - 16 if self.position[0] > 0 else scaledQImage.width()
scaledHeight = self.parentQExampleScrollArea.size().height() - 16 if self.position[1] > 0 else scaledQImage.height()
self.setFixedSize(abs(self.position[0]) + scaledWidth, abs(self.position[1]) + scaledHeight)
class QExampleScrollArea (QtGui.QScrollArea):
def __init__ (self, parentQWidget = None):
super(QtGui.QScrollArea, self).__init__(parentQWidget)
self.myAnnotator = Annotator(self)
self.setWidget(self.myAnnotator)
def mousePressEvent (self, eventQMouseEvent):
QtGui.QScrollArea.mousePressEvent(self, eventQMouseEvent)
self.myAnnotator.mousePressEvent(eventQMouseEvent)
def mouseReleaseEvent (self, eventQMouseEvent):
QtGui.QScrollArea.mouseReleaseEvent(self, eventQMouseEvent)
self.myAnnotator.mouseReleaseEvent(eventQMouseEvent)
def mouseMoveEvent (self, eventQMouseEvent):
QtGui.QScrollArea.mouseMoveEvent(self, eventQMouseEvent)
self.myAnnotator.mouseMoveEvent(eventQMouseEvent)
def wheelEvent (self, eventQWheelEvent):
self.myAnnotator.wheelEvent(eventQWheelEvent)
app = QtGui.QApplication(sys.argv)
myQExampleScrollArea = QExampleScrollArea()
myQExampleScrollArea.show()
sys.exit(app.exec_())
Note : Recommend use QtGui.QLabel to paint image

Resources