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.)
Related
Im making a transition screen in Tkinter between the loading screen and the actual inteface, and my desired behaviour is for the entire window fade to a shade of black, resize itself to the size of the inteface, before fading back in to the interface. The things I saw with root.attribute would not work because it would simply turn the screen transparent which is not what I want. This is the code I have so far, except I dont have the fading part.
import tkinter as tk
moduleImportList = [
'from keras.models import Sequential',
'from keras.layers import Dense',
'import pandas as pd',
]
class mainGUI:
def __init__(self, master):
self.master = master
master.title('Loading screen test')
master.config(bg="#1f1f1f")
master.resizable(False,False)
master.geometry('300x100')
master.eval('tk::PlaceWindow . center')
self.loadingScreen = tk.Label(master,text='Loading...',font=('ariel 30 bold'),bg='#1f1f1f',fg='white')
self.loadingScreen.pack(pady=20)
self.loadModules()
self.fadeAndResize(master)
def loadModules(self):
for i in moduleImportList:
root.update()
exec(i)
print('module loaded')
def fadeAndResize(self, master):
initHeight, initWidth = master.winfo_height(),master.winfo_width()
for i in range(200):
Nwidth = initWidth + (800-initWidth)/200*(i+1)
Nheight = initHeight + (500-initHeight)/200*(i+1)
master.geometry("{}x{}".format(round(Nwidth),round(Nheight)))
root.update()
root = tk.Tk()
mainWindow = mainGUI(root)
root.mainloop()
(also if there's a way for it to resize about the middle of the screen that would be nice too)
Edit: After viewing a bunch of other posts, I have come to the conclusion that messing around with transparency would not get me anywhere, so the next thing I can think of is to change the colors of everything within a frame to be the same as the background so it's virtually indistinguishable or to have some sort of canvas etc covering everything else, not sure how to implement that tho.
I'm working on a program (in Linux) where I need to know the color at the point where of mouse click. I can't install external modules (PIL is fine though). I did try and see if there are solutions posted in the net (Return RGB Color of Image Pixel under Mouse Tkinter) but all of them seem to use modules which I'll have to install. Is there a way I can do it with these restrictions in mind?
Here is a short script that enables colors to be found and displayed in tkinter.
It uses PIL ImageGrab.grab() to grab the entire screen as pic then you simply press space-bar to find the color under the mouse pointer. It uses pic.getpixel(x, y)
import tkinter as tk
from PIL import ImageGrab
master = tk.Tk()
master.columnconfigure(0, weight = 1)
master.title("Colors")
button = tk.Button(master, text = "Press Spacebar")
button.grid(sticky = tk.NSEW)
canvas = tk.Canvas(master, width = 200, height = 200)
canvas.grid(sticky = tk.NSEW)
pic = ImageGrab.grab()
def color():
x, y = master.winfo_pointerx(), master.winfo_pointery()
r, g, b = pic.getpixel((x, y))
hue = f"#{r:02x}{g:02x}{b:02x}"
button.config( text = f"{x}, {y} = {hue}")
canvas["background"] = hue
button["command"] = color
button.focus_force()
master.mainloop()
I want to add a Drag Text Feature in canvas to change the position of text using mouse.
from PIL import Image,ImageFont,ImageDraw,ImageTk
import tkinter as tk
root = tk.Tk()
root.title('Demo')
root.geometry('400x50')
def func_image():
img_window = tk.Toplevel()
img_window.grab_set()
photo = Image.open(r'E:\side_300.png')
wi,hi = photo.size
fonty = ImageFont.truetype('arial.ttf',18)
draw = ImageDraw.Draw(photo)
draw.text((50,50),text=text.get(),fill='red',font=fonty)
new_photo = photo
can_photo = ImageTk.PhotoImage(new_photo)
canvas = tk.Canvas(img_window,height=500,width=500)
canvas.pack(anchor='n')
canvas.create_image(wi/2,hi/2,image=can_photo,anchor='center')
img_window.mainloop()
lbl_text = tk.Label(root,text='Enter Text :')
lbl_text.grid(row=0,column=0)
text = tk.Entry()
text.grid(row=0,column=1)
btn = tk.Button(root,text='Click Me',command=func_image)
btn.grid(row=0,column=2)
root.mainloop()
When you run the code it will firstly open a window with name 'Demo' which contains one entry box and a button.
When you click on a Button 'Click Me' after entering some text into entry box it will go to a function func_image and opens a new window which contain a canvas filled with new_image.
Quick Disclaimer: I don't have a lot of experience with PIL, so i don't know how to remove text that has already been drawn. Maybe you can figure that one out yourself. But apart from that, i know some things about tkinter. My idea would be the following:
Bind a function to the <B1-motion> event (Button 1 is being held down and moved) that will constantly get the position of the mouse inside the window and draw new text at that position, while deleting the previous text.
import...
...
def func_image():
img_window = tk.Toplevel()
...
...
draw = ImageDraw.Draw(photo)
draw.text((50,50),text=text.get(),fill='red',font=fonty)
...
def move_text(event):
# here you would delete your previous text
x = event.x
y = event.y
draw.text((x,y),text=text.get(),fill='red',font=fonty
img_window.bind('<B1-Motion>', move_text)
That being said, i think it would be a better idea to use Canvas.create_text (more on effbot.org) in order to write your text on the image. It's really easy to drag around text on a Canvas, here's a little example:
import tkinter as tk
root = tk.Tk()
def change_position(event):
x = event.x
y = event.y
# 20x20 square around mouse to make sure text only gets targeted if the mouse is near it
if text in c.find_overlapping(str(x-10), str(y-10), str(x+10), str(y+10)):
c.coords(text, x, y) # move text to mouse position
c = tk.Canvas(root)
c.pack(anchor='n')
text = c.create_text('10', '10', text='test', fill='red', font=('arial', 18)) # you can define all kinds of text options here
c.bind("<B1-Motion>", change_position)
root.mainloop()
I have worked out how to have an image for a button, thats positioned on top of a label (I think I maybe doing it the long-winded way because I can't install PIL on my Mac for some reason). Anyhow, it works as it should to a certain degree - the problem I have is it's adding white space either side, and then the image itself is not displaying its transparent background.
The code I am using is as follows:
from tkinter import *
#from PIL import Image
root = Tk()
#Removes the title bar and places over mac top bar
root.tk.call("::tk::unsupported::MacWindowStyle", "style", root._w, "plain", "none")
# Makes the app full screen
#root.wm_attributes('-fullscreen', 1)
root.geometry('{}x{}'.format(480, 320))
#root.attributes('-topmost', True)
def quitApp():
# mlabel = Label (root, text = 'Close').pack()
root.destroy()
background_img = PhotoImage(file="images/bg.gif")
scanBtn_img = PhotoImage(file="images/scanBtn.gif")
background = Label(root,
compound = CENTER,
quitButton = Button(image=scanBtn_img, command = quitApp).pack(),
image = background_img).pack(side="right")
background.image = background_img # keep a reference!
root.mainloop()
From what I understand tkinter natively supports transparency on images like GIF.
I chopped up your code a little but it does work for me. Maybe there is a problem with how you have set up your code. Your label also has a button in it. I don't think you need to have both. You can just created the button where you want it.
Just for reference I created a Label and a Button packed on different sides with a black background to show the transparency of the image.
Here is the code I used to test a gif I have that has transparency. I tested this on both python 3.6 and 2.7 just in case.
from tkinter import *
root = Tk()
def quitApp():
root.destroy()
background_img = PhotoImage(file="Colors/sa.gif")
scanBtn_img = PhotoImage(file="Colors/sa.gif")
background = Label(root,bg='black', image = background_img).pack(side = RIGHT)
quitButton = Button(bg='black', image=scanBtn_img, command = quitApp).pack(side = LEFT)
backgroundimage = background_img # keep a reference!
root.mainloop()
Update: I used the gif you link in the comment
Here is the result.
Update:
After doing some more digging I found what might work for Mac OS:
I don't have a Mac to test on right now so let me know if this works for you:
from tkinter import *
root = Tk()
# Hide the root window drag bar and close button
root.overrideredirect(True)
# Make the root window always on top
root.wm_attributes("-topmost", True)
# Make the window content area transparent
root.wm_attributes("-transparent", True)
# Set the root window background color to a transparent color
root.config(bg='systemTransparent')
def quitApp():
root.destroy()
background_img = PhotoImage(file="Colors/1.gif")
scanBtn_img = PhotoImage(file="Colors/1.gif")
background = Label(root,bg='black', image = background_img)
background.pack(side = RIGHT)
background.config(bg='systemTransparent')
quitButton = Button(bg='black', image=scanBtn_img, command = quitApp)
quitButton.pack(side = LEFT)
quitButton.config(bg='systemTransparent')
backgroundimage = background_img # keep a reference!
root.mainloop()
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)