I'm trying to write a simple CLI python text editor using curses module that comes with python. I have everything set up correctly on my Windows 10 box and can do all the tutorials without issue.
I draw in the order, the screen, and windows on the screen with a border less than the screen. Create a window using the border measurements that are in 2 rows, columns in from the outside of the screen. Then I define a text area and create a subwindow.
If I exclude the subwindow, a border is drawn and the cursor placed inside the border. But when I try to save the text by gathering it the text includes the border. So, that is the reason for the subwindow. If he box is larger than subwindow why would the border disappear.
Here is the code:
import curses
import traceback
from curses.textpad import Textbox, rectangle
from pathlib import Path
def draw_menu():
pass
def edit_mode(window):
textbox = Textbox(window)
textbox.edit()
return textbox.gather()
def main(screen):
"""
Get the screen size and set a border around the text area.
Reset the cursor to the top of the text area.
"""
# get the current screen size
y_max, x_max = screen.getmaxyx()
ymin_border, xmin_border, ymax_border, xmax_border = \
2, 2, y_max-2, x_max-2
ymin_textpad, xmin_textpad, ymax_textpad, xmax_textpad = \
ymin_border+1, xmin_border+1, ymax_border-1, xmax_border-1
# draw the windows and box around it. Place cursor at beginning of
# the edit area
window = curses.newwin(ymax_border, xmax_border, ymin_border, xmin_border)
window.box()
# if this line is excluded I see the box but then the box is saved input
text_box = screen.subwin(ymax_textpad, xmax_textpad, ymin_textpad,
xmin_textpad)
window.addstr(ymin_textpad, xmin_textpad, "")
screen.refresh()
text = edit_mode(text_box) # right now drop user into edit mode
return text
if __name__ == "__main__":
buffer = ""
try:
screen = curses.initscr()
curses.noecho()
buffer = main(screen)
curses.echo()
curses.endwin()
print(f"Saved Buffer to Screen\n{buffer}")
except:
curses.echo()
curses.endwin()
traceback.print_exc()
Related
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
I wish to have an image in my GTK app that continually resizes to fit its parent container.
I've accomplished this by getting the parent container's size inside a size-allocate event callback, and resizing my image according to those dimensions. This works fine when I'm making the window smaller, but when I want to make it bigger, it refuses to resize because it has to be at least as big as the contents (the image).
To overcome that aspect, I've placed the image in a ScrolledWindow so that I can freely resize my window smaller.
The issue lies in that when I switch the image shown to one with different dimensions, the ScrolledWindow doesn't seem to realize it, and I'm left with a ScrolledWindow with the wrong content size and unnecessary scroll bars. But alas, I can hover over the scroll bar and it realizes that it's too big for its content and removes the scroll bars. See the below demonstration.
Can I somehow have this "correction" behavior happen right away instead of when I hover over the scroll bars?
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import GdkPixbuf
class Minimal(Gtk.Window):
imageShown = 0
img = Gtk.Image.new()
pixbufRed = GdkPixbuf.Pixbuf.new_from_file("kirby_red.png")
pixbufBlue = GdkPixbuf.Pixbuf.new_from_file("kirby_blue.png")
pixbuf = None
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(400,300)
button = Gtk.Button.new_with_label("Swap Image")
button.connect("clicked", self.on_button_click)
self.pixbuf = self.pixbufRed
self.img.set_from_pixbuf(self.pixbuf)
scrolled = Gtk.ScrolledWindow()
scrolled.connect("size-allocate", self.on_size_allocated);
scrolled.add(self.img)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,spacing=0)
box.pack_start(button, False, False, 0)
box.pack_end(scrolled, True, True, 0)
self.add(box)
#swap image shown using imageShown flag to keep track
def on_button_click(self, button):
if(self.imageShown == 0):
self.pixbuf = self.pixbufBlue
self.imageShown = 1
else:
self.pixbuf = self.pixbufRed
self.imageShown = 0
self.img.set_from_pixbuf(self.pixbuf)
def on_size_allocated(self, widget, allocation):
scaledPixbuf = Minimal.scale_image_from_allocation_keep_aspect(self.pixbuf, allocation)
self.img.set_from_pixbuf(scaledPixbuf)
#staticmethod
def scale_image_from_allocation_keep_aspect(pixbuf, allocation):
imgWidth = pixbuf.get_width()
imgHeight = pixbuf.get_height()
parentWidth = allocation.width
parentHeight = allocation.height
aspectWidth = parentWidth/imgWidth
aspectHeight= parentHeight/imgHeight
aspect=0
if(aspectWidth < aspectHeight):
aspect = aspectWidth
else:
aspect = aspectHeight
newWidth = imgWidth*aspect
newHeight = imgHeight*aspect
return pixbuf.scale_simple(newWidth, newHeight, GdkPixbuf.InterpType.BILINEAR)
win = Minimal()
win.show_all()
Gtk.main()
size-allocate isn't really the right place to be changing the contents of your widget (like changing the image widget's pixbuf), and it usually doesn't work correctly if you try to use it like that. It's intended more for custom container widgets to layout their children once the size is already determined.
In GTK 3, I usually solve the problem of making images fill the available space by creating a very simple custom widget, like this:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf, Gdk
class ScaleImage(Gtk.DrawingArea):
def __init__(self, pixbuf):
Gtk.DrawingArea.__init__(self)
self.pixbuf = pixbuf
def do_draw(self, cr):
alloc, baseline = self.get_allocated_size()
factor = min(alloc.width / self.pixbuf.get_width(), alloc.height / self.pixbuf.get_height())
cr.scale(factor, factor)
Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0)
cr.paint()
win = Gtk.Window()
img = ScaleImage(GdkPixbuf.Pixbuf.new_from_file("file.png"))
win.add(img)
win.show_all()
Gtk.main()
I haven't tried it yet, but in GTK 4 you should be able to use Gtk.Picture to get the same effect without a custom widget.
I am making a tutorial to explain things to others. For that tutorial i am trying to make a python program (which is like the paint app)
Which we all use in windows. To draw with pen,brush and to draw shapes like square,circle and have a option for color piker to choose colour to draw.
I already tried with the from tkinter import choosecolor to create paint like software in python.
But with that it draws only on a tkinter canvas.
But i don't want to draw on a canvas i want to draw it on live screen while i make the tutorial.
example image is shown below
I am trying to make a gui window like this to choose color and pen tool to draw on the screen (eg.desktop,web browser etc).
Can anyone give me some suggestion on how can i draw like this on my desktop screen or on any window.
Although in your video,it seems that " draw directly on screen ".Actually,I think it didn't.
There is a easy example to "draw on the screen",You can modify it:
import tkinter as tk
from PIL import ImageGrab,ImageTk
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(2) # windows 10
class ToolWin(tk.Toplevel):
def __init__(self):
tk.Toplevel.__init__(self)
self._offsetx = 0
self._offsety = 0
self.wm_attributes('-topmost',1)
self.penSelect = tk.BooleanVar()
self.overrideredirect(1)
self.geometry('200x200')
self.penModeId = None
self.bind('<ButtonPress-1>',self.clickTool)
self.bind('<B1-Motion>',self.moveTool) # bind move event
draw = tk.Checkbutton(self,text="Pen",command=self.penDraw,variable=self.penSelect)
draw.pack()
cancel = tk.Button(self,text="Quit",command=root.destroy)
cancel.pack()
def moveTool(self,event):
self.geometry("200x200+{}+{}".format(self.winfo_pointerx()-self._offsetx,self.winfo_pointery()-self._offsety))
def clickTool(self,event):
self._offsetx = event.x
self._offsety = event.y
def penDraw(self):
if self.penSelect.get():
self.penModeId = root.bind("<B1-Motion>",Draw)
else:
root.unbind('<B1-Motion>',self.penModeId)
def Draw(event):# r = 3
fullCanvas.create_oval(event.x-3,event.y-3,event.x+3,event.y+3,fill="black")
def showTool(): # the small tool window
toolWin = ToolWin()
toolWin.mainloop()
root = tk.Tk()
root.state('zoomed')
root.overrideredirect(1)
fullCanvas = tk.Canvas(root)
background = ImageTk.PhotoImage(ImageGrab.grab(all_screens=True)) # show the background,make it "draw on the screen".
fullCanvas.create_image(0,0,anchor="nw",image=background)
fullCanvas.pack(expand="YES",fill="both")
root.after(100,showTool)
root.mainloop()
Also,you can move the toolbar by dragging it.
(PS: I think you nearly finished it.)
# The imports include turtle graphics and tkinter modules.
# The colorchooser and filedialog modules let the user
# pick a color and a filename.
import turtle
import tkinter
import tkinter.colorchooser
import tkinter.filedialog
import xml.dom.minidom
# The following classes define the different commands that
# are supported by the drawing application.
class GoToCommand:
def __init__(self,x,y,width=1,color="black"):
self.x = x
self.y = y
self.width = width
self.color = color
# The draw method for each command draws the command
# using the given turtle
def draw(self,turtle):
turtle.width(self.width)
turtle.pencolor(self.color)
turtle.goto(self.x,self.y)
# The __str__ method is a special method that is called
# when a command is converted to a string. The string
# version of the command is how it appears in the graphics
# file format.
def __str__(self):
return '<Command x="' + str(self.x) + '" y="' + str(self.y) + \
'" width="' + str(self.width) \
+ '" color="' + self.color + '">GoTo</Command>'
class CircleCommand:
def __init__(self,radius, width=1,color="black"):
self.radius = radius
self.width = width
self.color = color
def draw(self,turtle):
turtle.width(self.width)
turtle.pencolor(self.color)
turtle.circle(self.radius)
def __str__(self):
return '<Command radius="' + str(self.radius) + '" width="' + \
str(self.width) + '" color="' + self.color + '">Circle</Command>'
class TextCommand:
def __init__(self, move=False, align="left", font=("Arial", 8, "normal")):
self.move = move
self.align = align
self.font = font
def draw(self,turtle):
#turtle.write("test",self.move,self.align,self.font)
turtle.move(self.move)
turtle.align(self.align)
turtle.font(self.font)
def __str__(self):
return '<Command TODO ENTER COMMAND>'
class BeginFillCommand:
def __init__(self,color):
self.color = color
def draw(self,turtle):
turtle.fillcolor(self.color)
turtle.begin_fill()
def __str__(self):
return '<Command color="' + self.color + '">BeginFill</Command>'
class EndFillCommand:
def __init__(self):
pass
def draw(self,turtle):
turtle.end_fill()
def __str__(self):
return "<Command>EndFill</Command>"
class PenUpCommand:
def __init__(self):
pass
def draw(self,turtle):
turtle.penup()
def __str__(self):
return "<Command>PenUp</Command>"
class PenDownCommand:
def __init__(self):
pass
def draw(self,turtle):
turtle.pendown()
def __str__(self):
return "<Command>PenDown</Command>"
# This is the PyList container object. It is meant to hold a
class PyList:
def __init__(self):
self.gcList = []
# The append method is used to add commands to the sequence.
def append(self,item):
self.gcList = self.gcList + [item]
# This method is used by the undo function. It slices the sequence
# to remove the last item
def removeLast(self):
self.gcList = self.gcList[:-1]
# This special method is called when iterating over the sequence.
# Each time yield is called another element of the sequence is returned
# to the iterator (i.e. the for loop that called this.)
def __iter__(self):
for c in self.gcList:
yield c
# This is called when the len function is called on the sequence.
def __len__(self):
return len(self.gcList)
# This class defines the drawing application. The following line says that
# the DrawingApplication class inherits from the Frame class. This means
# that a DrawingApplication is like a Frame object except for the code
# written here which redefines/extends the behavior of a Frame.
class DrawingApplication(tkinter.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.buildWindow()
self.graphicsCommands = PyList()
# This method is called to create all the widgets, place them in the GUI,
# and define the event handlers for the application.
def buildWindow(self):
# The master is the root window. The title is set as below.
self.master.title("Draw")
# Here is how to create a menu bar. The tearoff=0 means that menus
# can't be separated from the window which is a feature of tkinter.
bar = tkinter.Menu(self.master)
fileMenu = tkinter.Menu(bar,tearoff=0)
# This code is called by the "New" menu item below when it is selected.
# The same applies for loadFile, addToFile, and saveFile below. The
# "Exit" menu item below calls quit on the "master" or root window.
def newWindow():
# This sets up the turtle to be ready for a new picture to be
# drawn. It also sets the sequence back to empty. It is necessary
# for the graphicsCommands sequence to be in the object (i.e.
# self.graphicsCommands) because otherwise the statement:
# graphicsCommands = PyList()
# would make this variable a local variable in the newWindow
# method. If it were local, it would not be set anymore once the
# newWindow method returned.
theTurtle.clear()
theTurtle.penup()
theTurtle.goto(0,0)
theTurtle.pendown()
screen.update()
screen.listen()
self.graphicsCommands = PyList()
fileMenu.add_command(label="New",command=newWindow)
# The parse function adds the contents of an XML file to the sequence.
def parse(filename):
xmldoc = xml.dom.minidom.parse(filename)
graphicsCommandsElement = xmldoc.getElementsByTagName("GraphicsCommands")[0]
graphicsCommands = graphicsCommandsElement.getElementsByTagName("Command")
for commandElement in graphicsCommands:
print(type(commandElement))
command = commandElement.firstChild.data.strip()
attr = commandElement.attributes
if command == "GoTo":
x = float(attr["x"].value)
y = float(attr["y"].value)
width = float(attr["width"].value)
color = attr["color"].value.strip()
cmd = GoToCommand(x,y,width,color)
elif command == "Circle":
radius = float(attr["radius"].value)
width = float(attr["width"].value)
color = attr["color"].value.strip()
cmd = CircleCommand(radius,width,color)
elif command == "BeginFill":
color = attr["color"].value.strip()
cmd = BeginFillCommand(color)
elif command == "EndFill":
cmd = EndFillCommand()
elif command == "PenUp":
cmd = PenUpCommand()
elif command == "PenDown":
cmd = PenDownCommand()
else:
raise RuntimeError("Unknown Command: " + command)
self.graphicsCommands.append(cmd)
def loadFile():
filename = tkinter.filedialog.askopenfilename(title="Select a Graphics File")
newWindow()
# This re-initializes the sequence for the new picture.
self.graphicsCommands = PyList()
# calling parse will read the graphics commands from the file.
parse(filename)
for cmd in self.graphicsCommands:
cmd.draw(theTurtle)
# This line is necessary to update the window after the picture is drawn.
screen.update()
fileMenu.add_command(label="Load...",command=loadFile)
def addToFile():
filename = tkinter.filedialog.askopenfilename(title="Select a Graphics File")
theTurtle.penup()
theTurtle.goto(0,0)
theTurtle.pendown()
theTurtle.pencolor("#000000")
theTurtle.fillcolor("#000000")
cmd = PenUpCommand()
self.graphicsCommands.append(cmd)
cmd = GoToCommand(0,0,1,"#000000")
self.graphicsCommands.append(cmd)
cmd = PenDownCommand()
self.graphicsCommands.append(cmd)
screen.update()
parse(filename)
for cmd in self.graphicsCommands:
cmd.draw(theTurtle)
screen.update()
fileMenu.add_command(label="Load Into...",command=addToFile)
# The write function writes an XML file to the given filename
def write(filename):
file = open(filename, "w")
file.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')
file.write('<GraphicsCommands>\n')
for cmd in self.graphicsCommands:
file.write(' '+str(cmd)+"\n")
file.write('</GraphicsCommands>\n')
file.close()
def saveFile():
filename = tkinter.filedialog.asksaveasfilename(title="Save Picture As...")
write(filename)
fileMenu.add_command(label="Save As...",command=saveFile)
fileMenu.add_command(label="Exit",command=self.master.quit)
bar.add_cascade(label="File",menu=fileMenu)
# This tells the root window to display the newly created menu bar.
self.master.config(menu=bar)
# Here several widgets are created. The canvas is the drawing area on
# the left side of the window.
canvas = tkinter.Canvas(self,width=600,height=600)
canvas.pack(side=tkinter.LEFT)
# By creating a RawTurtle, we can have the turtle draw on this canvas.
# Otherwise, a RawTurtle and a Turtle are exactly the same.
theTurtle = turtle.RawTurtle(canvas)
# This makes the shape of the turtle a circle.
theTurtle.shape("circle")
screen = theTurtle.getscreen()
# This causes the application to not update the screen unless
# screen.update() is called. This is necessary for the ondrag event
# handler below. Without it, the program bombs after dragging the
# turtle around for a while.
screen.tracer(0)
# This is the area on the right side of the window where all the
# buttons, labels, and entry boxes are located. The pad creates some empty
# space around the side. The side puts the sideBar on the right side of the
# this frame. The fill tells it to fill in all space available on the right
# side.
sideBar = tkinter.Frame(self,padx=5,pady=5)
sideBar.pack(side=tkinter.RIGHT, fill=tkinter.BOTH)
# This is a label widget. Packing it puts it at the top of the sidebar.
pointLabel = tkinter.Label(sideBar,text="Width")
pointLabel.pack()
# This entry widget allows the user to pick a width for their lines.
# With the widthSize variable below you can write widthSize.get() to get
# the contents of the entry widget and widthSize.set(val) to set the value
# of the entry widget to val. Initially the widthSize is set to 1. str(1) is
# needed because the entry widget must be given a string.
widthSize = tkinter.StringVar()
widthEntry = tkinter.Entry(sideBar,textvariable=widthSize)
widthEntry.pack()
widthSize.set(str(1))
radiusLabel = tkinter.Label(sideBar,text="Radius")
radiusLabel.pack()
radiusSize = tkinter.StringVar()
radiusEntry = tkinter.Entry(sideBar,textvariable=radiusSize)
radiusSize.set(str(10))
radiusEntry.pack()
# A button widget calls an event handler when it is pressed. The circleHandler
# function below is the event handler when the Draw Circle button is pressed.
def circleHandler():
# When drawing, a command is created and then the command is drawn by calling
# the draw method. Adding the command to the graphicsCommands sequence means the
# application will remember the picture.
cmd = CircleCommand(float(radiusSize.get()), float(widthSize.get()), penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
# These two lines are needed to update the screen and to put the focus back
# in the drawing canvas. This is necessary because when pressing "u" to undo,
# the screen must have focus to receive the key press.
screen.update()
screen.listen()
def textHandler():
# When drawing, a command is created and then the command is drawn by calling
# the draw method. Adding the command to the graphicsCommands sequence means the
# application will remember the picture.
cmd = TextCommand(False, penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
# These two lines are needed to update the screen and to put the focus back
# in the drawing canvas. This is necessary because when pressing "u" to undo,
# the screen must have focus to receive the key press.
screen.update()
screen.listen()
# This creates the button widget in the sideBar. The fill=tkinter.BOTH causes the button
# to expand to fill the entire width of the sideBar.
circleButton = tkinter.Button(sideBar, text = "Draw Circle", command=circleHandler)
circleButton.pack(fill=tkinter.BOTH)
textButton = tkinter.Button(sideBar, text = "Draw Text", command=textHandler)
textButton.pack(fill=tkinter.BOTH)
# The color mode 255 below allows colors to be specified in RGB form (i.e. Red/
# Green/Blue). The mode allows the Red value to be set by a two digit hexadecimal
# number ranging from 00-FF. The same applies for Blue and Green values. The
# color choosers below return a string representing the selected color and a slice
# is taken to extract the #RRGGBB hexadecimal string that the color choosers return.
screen.colormode(255)
penLabel = tkinter.Label(sideBar,text="Pen Color")
penLabel.pack()
penColor = tkinter.StringVar()
penEntry = tkinter.Entry(sideBar,textvariable=penColor)
penEntry.pack()
# This is the color black.
penColor.set("#000000")
def getPenColor():
color = tkinter.colorchooser.askcolor()
if color != None:
penColor.set(str(color)[-9:-2])
penColorButton = tkinter.Button(sideBar, text = "Pick Pen Color", command=getPenColor)
penColorButton.pack(fill=tkinter.BOTH)
fillLabel = tkinter.Label(sideBar,text="Fill Color")
fillLabel.pack()
fillColor = tkinter.StringVar()
fillEntry = tkinter.Entry(sideBar,textvariable=fillColor)
fillEntry.pack()
fillColor.set("#000000")
def getFillColor():
color = tkinter.colorchooser.askcolor()
if color != None:
fillColor.set(str(color)[-9:-2])
fillColorButton = \
tkinter.Button(sideBar, text = "Pick Fill Color", command=getFillColor)
fillColorButton.pack(fill=tkinter.BOTH)
def beginFillHandler():
cmd = BeginFillCommand(fillColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
beginFillButton = tkinter.Button(sideBar, text = "Begin Fill", command=beginFillHandler)
beginFillButton.pack(fill=tkinter.BOTH)
def endFillHandler():
cmd = EndFillCommand()
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
endFillButton = tkinter.Button(sideBar, text = "End Fill", command=endFillHandler)
endFillButton.pack(fill=tkinter.BOTH)
penLabel = tkinter.Label(sideBar,text="Pen Is Down")
penLabel.pack()
def penUpHandler():
cmd = PenUpCommand()
cmd.draw(theTurtle)
penLabel.configure(text="Pen Is Up")
self.graphicsCommands.append(cmd)
penUpButton = tkinter.Button(sideBar, text = "Pen Up", command=penUpHandler)
penUpButton.pack(fill=tkinter.BOTH)
def penDownHandler():
cmd = PenDownCommand()
cmd.draw(theTurtle)
penLabel.configure(text="Pen Is Down")
self.graphicsCommands.append(cmd)
penDownButton = tkinter.Button(sideBar, text = "Pen Down", command=penDownHandler)
penDownButton.pack(fill=tkinter.BOTH)
# Here is another event handler. This one handles mouse clicks on the screen.
def clickHandler(x,y):
# When a mouse click occurs, get the widthSize entry value and set the width of the
# pen to the widthSize value. The float(widthSize.get()) is needed because
# the width is an integer, but the entry widget stores it as a string.
cmd = GoToCommand(x,y,float(widthSize.get()),penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
screen.update()
screen.listen()
# Here is how we tie the clickHandler to mouse clicks.
screen.onclick(clickHandler)
def dragHandler(x,y):
cmd = GoToCommand(x,y,float(widthSize.get()),penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
screen.update()
screen.listen()
theTurtle.ondrag(dragHandler)
# the undoHandler undoes the last command by removing it from the
# sequence and then redrawing the entire picture.
def undoHandler():
if len(self.graphicsCommands) > 0:
self.graphicsCommands.removeLast()
theTurtle.clear()
theTurtle.penup()
theTurtle.goto(0,0)
theTurtle.pendown()
for cmd in self.graphicsCommands:
cmd.draw(theTurtle)
screen.update()
screen.listen()
screen.onkeypress(undoHandler, "u")
screen.listen()
# The main function in our GUI program is very simple. It creates the
# root window. Then it creates the DrawingApplication frame which creates
# all the widgets and has the logic for the event handlers. Calling mainloop
# on the frames makes it start listening for events. The mainloop function will
# return when the application is exited.
def main():
root = tkinter.Tk()
drawingApp = DrawingApplication(root)
drawingApp.mainloop()
print("Program Execution Completed.")
if __name__ == "__main__":
main()
Running the following code works flawlessly, once it is ran I would press the button labeled "Draw Text" and the following error is displayed:
C:\Python34\python.exe C:/Users/ThinkTank/PycharmProjects/untitled2/1/__init__.py
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
return self.func(*args)
File "C:/Users/ThinkTank/PycharmProjects/untitled2/1/__init__.py", line 354, in textHandler
cmd.draw(theTurtle)
File "C:/Users/ThinkTank/PycharmProjects/untitled2/1/__init__.py", line 57, in draw
turtle.move(self.move)
AttributeError: 'RawTurtle' object has no attribute 'move'
There is a task which requires me to draw some text on a tkinter screen using turtle. I have added in code which tells the turtle to draw this if the button in the menu is pressed, but this error than shows up. I am rather new to python and don't understand how to go about fixing such a problem.
The problem is that the RawTurtle object, from the turtle module, has no attribute move. You can use the commands forward, backward, left, and right to move your turtle. Before using the above commands, I suggest looking at the documentation for the turtle module, as you seem to be confused about how to properly use it.
Here is a quick explanation for the basic turtle move methods:
turtle.forward(int\float): This method moves a turtle object forward(in pixels). Use a integer or a float to specify how far to move the turtle.
turtle.backward(int\float): This method moves a turtle object backwards(in pixels). Use a integer or a float to specify how far to move the turtle.
turtle.left(int\float): This method turns a turtle object left(in degrees). Use a integer or a float to specify how far to turn the turtle.
turtle.right(int\float): This method turns a turtle object right(in degrees). Use a integer or a float to specify how far to turn the turtle.
This is fairly straightforward. You initialize theTurtle in the caller to be a turtle.RawTurtle. RawTurtle doesn't have an attribute or method named move, it has special purpose methods for moving forward or backwards, and other methods to turn relatively (right and left) or to an absolute orientation (setheading).
If your goal is to, say, move the turtle forward by move "distance" or something from its current heading, you'd call forward/fd.
I am currently controlling a game with python by sending mouse and keystroke commands. What I am looking to do is have a transparent Tkinter window lay overtop of the game to provide some information such as mouse location and pixel color.
I am familiar with changing the window's alpha attribute to make it transparent but have no idea how to always keep that window in front and have mouse clicks pass through it.
My current method of controlling the game involves taking screenshots in certain locations and analyzing the color content. I will also need some way to do this without the Tkinter window interfering.
Pyscreenshot is used for screenshots
win32api is used for clicking
Thank you,
Alec
you can use the SetWindowLong function of win32gui module. If you want a transparent click through window you have to apply GWL_EXSTYLE's ony our window. Therefore you need the windowhandle of your Window.
hwnd = win32gui.FindWindow(None, "Your window title") # Getting window handle
# hwnd = root.winfo_id() getting hwnd with Tkinter windows
# hwnd = root.GetHandle() getting hwnd with wx windows
lExStyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
lExStyle |= win32con.WS_EX_TRANSPARENT | win32con.WS_EX_LAYERED
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE , lExStyle )
If you want to change the transparency of your window via winapi use SetLayeredWindowAttributes.
EDIT: Examplecode for an overlay always-on-top transparent window, which pass through clicks. It gets the current desktopimage and creates a transparent overlay, so you can enjoy your desktop background image.
from win32api import GetSystemMetrics
import win32con
import win32gui
import wx
def scale_bitmap(bitmap, width, height):
image = wx.ImageFromBitmap(bitmap)
image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
result = wx.BitmapFromImage(image)
return result
app = wx.App()
trans = 50
# create a window/frame, no parent, -1 is default ID
# change the size of the frame to fit the backgound images
frame1 = wx.Frame(None, -1, "KEA", style=wx.CLIP_CHILDREN | wx.STAY_ON_TOP)
# create the class instance
frame1.ShowFullScreen(True)
image_file = win32gui.SystemParametersInfo(win32con.SPI_GETDESKWALLPAPER,0,0)
bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
bmp1 = scale_bitmap(bmp1,GetSystemMetrics(1)*1.5,GetSystemMetrics(1))
bitmap1 = wx.StaticBitmap(frame1, -1, bmp1, (-100, 0))
hwnd = frame1.GetHandle()
extendedStyleSettings = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, extendedStyleSettings | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
win32gui.SetLayeredWindowAttributes(hwnd, 0, 255, win32con.LWA_ALPHA)
frame1.SetTransparent(trans)
def onKeyDown(e):
global trans
key = e.GetKeyCode()
if key==wx.WXK_UP:
print trans
trans+=10
if trans >255:
trans = 255
elif key==wx.WXK_DOWN:
print trans
trans-=10
if trans < 0:
trans = 0
try:
win32gui.SetLayeredWindowAttributes(hwnd, 0, trans, win32con.LWA_ALPHA)
except:
pass
frame1.Bind(wx.EVT_KEY_DOWN, onKeyDown)
app.MainLoop()
You can dynamically change the transparency with the arrow keys Up/Down.
Notice, the windowframe is created with 'wx', but should work with tkinter also.
Feel free to use the code as you like.