python class objects not drawing graphics window - python

I don't understand why the following code will not construct a graphics window with the circle. It does construct an object, but not graphically, when I run SomeObject = Tracker()
Why is that? This is a simple snippet of code, just for me to understand why I'm not getting a graphics window.
# tracker.py
from graphics import *
class Tracker:
def __inti__(self):
self.win = GraphWin('tracker', 500, 500)
self.circle = Circle(Point(0, 0), 0.5)
self.circle.draw(self.win)

You cannot see your circle because:
The radius of your circle (0.5) is too small
You placed the center of this small circle at (0, 0), which is at the top left corner
Your class's initializer was mispelled inti, hence the code was not called when you created your object.
Here is code that works:
from graphics import *
class Tracker:
def __init__(self):
# Window of size 500 x 500
self.win = GraphWin('tracker', 500, 500)
# Circle of radius 10 centered at (250, 250)
self.circle = Circle(Point(250, 250), 10)
self.circle.draw(self.win)
self.win.getMouse() # Pause to view result
self.win.close()
def main():
tracker = Tracker()
if __name__ == "__main__":
main()
Where graphics.py is presumably taken from this link.
I modified the sample code from the above link (which is probably also what you did) to call getMouse() to keep the window around.
The result is

Related

why does clearing this skia and glfw canvas result in black instead of transparent if the window is full screen?

I'm trying to use skia-python with glfw to draw various shapes and text onto a transparent floating overlay. I have a small demo working for my purposes, but it behaves differently if the window is created with full screen resolution versus created with anything smaller.
The code here alternates between drawing some red text or a green circle, and attempts to clear the canvas in between using canvas.clear(skia.ColorTRANSPARENT). This behaves exactly as I want if the window is created with dimensions anything less than 1920x1080 (the resolution of my screen). If I create the window with these full screen dimensions, instead of clearing the canvas this call fills the screen with black (and then the rest of the code still works, alternating between text and circle).
import contextlib, glfw, skia
from OpenGL import GL
import time
WIDTH, HEIGHT = 1920, 1080
#WIDTH, HEIGHT = 1919, 1079
#contextlib.contextmanager
def glfw_window():
if not glfw.init():
raise RuntimeError('glfw.init() failed')
glfw.window_hint(glfw.STENCIL_BITS, 8) # ?
glfw.window_hint(glfw.SAMPLES, 14) # ?
glfw.window_hint(glfw.DECORATED, 0)
glfw.window_hint(glfw.TRANSPARENT_FRAMEBUFFER, 1)
glfw.window_hint(glfw.FLOATING, 1)
window = glfw.create_window(WIDTH, HEIGHT, '', None, None)
glfw.make_context_current(window)
yield window
glfw.terminate()
#contextlib.contextmanager
def skia_surface(window):
context = skia.GrDirectContext.MakeGL()
(fb_width, fb_height) = glfw.get_framebuffer_size(window)
backend_render_target = skia.GrBackendRenderTarget(
fb_width,
fb_height,
0, # sampleCnt
0, # stencilBits
skia.GrGLFramebufferInfo(0, GL.GL_RGBA8))
surface = skia.Surface.MakeFromBackendRenderTarget(
context, backend_render_target, skia.kBottomLeft_GrSurfaceOrigin,
skia.kRGBA_8888_ColorType, skia.ColorSpace.MakeSRGB())
assert surface is not None
yield surface
context.abandonContext()
def drawString(canvas):
paint = skia.Paint(AntiAlias=True, Color=skia.ColorRED)
font = skia.Font(skia.Typeface('meiryo'), 36)
canvas.drawString('あかさたな', 100, 100, font, paint)
def drawCircle(canvas):
paint = skia.Paint(Color=skia.ColorGREEN)
canvas.drawCircle(100, 100, 40, paint)
with glfw_window() as window:
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
with skia_surface(window) as surface:
with surface as canvas:
while (glfw.get_key(window, glfw.KEY_ESCAPE) != glfw.PRESS
and not glfw.window_should_close(window)):
canvas.clear(skia.ColorTRANSPARENT)
if int(time.time()) % 2 == 0:
drawString(canvas)
else:
drawCircle(canvas)
surface.flushAndSubmit()
glfw.swap_buffers(window)
glfw.poll_events()
#glfw.wait_events()
For the purpose of demonstration, this is the entire working demo. Most of it comes from this skia-python documentation. I think the only packages it needs are glfw (2.5.3), PyOpenGl (3.1.6), and skia-python (87.4)
My actual use case will use a slightly different loop and doesn't need to draw to the screen as frequently as this demo, but it does need to periodically clear the canvas. I don't actually need it to be perfectly full screen, I can use 1919x1079, mostly I'm just curious what's going on here. This is being tested on Windows 10 with Python 3.10 by the way

