I want to use wxpython to show the trajectory of a random walk in real-time. However, the panel is updated only once at the end showing the entire random walk instead of updating step by step and showing the time course.
My first idea was to use wx.ClientDC().DrawPoint() but the result was as described above where I did not see single points being drawn but only the final result was shown.
So instead I thought about using wx.MemoryDC to draw the trajectory to a bitmap stored in memory and then use wx.ClientDC.DrawBitmap() to copy the buffered image to the screen at set time intervals in case flipping the image was the bottleneck. The result is still the same so I am hoping for you help.
The purpose of this exercise is to replace the random walk with positional data coming from an eye tracker with a frame rate of 1000 Hz and I would like to be able to visualize the trajectory in as close to real-time as possible (the monitor's frame rate is 120Hz).
This is my code (most of it comes from here):
import wx
import random
import time
from time import asctime
#-------------------------------------------------------------------
def jmtime():
return '[' + asctime()[11:19] + '] '
#-------------------------------------------------------------------
class MyDrawingArea(wx.Window):
def __init__(self, parent, id):
sty = wx.NO_BORDER
wx.Window.__init__(self, parent, id, style=sty)
self.parent = parent
self.SetBackgroundColour(wx.WHITE)
self.SetCursor(wx.CROSS_CURSOR)
# Some initalisation, just to reminds the user that a variable
# called self.BufferBmp exists. See self.OnSize().
self.BufferBmp = None
wx.EVT_SIZE(self, self.OnSize)
wx.EVT_PAINT(self, self.OnPaint)
wx.EVT_LEFT_DOWN(self,self.OnClick)
def OnSize(self, event):
print jmtime() + 'OnSize in MyDrawingArea'
# Get the size of the drawing area in pixels.
self.wi, self.he = self.GetSizeTuple()
# Create BufferBmp and set the same size as the drawing area.
self.BufferBmp = wx.EmptyBitmap(self.wi, self.he)
memdc = wx.MemoryDC()
memdc.SelectObject(self.BufferBmp)
# Drawing job
ret = self.DoSomeDrawing(memdc)
if not ret: #error
self.BufferBmp = None
wx.MessageBox('Error in drawing', 'CommentedDrawing', wx.OK | wx.ICON_EXCLAMATION)
def OnPaint(self, event):
print jmtime() + 'OnPaint in MyDrawingArea'
dc = wx.PaintDC(self)
dc.BeginDrawing()
if self.BufferBmp != None:
print jmtime() + '...drawing'
dc.DrawBitmap(self.BufferBmp, 0, 0, True)
else:
print jmtime() + '...nothing to draw'
dc.EndDrawing()
def OnClick(self,event):
pos = event.GetPosition()
dc = wx.ClientDC(self)
dc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID))
dcwi, dche = dc.GetSizeTuple()
x = pos.x
y = pos.y
time_start = time.time()
memdc = wx.MemoryDC()
memdc.SelectObject(self.BufferBmp)
memdc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID))
count = 1
runtime = 5
while (time.time() - time_start) < runtime:
x,y = random_walk(x,y,dcwi,dche)
memdc.DrawPoint(x,y)
if (time.time() - time_start) > count * runtime * 0.1:
print jmtime() + 'Random walk in MyDrawingArea'
count += 1
dc.BeginDrawing()
dc.DrawBitmap(self.BufferBmp, 0, 0, True)
dc.EndDrawing()
dc.BeginDrawing()
dc.DrawBitmap(self.BufferBmp, 0, 0, True)
dc.EndDrawing()
# End of def OnClick
def DoSomeDrawing(self, dc):
try:
print jmtime() + 'DoSomeDrawing in MyDrawingArea'
dc.BeginDrawing()
#~ raise OverflowError #for test
# Clear everything
dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID))
dc.Clear()
dc.EndDrawing()
return True
except:
return False
#-------------------------------------------------------------------
class MyPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize)
self.drawingarea = MyDrawingArea(self, -1)
self.SetAutoLayout(True)
gap = 30 #in pixels
lc = wx.LayoutConstraints()
lc.top.SameAs(self, wx.Top, gap)
lc.left.SameAs(self, wx.Left, gap)
lc.right.SameAs(self, wx.Width, gap)
lc.bottom.SameAs(self, wx.Bottom, gap)
self.drawingarea.SetConstraints(lc)
#-------------------------------------------------------------------
# Usual frame. Can be resized, maximized and minimized.
# The frame contains one panel.
class MyFrame(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'CommentedDrawing', wx.Point(0, 0), wx.Size(500, 400))
self.panel = MyPanel(self, -1)
wx.EVT_CLOSE(self, self.OnCloseWindow)
def OnCloseWindow(self, event):
print jmtime() + 'OnCloseWindow in MyFrame'
self.Destroy()
#-------------------------------------------------------------------
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1)
frame.Show(True)
self.SetTopWindow(frame)
return True
#-------------------------------------------------------------------
def random_walk(x,y,sizex = 250, sizey = 200):
rn = random.randrange(0,2)
x_new = x + (1-rn) - rn
while x_new < 0 or x_new > sizex:
rn = random.randrange(0,2)
x_new = x + (1-rn) - rn
rn = random.randrange(0,2)
y_new = y + (1-rn) - rn
while y_new < 0 or y_new > sizex:
rn = random.randrange(0,2)
y_new = y + (1-rn) - rn
return x_new, y_new
# end of def random_walk
#-------------------------------------------------------------------
def main():
print 'main is running...'
app = MyApp(0)
app.MainLoop()
#-------------------------------------------------------------------
if __name__ == "__main__" :
main()
#eof-------------------------------------------------------------------
This is the solution I came up with. Instead of using dc.DrawBitmap() to copy the buffered image to the screen I used Update() and Refresh() to trigger a paint event. However, what I still don't understand is why I cannot use DrawBitmap() to accomplish the same.
The only difference is that OnPaint() uses PaintDC() and in OnClick() I use ClientDC().
Anyways, this is my current code for OnClick():
def OnClick(self,event):
pos = event.GetPosition()
x = pos.x
y = pos.y
time_start = time.time()
memdc = wx.MemoryDC()
memdc.SelectObject(self.BufferBmp)
dcwi, dche = memdc.GetSizeTuple()
memdc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID))
runtime = 10
while (time.time() - time_start) < runtime:
x,y = random_walk(x,y,dcwi,dche)
memdc.SelectObject(self.BufferBmp)
memdc.DrawPoint(x,y)
memdc.SelectObject(wx.NullBitmap)
self.Update()
self.Refresh()
print jmtime() + 'Random walk in MyDrawingArea done'
Related
Here is my sample program. When I need to draw a line for x axis and y label for y axis .so can any one please help me how to add a line and lables to scene.i tried different ways but i didn't get the proper output.So please help me how to add labels to scene.Give me any suggestion to solve this task.Thank you in advance.
Given bellow is my tried code:
import sys
from pyface.qt import QtGui, QtCore
# class ScanView(QtGui.QGraphicsView):
# def __init__(self,X=5, Y=5,parent=None):
# super(ScanView, self).__init__(parent)
class DemoApp(QtGui.QMainWindow):
def __init__(self, parent=None):
super(DemoApp, self).__init__()
self.w= QtGui.QGridLayout()
self.v= QtGui.QGraphicsView()
self.w.addWidget(self.v)
self.widget = QtGui.QWidget()
self.widget.setLayout(self.w)
self.setCentralWidget(self.widget)
self._squares = []
n_rows, n_cols = 3, 2
squareLB = 50
label = QtGui.QLabel("xaxis")
label1 = QtGui.QLabel("yaxis")
self._scene = QtGui.QGraphicsScene()
mytext1 = QtGui.QGraphicsSimpleTextItem('label')
self._scene.addItem(mytext1)
mytext2 = QtGui.QGraphicsSimpleTextItem('label1')
self._scene.addItem(mytext2)
self.v.setScene(self._scene)
self.pen = QtGui.QPen(QtCore.Qt.DotLine)
self.pen.setColor(QtCore.Qt.red)
width, height = (2 + 2)*squareLB, (3 + 2)*squareLB
self._scene = QtGui.QGraphicsScene(0, 0, max(708, width), height)
p = squareLB if width > 708 else (708.0-2*squareLB)/2.0
for i in range(n_rows):
for j in range(n_cols):
it = self._scene.addRect(QtCore.QRectF(0,0,squareLB,squareLB),self.pen)
it.setPos(p + j*squareLB, i*squareLB)
self._squares.append(it)
self.v.setScene(self._scene)
class Settings(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Settings, self).__init__(parent)
self.folder = QtGui.QPushButton("Folder", clicked=self.showSettings)
central_widget = QtGui.QWidget()
self.setCentralWidget(central_widget)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(self.folder)
self.scrollArea = QtGui.QScrollArea(widgetResizable=True)
self.scrollArea.setBackgroundRole(QtGui.QPalette.Light)
hlay = QtGui.QHBoxLayout(central_widget)
hlay.addLayout(vbox)
hlay.addWidget(self.scrollArea)
self.setGeometry(200, 100, 300, 300)
def showSettings(self):
self.view = DemoApp()
self.newwidget = QtGui.QWidget()
hlay = QtGui.QHBoxLayout(self.newwidget)
hlay.addWidget(self.view)
self.scrollArea.setWidget(self.newwidget)
def main():
app = QtGui.QApplication(sys.argv)
ex = Settings()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You can use QpainterPath to draw the arrow and a little math to set the position:
class DemoApp(QtGui.QMainWindow):
def __init__(self, parent=None):
super(DemoApp, self).__init__()
self._squares = []
n_rows, n_cols = 5, 4
squareLB = 50
self.widget = QtGui.QWidget()
grid= QtGui.QGridLayout(self.widget)
self.v = QtGui.QGraphicsView()
grid.addWidget(self.v)
self.setCentralWidget(self.widget)
width, height = (2 + 2)*squareLB, (3 + 2)*squareLB
self._scene = QtGui.QGraphicsScene(0, 0, max(708, width), height)
self.v.setScene(self._scene)
pen = QtGui.QPen(QtCore.Qt.red, 0.0, QtCore.Qt.DotLine)
p = squareLB if width > 708 else (708.0-2*squareLB)/2.0
for i in range(n_rows):
for j in range(n_cols):
it = self._scene.addRect(QtCore.QRectF(0,0,squareLB,squareLB), pen)
it.setPos(p + j*squareLB, i*squareLB)
self._squares.append(it)
path_x = QtGui.QPainterPath()
path_x.lineTo(squareLB*n_cols/2, 0)
path_x.lineTo(squareLB*n_cols/2 - 0.2*squareLB, -0.2*squareLB)
path_x.lineTo(squareLB*n_cols/2, 0)
path_x.lineTo(squareLB*n_cols/2 - 0.2*squareLB, +0.2*squareLB)
pen = QtGui.QPen("green")
pen.setWidth(2)
item_path = self._scene.addPath(path_x, pen)
item_path.setPos(p, (i+1.2)*squareLB)
mytext1 = self._scene.addText("X")
mytext1.setPos(p + j*squareLB/2, (i+1.2)*squareLB)
path_y = QtGui.QPainterPath()
path_y.lineTo(0, -squareLB*n_rows/2)
path_y.lineTo(-0.2*squareLB, -squareLB*n_rows/2 + 0.2*squareLB)
path_y.lineTo(0, -squareLB*n_rows/2)
path_y.lineTo(+0.2*squareLB, -squareLB*n_rows/2 + 0.2*squareLB)
pen = QtGui.QPen("red")
pen.setWidth(2)
item_path = self._scene.addPath(path_y, pen)
item_path.setPos(p - 0.2*squareLB, (i+1)*squareLB)
mytext1 = self._scene.addText("Y")
mytext1.setPos(p - 0.7*squareLB, (i+1)*squareLB/2)
Lets say I have class Truck. There are many instances of this class, on arrival to specific point instance should "unload" it's cargo - simply not move for N seconds, while other trucks should keep moving, unless they arrived to their unloading points.
I do the stop part by setting movement vector to (0,0) and then resetting it back to original.
But how to wait N seconds without freezing other cars? From what I've found so far I think I need to somehow apply pygame.time.set_timer, but it is really confusing for me.
Something along these lines should work: Stop the truck when the target is reached (truck.vel = Vector2(0, 0)) and then set its waiting_time and start_time attributes (I just do it in the __init__ method here).
import pygame as pg
from pygame.math import Vector2
class Truck(pg.sprite.Sprite):
def __init__(self, pos, waiting_time, *groups):
super().__init__(*groups)
self.image = pg.Surface((50, 30))
self.image.fill(pg.Color('steelblue2'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.waiting_time = waiting_time # In seconds.
self.start_time = pg.time.get_ticks()
def update(self):
current_time = pg.time.get_ticks()
# * 1000 to convert to milliseconds.
if current_time - self.start_time >= self.waiting_time*1000:
# If the time is up, start moving again.
self.vel = Vector2(1, 0)
self.pos += self.vel
self.rect.center = self.pos
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
truck = Truck((70, 70), 4, all_sprites)
truck2 = Truck((70, 300), 2, all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Here's the dt version:
import pygame as pg
from pygame.math import Vector2
class Truck(pg.sprite.Sprite):
def __init__(self, pos, waiting_time, *groups):
super().__init__(*groups)
self.image = pg.Surface((50, 30))
self.image.fill(pg.Color('steelblue2'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.waiting_time = waiting_time
def update(self, dt):
self.waiting_time -= dt
if self.waiting_time <= 0:
self.vel = Vector2(1, 0)
self.pos += self.vel
self.rect.center = self.pos
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
truck = Truck((70, 70), 4, all_sprites)
truck2 = Truck((70, 300), 2, all_sprites)
done = False
while not done:
dt = clock.tick(30) / 1000
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.update(dt)
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
if __name__ == '__main__':
pg.init()
main()
pg.quit()
I copy a code from a Web page to Python 2.7 but I didn't success.
The code is:
# Raspbery Pi Color Tracking Project
# Code written by Oscar Liang
# 30 Jun 2013
import cv2.cv as cv
import smbus
bus = smbus.SMBus(1)
address = 0x04
def sendData(value):
bus.write_byte(address, value)
# bus.write_byte_data(address, 0, value)
return -1
def readData():
state = bus.read_byte(address)
# number = bus.read_byte_data(address, 1)
return state
def ColorProcess(img):
# returns thresholded image
imgHSV = cv.CreateImage(cv.GetSize(img), 8, 3)
# converts BGR image to HSV
cv.CvtColor(img, imgHSV, cv.CV_BGR2HSV)
imgProcessed = cv.CreateImage(cv.GetSize(img), 8, 1)
# converts the pixel values lying within the range to 255 and stores it in the destination
cv.InRangeS(imgHSV, (100, 94, 84), (109, 171, 143), imgProcessed)
return imgProcessed
def main():
# captured image size, change to whatever you want
width = 320
height = 240
capture = cv.CreateCameraCapture(0)
# Over-write default captured image size
cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,width)
cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,height)
cv.NamedWindow( “output”, 1 )
cv.NamedWindow( “processed”, 1 )
while True:
frame = cv.QueryFrame(capture)
cv.Smooth(frame, frame, cv.CV_BLUR, 3)
imgColorProcessed = ColorProcess(frame)
mat = cv.GetMat(imgColorProcessed)
# Calculating the moments
moments = cv.Moments(mat, 0)
area = cv.GetCentralMoment(moments, 0, 0)
moment10 = cv.GetSpatialMoment(moments, 1, 0)
moment01 = cv.GetSpatialMoment(moments, 0,1)
# Finding a big enough blob
if(area > 60000):
# Calculating the center postition of the blob
posX = int(moment10 / area)
posY = int(moment01 / area)
# check slave status and send coordinates
state = readData()
if state == 1:
sendData(posX)
sendData(posY)
print ‘x: ‘ + str(posX) + ‘ y: ‘ + str(posY)
# update video windows
cv.ShowImage(“processed”, imgColorProcessed)
cv.ShowImage(“output”, frame)
if cv.WaitKey(10) >= 0:
break
return;
if __name__ == “__main__”:
main()
I solved it. The right code is:
import cv2.cv as cv
import smbus
import cv2
bus = smbus.SMBus(1)
address = 0x04
def sendData(value):
bus.write_byte(address, value)
return -1
def readData():
state = bus.read_byte(address)
return state
def ColorProcess(img):
imgHSV = cv.CreateImage(cv.GetSize(img) ,8 ,3)
cv.CvtColor(img, imgHSV, cv.CV_BGR2HSV)
imgProcessed = cv.CreateImage(cv.GetSize(img) ,8 ,1)
cv.InRangeS(imgHSV, (100, 94, 84), (109, 171, 143), imgProcessed)
return imgProcessed
def main():
width = 320
height = 240
capture = cv.CreateCameraCapture(0)
cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH, width)
cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT, height)
cv.NamedWindow("output", 1)
cv.NamedWindow("processed", 1)
while True:
frame = cv.QueryFrame(capture)
cv.Smooth(frame, frame, cv.CV_BLUR, 3)
imgColorProcessed = ColorProcess(frame)
mat = cv.GetMat(imgColorProcessed)
moments = cv.Moments(mat, 0)
area = cv.GetCentralMoment(moments, 0, 0)
moment10 = cv.GetSpatialMoment(moments, 1, 0)
moment01 = cv.GetSpatialMoment(moments, 0, 1)
if (area > 60000):
posX = int(moment10/area)
posY = int(moment01/area)
ali = long(2000000)
state = readData()
if state == 1:
sendData(posX)
sendData(posY)
print 'x: ' + str(posX) + 'y: ' + str(posY)
cv.ShowImage("processed", imgColorProcessed)
cv.ShowImage("output", frame)
if cv.WaitKey(10) >= 0:
break
return;
if __name__ == "__main__":
main()
I'm trying to create a chat box, using tkinter, for real time chatting. But there is a problem in the GUI part (below) where I am getting this error:
NameError: global name 'action' is not defined
My code:
from Tkinter import *
from PIL import ImageTk,Image
class LoginFrame(Frame):
def action(event):
global EntryBox
global ChatLog
EntryBox.config(state=NORMAL)
EntryText = (EntryBox.get("0.0",END))
LoadMyEntry(ChatLog,EntryText)
EntryBox.delete("0.0",END)
def __init__(self, parent):
Frame.__init__(self, parent,background=("lavender blush"))
self.parent = parent
self.parent.title("Lets Gossip")
self.pack(fill=BOTH, expand=1)
w = 400
h = 500
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw - w)/2
y = (sh - h)/2
self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y))
ChatLog = Text(self, bd=0, bg="white", height="8", width="50", font="Arial",)
scrollbar = Scrollbar(self, command=ChatLog.yview, cursor="heart")
ChatLog['yscrollcommand'] = scrollbar.set
EntryBox = Text(self, bd=0, bg="white",width="29", height="5", font="Arial")
EntryBox.bind("<Return>",action)
EntryBox.bind("<KeyRelease-Return>")
scrollbar1 = Scrollbar(self, command=ChatLog.yview, cursor="heart")
EntryBox['yscrollcommand'] = scrollbar1.set
scrollbar.place(x=376,y=6, height=386)
ChatLog.place(x=6,y=6, height=386, width=370)
scrollbar1.place(x=376,y=401, height=90)
EntryBox.place(x=6, y=401, height=90, width=370)
self.pack()
root = Tk()
lf = LoginFrame(root)
root.mainloop()
I'm a bit new to python in terms of learning Tkinter and it's ability to code a GUI. As a result, I'm trying my hand at doing a simple JPEG image on a GUI using python 2.7.3. I've seen a number of different solutions using the "self" word and I think I understand the purpose. Unfortunately, that's now how my code is laid out since I'm kind of just coding as I think of stuff at the moment. Here is how my code is set up current:
from Tkinter import *
from random import randint
from PIL import Image, ImageTk
# Global root item for using TKinter
root = Tk()
PLAYER_IMAGE_PATH = 'Path_to_image'
# Player class
class Player:
playerHp = 0
playerAtk = 0
playerDef = 0
playerImg = ''
playerPositionX = 0
playerPositionY = 0
def __init__(self, hitpoints, attackPower, defensePower, pathToImage, positionX, positionY):
self.playerHp = hitpoints
self.playerAtk = attackPower
self.playerDef = defensePower
self.playerImg = pathToImage
self.playerPositionX = positionX
self.playerPositionY = positionY
# Method for building the frame.
def build_frame(screenHeight, screenWidth):
canvas = Canvas(root, bg = 'blue', height = screenHeight, width = screenWidth)
canvas.pack()
player = create_random_player()
display_player_image(canvas, player)
#display_player_stats(frame, player)
bind_all_keys(player)
# Key binding events.
def bind_all_keys(player):
root.bind('<Left>', lambda event, arg=player: left_key(event, arg))
root.bind('<Right>', lambda event, arg=player: right_key(event, arg))
root.bind('<Up>', lambda event, arg=player: up_key(event, arg))
root.bind('<Down>', lambda event, arg=player: down_key(event, arg))
def left_key(event, player):
print "Player coordinates(X,Y): " + str(player.playerPositionX) + "," + str(player.playerPositionY)
player.playerPositionX -= 1
def right_key(event, player):
print "Player coordinates(X,Y): " + str(player.playerPositionX) + "," + str(player.playerPositionY)
player.playerPositionX += 1
def up_key(event, player):
print "Player coordinates(X,Y): " + str(player.playerPositionX) + "," + str(player.playerPositionY)
player.playerPositionY -= 1
def down_key(event, player):
print "Player coordinates(X,Y): " + str(player.playerPositionX) + "," + str(player.playerPositionY)
player.playerPositionY += 1
# End key binding events.
def create_random_player():
return Player(randint(0,9), randint(0,9), randint(0,9), PLAYER_IMAGE_PATH, 0, 0)
def display_player_image(canvas, player):
canvas.create_rectangle(50, 50, 250, 100, fill = "green")
tkImage = ImageTk.PhotoImage(Image.open(player.playerImg))
canvas.create_image(100, 100, image = tkImage, anchor = NE)
def display_player_stats(frame, player):
hitPoints = Text(frame, height = 1)
hitPoints.insert(INSERT, "HP: " + str(player.playerHp))
hitPoints.pack()
attackPower = Text(frame, height = 1)
attackPower.insert(INSERT, "Attack: " + str(player.playerAtk))
attackPower.pack()
defensePower = Text(frame, height = 1)
defensePower.insert(INSERT, "Defense: " + str(player.playerDef))
defensePower.pack()
xPos = Text(frame, height = 1)
xPos.insert(INSERT, "X Pos: " + str(player.playerPositionX))
xPos.pack()
yPos = Text(frame, height = 1)
yPos.insert(INSERT, "Y Pos: " + str(player.playerPositionY))
yPos.pack()
# Main method. Calculates height at 70% then sets width to same height to create square on screen.
def main(root):
height = root.winfo_screenheight() * 0.7
width = height
build_frame(screenHeight = height, screenWidth = width)
root.mainloop()
# Entry method.
if __name__ == "__main__":
main(root)
So, you can see that I create a player class and set the path to the JPEG in the creat_random_player method. I create my canvas and proceed to try and create my image and nothing appears. I've tried a number of things and I know some people will come on here and say I need to pass "self" but I'm not sure how to do this as is. I appreciate any input people can offer because I'm at a bit of a loss.
Also, I'm aware this code is probably sloppy but it's a first pass and I will be cleaning it up as I continue to code but this is how it is now. Please refrain from comments on code structure unless there is no other way to code the solution except to change everything.
You're image is getting garbage collected by python's garbage collector. You need to save a reference to the image.
Here's a solution to get your playerImg to display
On your line(s)
def display_player_image(canvas, player):
canvas.create_rectangle(50, 50, 250, 100)
tkImage = ImageTk.PhotoImage(Image.open(player.playerImg))
canvas.create_image(100, 100, image = tkImage, anchor = NE)
player.playerImg = tkImage #Reference
there's other ways to save a reference in your code. This is just the quickest one i saw.