Python GUI changing the width of a line - python

I'm programming a drawing application in a GUI canvas.
I need to make it possible for the user to change the Width of the line in the canvas by using a spinbox.

You're not ever getting the value of the spinbox, or using the value to draw/redraw a line. Modify your add_point() function like so:
def add_point(self, event):
#Use color[1] to get the second element in the color tuple.
self.canvas.create_line(self.prev_x, self.prev_y, event.x, event.y, fill=color[1], width=self.spinbox1.get())
self.prev_x = event.x
self.prev_y = event.y
Now you can pick a color, draw a line, change the spinbox's value, and draw another line with a different thickness (width). See here for all the arguments you can pass to the create_line() method.

Related

Why does my tkinter object keep changing shape?

I have created an image on a canvas in tkinter that responds to a button event. And, the object is created on position x and position y where that event took place. But the object changes shape constantly.
def leftclick(event):
canvas1=Canvas(play, height=hei, width=wid)
canvas1.grid(row=0, column=0, sticky=W)
canvas1.delete("all")
x=event.x
y=event.y
print(event.x, event.y)
bullet = canvas1.create_oval(x,y, 100,100, fill="red")
xspeed=random.randint(0, 50)
yspeed=random.randint(0,50)
This just draws ovals which are randomly shaped. Why is this happening and how do I fix it?
You should only create your canvas once, but that's not a problem.
The problem is that the tkinter tries to create an oval inside the rectangle. You've specified the 2 points of the rectangle: x,y and 100,100. Just use bullet = canvas1.create_oval(x-50,y-50, x+50,y+50, fill="red") or whatever number you pick instead of 50. Hope that's helpful!

position of line when resizing Tkinter window

The following code:
from tkinter import *
root=Tk()
for x in range(10):
for y in range(10):
canvas=Canvas(root, width='15',height='15',highlightthickness=0,bg='red')
canvas.create_line(canvas.winfo_x(),canvas.winfo_y(),canvas.winfo_x()+15,canvas.winfo_y()+15,width=2,fill='black')
canvas.grid(row=y,column=x,sticky='NESW')
for x in range(10):
for y in range(10):
root.columnconfigure(x,weight=1)
root.rowconfigure(y,weight=1)
root.mainloop()
produces this, which is a 10 by 10 grid filled with canvases; there is a line extending from the top left to the bottom right corner of each canvas.
When I resize the window, the canvas widgets resize correctly, but the lines retain their shape like this. The lines need to adjust according to the window/widget size.
The core of the problem is that the lines are made using the coordinates of the top left corner of the widget, and are extended 15 pixels in each direction. Is there a way of getting the coordinates of the bottom right corner of the widget, so that the lines can change their shape dynamically, or some other way of keeping the lines shape, relative to the widget?
You can get the current width and height of any widget with the winfo_width and winfo_height methods. If you are binding to the <Configure> method to track when the canvas changes size, the event object has a width and height attribute.
For example:
from tkinter import *
def redraw_line(event):
width = event.width
height = event.height
canvas = event.widget
canvas.coords("diagonal", 0, 0, width, height)
root=Tk()
for x in range(10):
for y in range(10):
canvas=Canvas(root, width='15',height='15',highlightthickness=0,bg='red')
canvas.bind("<Configure>", redraw_line)
# coordinates are irrelevant; they will change as soon as
# the widget is mapped to the screen.
canvas.create_line(0,0,0,0, tags=("diagonal",))
canvas.grid(row=y,column=x,sticky='NESW')
for x in range(10):
for y in range(10):
root.columnconfigure(x,weight=1)
root.rowconfigure(y,weight=1)
root.mainloop()

How can I convert coordinate in tkinter?

I already tried to google it but I couldn't find anything ...
I created tkinter canvas with width 800, height 600
apparently, the left upside will be (0,0)
I want to change left downside to (0,0)
How can I do this???
You cannot change the coordinate system of the canvas. You can scroll the canvas so that 0,0 is in the bottom left, but the y coordinates will be negative going up.
In order to do that, you have to define your own function. Such:
def conv( coordinatePair ):
return { "x":coordinatePair["x"], "y":canvas.height-coordinatePair["y"]}
Where coordinatePair is a dictionary. That function will take your coordinate, flip the y, and return a new coordinate dictionary.