Make multiple shapes work together in Zelle Graphics

I'm a beginner in Python and I'm using the Zelle's Graphics library. I wish to draw multiple shapes and make them behave as one. For example, I might call a group of shapes 'x' and when I use the builtin move() method the entire collection of shapes move.
The solution I envision is a new GraphicsObject that is actually a group of graphics objects. Below is a skeletal example with just enough code to demonstrate the idea:
from graphics import *
class GraphicsGroup(GraphicsObject):
def __init__(self):
super().__init__(options=[])
self.components = []
def draw(self, graphwin):
for component in self.components:
component.draw(graphwin)
return self
def move(self, dx, dy):
for component in self.components:
component.move(dx, dy)
def add_component(self, component):
if isinstance(component, GraphicsObject):
self.components.append(component)
win = GraphWin("Group Test", 200, 200)
# Some example objects borrowed from graphics.py source docstrings
text = Text(Point(35, 35), "Centered Text")
polygon = Polygon(Point(10, 10), Point(50, 30), Point(20, 70))
circle = Circle(Point(50, 50), 10)
rectangle = Rectangle(Point(25, 60), Point(60, 25))
group = GraphicsGroup()
group.add_component(text)
group.add_component(polygon)
group.add_component(circle)
group.add_component(rectangle)
group.draw(win)
win.getMouse() # Pause to view result
group.move(100, 100)
win.getMouse() # Pause to view result
win.close()
Since GraphicsGroup isn't really a graphic object itself, we override draw and move instead of _draw and _move like a proper graphics entity.

Changing a rectangle's X value does not actually move it in the GUI

