0

I want to program a program that will draw the text where I click and when I go through it it will be deleted. This is my code when I cross the line, everything is cleared and the ones I didn't cross are drawn back. Thanks to anyone who help me.

from tkinter import *

class Program(Tk):

    def __init__(self):
        super().__init__()
        self.w, self.h = 250, 200
        self.canvas = Canvas(width=500, height=400)
        self.canvas.pack()
        self.draw_line()
        
        #self.x_lst_txt = None
        self.txt_lst_org = []
        self.txt2_lst_org = []
        self.change = False
        self.positon = False
        self.idx= 0
        self.new_lst=[]

        self.text1 = "Programovanie"
        self.text2 = "Je zábava"
        self.color1 = "green"
        self.color2 = "orange"
        self.opr1 = "-"
        self.opr2 = "+"

        self.all_binds()

    def draw_line(self):
        self.line = self.canvas.create_line(self.w, 0, self.w, self.h*2, width=5)

    def all_binds(self):
        self.canvas.bind("<Button-1>", self.draw_texts)
        self.canvas.bind("<Button-3>", self.draw_reacts)
        self.canvas.bind_all("<Right>", self.move_line_right)
        self.canvas.bind_all("<Left>", self.move_line_left)

    def draw_texts(self, event):
        self.xt = event.x
        self.yt = event.y
        uhol=self.yt

        if self.xt < self.w:
            self.text_left = self.canvas.create_text(self.xt, self.yt, text=self.text1, fill=self.color1, angle=uhol)
            self.txt2_lst_org.append([self.xt, self.yt])
            self.change = True
        else:
            self.text_right = self.canvas.create_text(self.xt, self.yt, text=self.text2, fill=self.color2, angle=-uhol)
            self.txt_lst_org.append([self.xt, self.yt])
            self.change = True

    def draw_reacts(self, event):
        self.xr = event.x
        self.yr = event.y
        
        for i in range(10):
            rect = self.canvas.create_rectangle(self.xr, self.yr+i*10, self.xr+10, self.yr+10+i*10)
            self.yr += 5

    def select_x(self, lst):
        if self.change:
            for i in range(0, len(lst)):
                if [len(i) for i in lst][self.idx] > 1:
                    self.new_lst.append(lst[i][0])
                    self.idx+=1
            self.idx = 0
            self.change=False
            return sorted(self.new_lst)
        return sorted(self.new_lst)

    def delete_all(self, lst, x_lst):
        self.new_lst = sorted(self.new_lst, reverse=self.positon)
        x_lst = sorted(x_lst, reverse=self.positon)
        del lst[0]
        del x_lst[0]
        del self.new_lst[0]

    def replace_text(self, lst, txt, fill, opr):
        for i in range(0, len(lst)+1):
            x, y = lst[i]
            angle = y
            texts = self.canvas.create_text(x, y, text=txt, fill=fill, angle=f"{opr}{angle}")


    def replace(self, lst, x_lst, con_lst, text, color, opr):
        self.delete_all(lst, x_lst)
        self.canvas.delete("all")
        self.draw_line()
        
        if lst != []:
            self.replace_text(lst, text, color, opr)

        elif con_lst != []:
            self.replace_text(con_lst, text, color, opr)


    def move_line_right(self, event):
        self.canvas.move(self.line, 5, 0)
        self.w+=5

        self.positon = False
        self.txt_lst_x = sorted(self.select_x(self.txt_lst_org))
        self.txt_lst_org = sorted(self.txt_lst_org)
        
        print("enter right",self.txt_lst_x, "org", self.txt_lst_org)

        if self.txt_lst_x != []:
            try:
                if self.w >= self.txt_lst_x[0]:
                    print("TRUE RIGHT")
                    self.replace(self.txt_lst_org, self.txt_lst_x, self.txt2_lst_org, 
                        self.text2, self.color2, self.opr1)
            except IndexError:
                pass

    def move_line_left(self, event):
        self.canvas.move(self.line, -5, 0)
        self.w-=5

        self.positon = True
        self.txt2_lst_x = sorted(self.select_x(self.txt2_lst_org), reverse=self.positon)
        self.txt2_lst_org = sorted(self.txt2_lst_org, reverse=self.positon)
        print("enter left", self.txt2_lst_x, "org", self.txt2_lst_org)

        if self.txt2_lst_x != []:
            try:
                if self.w <= self.txt2_lst_x[0]:
                    print("TRUE LEFT")
                    self.replace(self.txt2_lst_org, self.txt2_lst_x, self.txt_lst_org, 
                        self.text1, self.color1, self.opr2)
            except IndexError:
                pass