How do I selectively delete drawings in Tkinter?

I am drawing a lot of moving particles in a stationary box with Tkinter. My box is always there and does not change as time goes by, whereas the particles need to be updated.
My first intuition is to delete ALL the things (both particles and the box) and then redraw everything.
canvas.delete(ALL)
It indeed works, but the frame updates get extremely slow. This is because my box is of an irregular shape, which implies that I have to draw the box dot by dot. So this delete-everything-and-redraw-everything method is unsatisfactory.
I wish that the box is drawn only once, and only the particles get deleted and redrawn (updated). How should I do this?
Suppose you have a rectangle on canvas:
canvas.create_rectangle(x0, y0, x1, y1)
This would return a handle, so if you keep track of it,
myRectangle = canvas.create_rectangle(x0, y0, x1, y1)
canvas.delete(myRectangle)
This will delete only the myRectangle object.
Another way of doing it is to use tags.
canvas.create_rectangle(x0, y0, x1, y1, tags="myRectangle")
canvas.delete("myRectangle")
What you need to do is assign the drawings to variables, and then delete those. The below script demonstrates this:
from Tkinter import Button, Canvas, Tk
root = Tk()
canvas = Canvas()
canvas.grid()
drawing1 = canvas.create_oval((10,50,20,60), fill="red")
drawing2 = canvas.create_oval((30,70,40,80), fill="blue")
Button(text="Kill 1", command=lambda: canvas.delete(drawing1)).grid()
Button(text="Kill 2", command=lambda: canvas.delete(drawing2)).grid()
root.mainloop()
In addition to ALL, the delete method can also accept a specific drawing.

How to connect two state circles with an arrow in tkinter?

I am currently writing a fsm editor with tkinter. But, I stuck on connecting two states. I have two questions:
1) How can make the transition arrow growable according to mouse movement?
2) How can I stick the starting point of the arrow on a state and the end point of the arrow on another state?
PS. Do you think the documentation of tkinter is good enough?
Here's an example that shows the concept. In a nutshell, use tags to associate lines with boxes, and simply adjust the coordinates appropriately when the user moves the mouse.
Run the example, then click and drag from within the beige box.
Of course, for production code you need to make a more general solution, but hopefully this shows you how easy it is to create a box with arrows that adjust as you move the box around.
from Tkinter import *
class CanvasDemo(Frame):
def __init__(self, width=200, height=200):
Frame.__init__(self, root)
self.canvas = Canvas(self)
self.canvas.pack(fill="both", expand="1")
self.canvas.create_rectangle(50, 25, 150, 75, fill="bisque", tags="r1")
self.canvas.create_line(0,0, 50, 25, arrow="last", tags="to_r1")
self.canvas.bind("<B1-Motion>", self.move_box)
self.canvas.bind("<ButtonPress-1>", self.start_move)
def move_box(self, event):
deltax = event.x - self.x
deltay = event.y - self.y
self.canvas.move("r1", deltax, deltay)
coords = self.canvas.coords("to_r1")
coords[2] += deltax
coords[3] += deltay
self.canvas.coords("to_r1", *coords)
self.x = event.x
self.y = event.y
def start_move(self, event):
self.x = event.x
self.y = event.y
root = Tk()
canvas = CanvasDemo(root)
canvas.pack()
mainloop()
Tkinter is perfectly fine for this sort of application. In the past I've worked on tools that were boxes connected with arrows that stayed connected as you move the boxes around (which is what I think you are asking about). Don't let people who don't know much about Tkinter sway you -- it's a perfectly fine toolkit and the canvas is very flexible.
The solution to your problem is simple math. You merely need to compute the coordinates of the edges or corners of boxes to know where to anchor your arrows. To make it "grow" as you say, simply make a binding on mouse movements and update the coordinates appropriately.
To make the line growable all you have to do is adjust the coordinates of the line each time the mouse moves. The easiest thing to do is make liberal use of canvas tags. With the tags you can know which arrows connect to which boxes so that when you move the box you adjust the coordinates of any arrows that point to or from it.

Categories

Resources