I'm working on a GUI in Python with PySide2. I have a GraphicsView, where I'll put an image, and I'd like to draw and move a polygon around on that image. I've found many examples of simply drawing polygons, circles, etc. in PySide, PySide2, or PyQt 4/5 in Python. However, I haven't been able to figure out why my graphics items do not move on an event without deleting and redrawing.
I'm using the keyboard to change the X value on a PySide2 QRectF. The X value is clearly changing, but the rectangle does not actually move.
Here is a minimal example:
from PySide2 import QtCore, QtGui, QtWidgets
from functools import partial
class DebuggingDrawing(QtWidgets.QGraphicsView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# initialize the scene and set the size
self._scene = QtWidgets.QGraphicsScene(self)
self._scene.setSceneRect(0,0,500,500)
self.setScene(self._scene)
# make a green pen and draw a 10 wide, 20 high rectangle at x=20, y=30
self.pen = QtGui.QPen(QtCore.Qt.green, 0)
self.draw_rect = QtCore.QRectF(20, 30, 10, 20)
# add the rectangle to our scene
self._scene.addRect(self.draw_rect, self.pen)
def move_rect(self, dx: int):
# method for moving the existing rectangle
# get the x value
x = self.draw_rect.x()
print('x: {} dx: {}'.format(x, dx))
# use the moveLeft method of QRectF to change the rectangle's left side x value
self.draw_rect.moveLeft(x + dx)
self.update()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.labelImg = DebuggingDrawing()
# Get a keyboard shortcut and hook it up to the move_rect method
next_shortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Right'), self)
next_shortcut.activated.connect(partial(self.labelImg.move_rect, 1))
# get the left key shortcut, move_rect one pixel left
back_shortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Left'), self)
back_shortcut.activated.connect(partial(self.labelImg.move_rect, -1))
self.setCentralWidget(self.labelImg)
self.setMaximumHeight(480)
self.update()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
testing = MainWindow()
testing.show()
app.exec_()
Here's what the output looks like:
You clearly can't see in the image, but even though the rectangle's x value is changing according to our print calls, nothing moves around in the image. I've confirmed it's not just my eyes, because if I draw new rectangles in move_rect, they clearly show up.
draw_rect is a QRectF is an input to create an item(QGraphicsRectItem) that is returned by the addRect() method similar to pen, that is, it takes the information but then no longer uses it. The idea is to move the item using setPos():
class DebuggingDrawing(QtWidgets.QGraphicsView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# initialize the scene and set the size
self._scene = QtWidgets.QGraphicsScene(self)
self._scene.setSceneRect(0, 0, 500, 500)
self.setScene(self._scene)
# make a green pen and draw a 10 wide, 20 high rectangle at x=20, y=30
pen = QtGui.QPen(QtCore.Qt.green, 0)
draw_rect = QtCore.QRectF(20, 30, 10, 20)
# add the rectangle to our scene
self.item_rect = self._scene.addRect(draw_rect, pen)
def move_rect(self, dx: int):
p = self.item_rect.pos()
p += QtCore.QPointF(dx, 0)
self.item_rect.setPos(p)
If you still want to use draw_rect then you have to set it again in the item:
self.pen = QtGui.QPen(QtCore.Qt.green, 0)
self.draw_rect = QtCore.QRectF(20, 30, 10, 20)
# add the rectangle to our scene
self.item_rect = self._scene.addRect(self.draw_rect, self.pen)
def move_rect(self, dx: int):
# method for moving the existing rectangle
# get the x value
x = self.draw_rect.x()
print('x: {} dx: {}'.format(x, dx))
# use the moveLeft method of QRectF to change the rectangle's left side x value
self.draw_rect.moveLeft(x + dx)
self.item_rect.setRect(self.draw_rect)
It is recommended that "Graphics View Framework" be read so that the QGraphicsItems, QGraphicsView and QGraphicsScene work.

Turtle in Tkinter creating multiple windows

I am attempting to create a quick turtle display using Tkinter, but some odd things are happening.
First two turtle windows are being created, (one blank, one with the turtles), secondly, any attempt of turning the tracer off is not working.
This might be a simple fix but at the moment I cannot find it.
Any help would be appreciated,
Below is the code:
import tkinter as tk
import turtle
window = tk.Tk()
window.title('Top 10\'s')
def loadingscreen():
canvas = tk.Canvas(master = window, width = 500, height = 500)
canvas.pack()
arc1 = turtle.RawTurtle(canvas)
arc2 = turtle.RawTurtle(canvas)
#clean up the turtles and release the window
def cleanup():
turtle.tracer(True)
arc1.ht()
arc2.ht()
turtle.done()
#animate the turtles
def moveTurtles(rangevar,radius,extent,decrease):
for distance in range(rangevar):
arc1.circle(-radius,extent = extent)
arc2.circle(-radius,extent = extent)
radius -= decrease
#Set the turtle
def setTurtle(turt,x,y,heading,pensize,color):
turt.pu()
turt.goto(x,y)
turt.pd()
turt.seth(heading)
turt.pensize(pensize)
turt.pencolor(color)
#draw on the canvas
def draw():
#set variables
rangevar = 200
radius = 200
decrease = 1
extent = 2
#setup and draw the outline
turtle.tracer(False)
setTurtle(arc1,0,200,0,40,'grey')
setTurtle(arc2,14,-165,180,40,'grey')
moveTurtles(rangevar,radius,extent,decrease)
#setup and animate the logo
turtle.tracer(True)
setTurtle(arc1,0,200,0,20,'black')
setTurtle(arc2,14,-165,180,20,'black')
moveTurtles(rangevar,radius,extent,decrease)
#main program
def main():
turtle.tracer(False)
arc1.speed(0)
arc2.speed(0)
draw()
cleanup()
if __name__ == "__main__":
try:
main()
except:
print("An error occurred!!")
loadingscreen()
Essentially I am creating a Tk window, then a canvas, then two turtles, and then animating these turtles
My guess is you're trying to call turtle screen methods without actually having a turtle screen. When turtle is embedded in tkinter like this, you can overlay a Canvas with a TurtleScreen instance which will provide some, but not all, of the screen features of the standalone turtle:
import tkinter as tk
from turtle import RawTurtle, TurtleScreen
def cleanup():
""" hide the turtles """
arc1.hideturtle()
arc2.hideturtle()
def moveTurtles(rangevar, radius, extent, decrease):
""" animate the turtles """
for _ in range(rangevar):
arc1.circle(-radius, extent=extent)
arc2.circle(-radius, extent=extent)
radius -= decrease
def setTurtle(turtle, x, y, heading, pensize, color):
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
turtle.setheading(heading)
turtle.pensize(pensize)
turtle.pencolor(color)
def draw():
# set variables
rangevar = 200
radius = 200
decrease = 1
extent = 2
screen.tracer(False) # turn off animation while drawing outline
# setup and draw the outline
setTurtle(arc1, 0, 200, 0, 40, 'grey')
setTurtle(arc2, 14, -165, 180, 40, 'grey')
moveTurtles(rangevar, radius, extent, decrease)
screen.tracer(True) # turn animation back on for the following
# setup and animate the logo
setTurtle(arc1, 0, 200, 0, 20, 'black')
setTurtle(arc2, 14, -165, 180, 20, 'black')
moveTurtles(rangevar, radius, extent, decrease)
# main program
window = tk.Tk()
window.title("Top 10's")
canvas = tk.Canvas(master=window, width=500, height=500)
canvas.pack()
screen = TurtleScreen(canvas)
arc1 = RawTurtle(screen)
arc1.speed('fastest')
arc2 = RawTurtle(screen)
arc2.speed('fastest')
draw()
cleanup()
Another suggestion: don't mess with tracer() until after everything else is working and then (re)read it's documentation carefully.
I just have the answer for the two windows that are being created: the one with the turtles is obvious, and the blank one is for the main root window that you define (window = tk.Tk()). If you want it not to appear at all, you can add the following line right after its definition:
window.withdraw()
I found this solution here and here.

How to resize GraphWin window?

I'm using Zelle's graphics library to do some online coursework. Part of the assignment I'm working on seems to assume I can resize an existing GraphWin window. But this hasn't been touched on previously in the course, and looking over the documentation for graphics.py I don't see a way to accomplish this. I poked around a GraphWin object, and nothing seems to alter the window's size. Is it possible to resize a GraphWin window?
I've tried:
from graphics import *
new_win = GraphWin('Test', 300, 300)
new_win.setCoords(0, 0, 100, 200)
new_win.width = 100
The setCoords() method just creates a new virtual coordinate system within an existing window.
We might be able to achieve sufficent functionality for your purpose by dropping down to the tkinter level and specializing GraphWin:
from graphics import *
class ResizeableGraphWin(GraphWin):
""" A resizeable toplevel window for Zelle graphics. """
def __init__(self, title="Graphics Window", width=200, height=200, autoflush=True):
super().__init__(title, width, height, autoflush)
self.pack(fill="both", expand=True) # repack?
def resize(self, width=200, height=200):
self.master.geometry("{}x{}".format(width, height))
self.height = int(height)
self.width = int(width)
# test code
win = ResizeableGraphWin("My Circle", 100, 100)
win.setBackground('green')
c = Circle(Point(75, 75), 50)
c.draw(win) # should only see part of circle
win.getMouse() # pause for click in window
win.resize(200, 400) # should now see all of circle
win.getMouse() # pause for click in window
c.move(25, 125) # center circle in newly sized window
win.getMouse() # pause for click in window
c.setFill('red') # modify cirlce
win.getMouse() # pause for click in window
win.close()
A Python 3 implementation since I called super(). It can probably be retrofit for Python 2.
Zelle's graphics library does not have a method for resizing a window after it has been drawn.
I just found out how to do it
from graphics import *
win= GraphWin("Person",400,400)

Categories

Resources