Problems while drawing straight line and dragging in Tkinter canvas - python

So, I'm trying to draw vertical lines in canvas on the click of the button "line".
These are the problems and my requirements:
When i try click on the line drawn to drag it to a position, it repels away from the mouse cursor but moves in the correct direction. What do i do to prevent this?
On subsequent clicks on the "line" button, i want a new line to be drawn (every time i click) while the original lines stays in the canvas unmoved.
The latest line is the only one which can be dragged. All other lines should be static.
I want coordinates of all these drawn lines. How do i get these?
This is the code i've written:
from tkinter import *
import tkinter
root = Tk()
canvas = tkinter.Canvas(root, width = 480,height = 600)
canvas.pack()
def draw_lines():
canvas.create_line(300, 35, 300, 200, dash=(4, 2))
def drag(event):
event.widget.place(x=event.x_root, y=event.y_root,anchor=CENTER)
canvas.bind("<B1-Motion>", drag)
btn1 = Button(root, text = 'line', bd = '5',command = draw_lines)
btn2 = Button(root, text = 'Close', bd = '5',command = root.destroy)
btn1.pack(side = 'top')
btn2.pack(side = 'top')
canvas.mainloop()
please help!!!!

Using Python 3.11.0rc1.
I added:
geometry. so it will not resize when dragging.
Canvas. You have to play around with height set to 800
I removed bd=5. You can suit yourself. Don't use quote.
I removed Quotes for this btn1.pack(side=TOP)
At last canvas.pack() always next to mainloop()
Here is the code re-worked:
from tkinter import *
root = Tk()
root.geometry('400x650')
canvas = Canvas(root, width=480, height=600)
def draw_lines():
canvas.create_line(300, 35, 300, 200, dash=(4, 2))
def drag(event):
event.widget.place(x=event.x_root, y=event.y_root,anchor=CENTER)
canvas.bind("<B1-Motion>", drag)
btn1 = Button(root, text='line', command=draw_lines)
btn2 = Button(root, text= 'Close', command=root.destroy)
btn1.pack(side=TOP)
btn2.pack(side=TOP)
canvas.pack()
canvas.mainloop()
Result output:

Related

How to use the same button to generate and remove specific text label from Tkinter Canvas?

I just started to learn Tkinter. Going through a beginner project I tripped over this situation where I have to use the same button to generate a string and replace it with a new one as the new ones are overlapping the old ones. Here're the code segments:
def ranQ():
if root.count < len(root.LoQ):
tx=canv.create_text(400, 50, text=root.LoQ[root.count], font=('Jokerman', 15), fill="Purple")
root.count += 1
else:
# l2 = Label(root, text="End of 7 questions! Click to generate again!", fg= "white", bg ="red")
# l2.pack()
canv.create_text(400, 450, text="End of 7 questions! Click to generate again!", font=('Jokerman', 10), fill="Purple")
root.count=0
random.shuffle(root.LoQ)
# defining background image
im = PhotoImage(file="{path}")
# Creating a canvas
canv = Canvas(root, width =800, height=500)
canv.pack(fill ="both", expand= True)
# Putting the image in canvas
canv.create_image(0,0, image=im, anchor='nw')
# adding a text label
canv.create_text(400,450,text ="7 Random Questions!", font=('Jokerman',50), fill="black")
canv.create_text(404,454,text ="7 Random Questions!", font=('Jokerman',50), fill="purple")
# adding the generate button
btn_g = Button(root, text='Press to generate a random question'.upper(),font=('Jokerman',10), padx=60, pady=20, fg="white", bg='Red',
command=ranQ)
b_window = canv.create_window(220,225,anchor="nw", window= btn_g)
Have you tried something like this?:
import tkinter as tk
from random import randint
def callback():
new_text = randint(0, 100)
# Reconfigure the text
canvas.itemconfig(text_id, text=new_text)
root = tk.Tk()
canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()
# Save the text id that the canvas gives us
text_id = canvas.create_text(100, 100, text="")
button = tk.Button(root, text="Click me", command=callback)
button.pack(fill="x")
root.mainloop()
Basically you reconfigure the text. You can find more info here

Unable To Add Scroll Bars To A Canvas Widget