main = Program()
main.mainloop()
6
  • 4
    It's not clear what you're asking, since the delete message is documented and there are many examples on the internet. Why do you need our help? Also, please reduce this code down to a minimal reproducible example. If the question is about deleting canvas objects then we don't need code for moving them, selecting them, drawing text, etc. Commented May 10, 2021 at 16:12
  • I don't want to delete line. I want to delete text after when I cross the line. Commented May 10, 2021 at 17:59
  • When there are many such examples. Please send them to me Commented May 10, 2021 at 18:00
  • if you want to delete text the you should use canvas.delete() instead of replace(). In current code if line touch text on first list then you get it and replace with text on second list - and this way you move it from left side to right side. Commented May 10, 2021 at 18:43
  • 1
    if you create temporary variables in function then you don't have to use self. - it can be misleading - x = event.x instead of self.xt = event.x. And you could use more readable names - ie. text_left instead of `txt_lst_org Commented May 10, 2021 at 19:04

2 Answers 2

1

I think you created too complicated code.

But first I changed names to make them more readable

        self.items_left = []
        self.items_right = []

and in similar way

        self.text_left = "Programovanie"
        self.text_right = "Je zábava"
        
        self.color_left = "green"
        self.color_right = "orange"
        
        self.opr_left = "-"
        self.opr_right = "+"

Next I keep all information as dictionary on one list

            self.items_right.append({
                'id': text_id,
                'x': x,
                'y': y,
                'angle': -angle
            })

This way I can sort all values using only one line (with key= in sorted())

 self.items_right = sorted(self.items_right, key=(lambda item: item['x']))

and I could remove function select_x()

And finally I resolved problem: I removed functions replace(), replace_text(), delete_all() and keep only three lines (but they can be reduced to two lines).

                first_item = self.items_right[0]

                # remove from canvas
                self.canvas.delete(first_item['id'])

                # remove from list
                self.items_right.pop(0)

Full working code.

from tkinter import *

class Program(Tk):

    def __init__(self):
        super().__init__()
        
        self.canvas = Canvas(width=500, height=400)
        self.canvas.pack()
        
        self.w = 250
        self.h = 200
        self.draw_line()
        
        self.items_left = []
        self.items_right = []
        
        self.change = False
        self.positon = False

        self.text_left = "Programovanie"
        self.text_right = "Je zábava"
        
        self.color_left = "green"
        self.color_right = "orange"
        
        self.opr_left = "-"
        self.opr_right = "+"

        self.set_binds()

    def draw_line(self):
        self.line = self.canvas.create_line(self.w, 0, self.w, self.h*2, width=5)

    def set_binds(self):
        self.canvas.bind("<Button-1>", self.draw_text)
        self.canvas.bind_all("<Right>", self.move_line_right)
        self.canvas.bind_all("<Left>", self.move_line_left)

    def draw_text(self, event):
        x = event.x
        y = event.y
        angle = y

        if x < self.w:
            text_id = self.canvas.create_text(x, y, text=self.text_left, fill=self.color_left, angle=angle)
            self.items_left.append({
                'id': text_id,
                'x': x,
                'y': y,
                'angle': angle
            })
        else:
            text_id = self.canvas.create_text(x, y, text=self.text_right, fill=self.color_right, angle=-angle)
            self.items_right.append({
                'id': text_id,
                'x': x,
                'y': y,
                'angle': -angle
            })
            
        self.change = True

    def move_line_right(self, event):
        self.canvas.move(self.line, 5, 0)
        self.w += 5

        self.positon = False
        self.items_right = sorted(self.items_right, key=(lambda item: item['x']))
        
        print("enter right", self.items_right)

        if self.items_right:
            #print('[DEBUG] check:', self.items_left[0], self.w) 
            first_item = self.items_right[0]
            try:
                if self.w >= first_item['x']:
                    print("TRUE RIGHT", first_item['id'])
                    #print('[DEBUG] before:', self.items_left) 
                    # remove from canvas
                    self.canvas.delete(first_item['id'])
                    # remove from list
                    self.items_right.pop(0)
                    #print('[DEBUG] after:', self.items_left) 
            except IndexError as ex:
                print('ERROR:', ex)

    def move_line_left(self, event):
        self.canvas.move(self.line, -5, 0)
        self.w -= 5

        self.positon = True
        #self.items_left = sorted(self.items_left, key=(lambda item: item['x']), reverse=True)
        self.items_left = sorted(self.items_left, key=(lambda item: -item['x']))
        
        print("enter left", self.items_left)

        if self.items_left:
            #print('[DEBUG] check:', self.items_left[0], self.w) 
            first_item = self.items_left[0]
            try:
                if self.w <= first_item['x']:
                    print("TRUE LEFT", first_item['id'])
                    #print('[DEBUG] before:', self.items_left) 
                    # remove from canvas
                    self.canvas.delete(first_item['id'])
                    # remove from list
                    self.items_left.pop(0)
                    #print('[DEBUG] after:', self.items_left) 
            except IndexError as ex:
                print('ERROR:', ex)

main = Program()
main.mainloop()
Sign up to request clarification or add additional context in comments.

5 Comments