Using Python 2.7.16 on a iMac.
New to Python and this forum.
I have an application that has a canvas widget which the user can drawn on and I want to add scroll bars to it. I have been trying for the past two days and been having no luck. I have looked at numerous example but I can't get anything to work.
How can I do that?
Below is a screen shot and strip down source code to the essential code.
In the screen shot the scroll bars on the outer window. I want the scroll bars on the drawing canvas which is the black area.
Thanks.
This what my code example produce.
This what my code example produce.
This is what I want with the canvas having scroll bars.
Now it looks like this
#!/usr/bin/python
import Tkinter as tk
WINDOW_SIZE='950x650'
##########
# Size for canvas draring area
##########
MAX_X = 600
MAX_Y = 600
window = tk.Tk()
window.title("Cluster")
window.geometry(WINDOW_SIZE)
# Create a frame parent for the canvas and scrollbar(s).
p_frame = tk.Frame(window)
p_frame.grid(row=3, column=0, sticky=tk.NW)
Canvas_frame = tk.Frame()
Canvas = tk.Canvas(window, bg="black", height = MAX_Y, width = MAX_X)
Canvas.pack();
coord = 10, 50, 240, 210
arc = Canvas.create_arc(coord, start=0, extent=150, fill="red")
line = Canvas.create_line(0, 0, 20, 20, 300, 300, 400, 400, fill="dark violet")
lbl = tk.Label(window, width=15, height=5, borderwidth=2, relief="groove", anchor="center", justify="center", text="fasfdasf")
lbl.pack()
# Create a vertical scrollbar linked to the canvas.
vsbar = tk.Scrollbar(p_frame, orient=tk.VERTICAL, command=Canvas.yview)
vsbar.grid(row=0, column=1, sticky=tk.NS)
Canvas.configure(yscrollcommand=vsbar.set)
# Create a horizontal scrollbar linked to the canvas.
hsbar = tk.Scrollbar(p_frame, orient=tk.HORIZONTAL, command=Canvas.xview)
hsbar.grid(row=1, column=0, sticky=tk.EW)
Canvas.configure(xscrollcommand=hsbar.set)
# Start Tk's event loop
window.mainloop()
You should not put the scrollbars inside the canvas. Typically the canvas and the scrollbars should share a common parent.
If you want the scrollbars to appears as if they are inside the canvas, create a frame with a border and the put the canvas and scrollbars inside the frame.

Tkinter Canvas Scrollbars stopped working

Intitially when the frame and canvas size were smaller both scrollbars worked fine. After I increased their size to match that of the Toplevel, the x scrollbar disappear and the y one stopped working.
You may say I don't need the x scrollbar, because I adjusted the canvas create_text width attribute to fit the text within the window, and you'd be right, but I am trying to learn how to use scrollbars when the window's maximize button is on and when it's off.
The files I load to read are pretty lengthy, so I need the y scrollbar to scroll all the way to the end of the text. Checking some online notes on the scrollregion, I came a cross one that suggested using n,e,w,s coordintates, but when I use them, I get errores. I used scrollregion=(0,0,500,500) but that seems too finite to me.
from tkinter import *
from tkinter import font
newline=''
fileContent=[]
filePath='file.txt'
lines=open(filePath)
newline=lines.read()
w=Tk()
def openViewer():
pop = Toplevel(w)
pop.title('Operation Report')
pop.geometry("750x500+15+20")
pop.state('zoomed') # Window's Miximize button
frame=Frame(pop,width=780,height=560)
frame.grid(row=0,column=0)
canvas=Canvas(frame, width=780, height=560, background='black')
canvas.config(scrollregion=(0,0,500,500))
canvas.pack(side=LEFT, fill=BOTH)
verdana_font = font.Font(family = "Verdana",size = 13)
canvas.create_text((30, 0), anchor='nw', text=newline,
font=verdana_font, fill = 'light grey',
justify=LEFT, width=750)
hbar=Scrollbar(frame,orient=HORIZONTAL)
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
vbar=Scrollbar(frame,orient=VERTICAL)
vbar.pack(side=RIGHT,fill=Y)
vbar.config(command=canvas.yview)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
btn=Button(w, text='View Content', command=openViewer)
btn.pack()
w.mainloop()
from tkinter import *
from tkinter import font
newline=''
fileContent=[]
filePath='C:/path to/ file.txt'
lines=open(filePath)
newline=lines.read()
w=Tk()
def openViewer():
pop = Toplevel(w)
pop.title('Operation Report')
pop.geometry("750x500+15+20")
pop.state('zoomed') # Window's Miximize button
frame=Frame(pop,width=780,height=560)
frame.grid(row=0,column=0)
# I decreased the canvas height to show the x scrollbar and removed
# the create_text method width attribute to unwrap the text and
# activate the horizontal scrollbar
canvas=Canvas(frame, width=780,height=530, background='black')
verdana_font = font.Font(family = "Verdana",size = 13)
canvas.create_text((0, 0), anchor='nw', text=newline,
font=verdana_font, fill = 'light grey',
justify=LEFT) # Add this width=750 to wrap text
hbar=Scrollbar(frame,orient=HORIZONTAL)
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
vbar=Scrollbar(frame,orient=VERTICAL)
vbar.pack(side=RIGHT,fill=Y)
vbar.config(command=canvas.yview)
canvas.config(scrollregion=canvas.bbox(ALL))
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side=LEFT, expand=True, fill=BOTH)
btn=Button(w, text='View Content', command=openViewer)
btn.pack()
w.mainloop()
Hopefully, this may help someone else with the same or similar problem. :)

Zoom in and out function in Python

I am trying to use zoom in, zoom out feature in python. I have previously tried to use the functionality to zoom in a line in turtle, canvas, etc. but nothing seem to work out, instead of zooming, the code is either increasing or decreasing the length of the line. I want to zoom in the line to add text on the line so that when a user zoom's in the line he/she can see the text. here is the code which I am trying to change.
from tkinter import *
root = Tk()
Label(root).pack()
canvas = Canvas(root, width=400, height=400)
canvas.pack(fill=BOTH, expand=1)
widget = Button(None, text='zoomin-out')
widget.pack()
canvas.create_line(175,175,225,225)
def zoomin(event):
d = event.delta
if d < 0:
amt=0.9
else:
amt=1.1
canvas.scale(ALL, 200,200, amt, amt)
widget.bind('<Button-1>', zoomin)
def zoomout(event):
d = event.delta
if d >0:
amt=1.1
else:
amt=0.7
canvas.scale(ALL, 200,200 , amt, amt)
widget.bind('<Double-1>', zoomout)
widget.mainloop()
root.mainloop()
There are two issues. First, when you add both the Button-1 and Double-1 events to your Button widget, doing a double-click fires both events. They end up cancelling each other out, so only the single-click works as expected.
Second, as I pointed out in this SO answer, certain elements, like text, won't zoom, they'll remain fixed. You'll need to manually scale your fonts to simulate text zoom.
Below's a rework of your code along the above lines. Instead of the problematic single and double click, I've changed it so that left and right clicks on the button cause the canvas to zoom in or out:
from tkinter import *
EXAMPLE_TEXT = "Left or Right click button to zoom in/out"
FONT_NAME = "Helvetica"
font_size = 12
def zoom(amount):
global font_size
canvas.scale(ALL, 200, 200, amount, amount)
font_size *= amount
canvas.itemconfigure(text_item, font=(FONT_NAME, int(font_size)))
root = Tk()
canvas = Canvas(root, width=400, height=400)
canvas.pack(fill=BOTH, expand=1)
text_item = canvas.create_text(200, 200, font=(FONT_NAME, font_size), text=EXAMPLE_TEXT)
canvas.create_oval(50, 50, 350, 350)
widget = Button(root, text='zoom in/out')
widget.pack()
widget.bind('<Button-1>', lambda e: zoom(1.1))
widget.bind('<Button-2>', lambda e: zoom(0.7))
root.mainloop()
If you comment out the line that starts with canvas.itemconfigure(...), you'll see that the circle continues to zoom in and out, but the text remains fixed size.

Make button on opposite side of tkinter GUI

When I put in my code for this name picker, the gui opens and the two buttons are on top of each other. I understand why this is happening but I do not know how to move it.
This is what it looks like
This is what I want it to look like
Code:
from tkinter import *
import tkinter
import random
names =['Sledge','Thatcher','Ash','Thermite','Twitch','Montagne','Glaz','Fuze','Blitz','IQ','Buck','Blackbeard','Capitão','Hibana']
name = ["Smoke","Mute","Castle","Pulse","Doc","Rook","Kapkan","Tachanka","Jäger","Bandit","Frost","Valkyrie","Caveira","Echo"]
def pickName():
nameLabel.configure(text=random.choice(names))
def pickName1():
nameLabel.configure(text=random.choice(name))
root = tkinter.Tk()
root.title("Operator Picker")
root.geometry("400x100")
nameLabel = tkinter.Label(root, text="", font=('Helvetica', 32))
nameLabel.pack()
Grid()
pickButton1 = tkinter.Button(text="Pick Attack", command=pickName)
pickButton1.pack()
pickButton1.place(bordermode=OUTSIDE,height=100, width= 100)
pickButton2 = tkinter.Button(text="Pick Defend", command=pickName1)
pickButton2.pack()
pickButton2.place(bordermode=OUTSIDE,height=100, width= 100)
root.mainloop()
You don't need to pack and place your buttons, you can just pack them. If you want them on opposite sides, try this
pickButton1 = tkinter.Button(root, text="Pick Attack", command=pickName, height=100, width=100)
pickButton1.pack(side=tkinter.LEFT)
pickButton2 = tkinter.Button(root, text="Pick Defend", command=pickName1, height=100, width=100)
pickButton2.pack(side=tkinter.RIGHT)
Edit:
When you define the width and height of an object containing text, it is measured in lines and characters instead of pixels, if you want those exact sizes, you need to add frames
f1 = tkinter.Frame(root, height=100, width=100) #defines frame size in pixels
f1.pack(side=tkinter.LEFT) #packs on the left
f1.pack_propagate(0) #tells frame not to let children control size
pickButton1 = tkinter.Button(f1, command=pickName, text="Pick Attack")
pickButton1.pack(fill=tkinter.BOTH, expand=1) #takes up all available space
f2 = tkinter.Frame(root, height=100, width=100)
f2.pack(side=tkinter.RIGHT)
f2.pack_propagate(0)
pickButton2 = tkinter.Button(f2, command=pickName1, text="Pick Defend")
pickButton2.pack(fill=tkinter.BOTH, expand=1)

Categories