+1 Great explanation but wouldn't it be better to use the if statement in draw_text to set the angle then add the text to the canvas. It will shorten the code
@TheLizzard create_text uses also different color and text so it would need to set 3 variables. It could be more readable - and it could use one create_text and one append() - but there were other problems and I skip/forgot this one :) I was also thinking to keep values in directory color = {'left': ..., 'right': ...} and text = {'left': ..., 'right': ...} and then it would set only side = 'left' to get values color[side], text[side] but I decided that it would be too much changes for beginners.
Still a great answer. Btw I never knew that I can rotate text that is why I looked at that function :D.
Thanks man your solution is very helpful for me. I didn't think of doing it that way
I only have 16, I do everything complicated
0

This is a full solution. If is anything complicate write me.

from tkinter import *

class Program(Tk):

def __init__(self):
    super().__init__()
    WIDTH, HEIGHT = 500, 400
    self.w=WIDTH/2
    self.canvas = Canvas(width=WIDTH, height=HEIGHT)
    self.canvas.pack()
    self.draw_line()

    self.items_text = {
        "RIGHT":[],
        "LEFT":[]
    }
    self.items_rect = {
        "RIGHT":[],
        "LEFT":[]
    }

    self.all_binds()

def draw_line(self):
    self.line = self.canvas.create_line(self.w, 0, self.w, 400, width=5)

def all_binds(self):
    self.canvas.bind("<Button-1>", self.draw_texts)
    self.canvas.bind("<Button-3>", self.draw_reacts)
    self.canvas.bind_all("<Right>", self.move_line_right)
    self.canvas.bind_all("<Left>", self.move_line_left)

def draw_texts(self, event):
    x = event.x
    y = event.y
    uhol=y

    if x < self.w:
        text_id = self.canvas.create_text(x, y, text="Programovanie", fill="green", angle=uhol)
        self.items_text["LEFT"].append({
            "id": text_id,
            "x": x
        })
    else:
        text_id = self.canvas.create_text(x, y, text="Je zábava", fill="orange", angle=-uhol)
        self.items_text["RIGHT"].append({
            "id": text_id,
            "x": x
        })

def draw_reacts(self, event):
    x = event.x
    y = event.y
    
    if x < self.w:
        for i in range(10):
            rect = self.canvas.create_rectangle(x, y+i*10, x+10, y+10+i*10)
            y += 5
            self.items_rect["LEFT"].append({
                "id": rect,
                "x": x
            })
    else:
        for i in range(10):
            rect = self.canvas.create_rectangle(x, y+i*10, x+10, y+10+i*10)
            y += 5
            self.items_rect["RIGHT"].append({
                "id": rect,
                "x": x
            })

def move_line_right(self, event):
    self.canvas.move(self.line, 5, 0)
    self.w+=5

    self.items_text["RIGHT"] = sorted(self.items_text["RIGHT"], key=(lambda item: item["x"]))
    self.items_rect["RIGHT"] = sorted(self.items_rect["RIGHT"], key=(lambda item: item["x"]))

    if self.items_text["RIGHT"]:
        first_item = self.items_text["RIGHT"][0]

        try:
            if self.w >= first_item["x"]:
                self.canvas.delete(first_item["id"])
                self.items_text["RIGHT"].pop(0)
        except IndexError:
            pass

    if self.items_rect["RIGHT"]:
        first_item = self.items_rect["RIGHT"][0]
        
        try:
            if self.w >= first_item["x"]:
                for j, i in enumerate(self.items_rect["RIGHT"]):
                    if i["x"] == first_item["x"]:
                        self.canvas.delete(i["id"])

                self.items_rect["RIGHT"] = list(filter(lambda i: i["x"] != first_item["x"], self.items_rect["RIGHT"]))

        except IndexError:
            pass

def move_line_left(self, event):
    self.canvas.move(self.line, -5, 0)
    self.w-=5

    self.items_text["LEFT"] = sorted(self.items_text["LEFT"] , key=(lambda item: item["x"]), reverse=True)
    self.items_rect["LEFT"] = sorted(self.items_rect["LEFT"], key=(lambda item: item["x"]), reverse=True)

    if self.items_text["LEFT"]:
        first_item = self.items_text["LEFT"][0]

        try:
            if self.w <= first_item["x"]:
                self.canvas.delete(first_item["id"])
                self.items_text["LEFT"].pop(0)
        except IndexError:
            pass
    
    if self.items_rect["LEFT"]:
        first_item = self.items_rect["LEFT"][0]
        
        try:
            if self.w <= first_item["x"]:
                for j, i in enumerate(self.items_rect["LEFT"]):
                    if i["x"] == first_item["x"]:
                        self.canvas.delete(i["id"])

                self.items_rect["LEFT"] = list(filter(lambda i: i["x"] != first_item["x"], self.items_rect["LEFT"]))

        except IndexError:
            pass

main = Program() main.mainloop()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.