【问题标题】:Tkinter: How to make a rounded corner text widget?Tkinter:如何制作圆角文本小部件?
【发布时间】:2018-12-27 18:25:36
【问题描述】:

问题

如何创建圆角文本小部件?我想我想创建一个圆形画布并用没有边框的文本框填充整个画布。


问题

当我尝试扩展画布的高度和宽度时,创建圆形边框画布的代码不起作用。换行并变得不连续。


创建圆角画布的代码取自How to make a tkinter canvas rectangle with rounded corners?

我的自定义宽度和高度的代码

def rounded_rect(canvas, x, y, w, h, c):
    canvas.create_arc(x,   y,   x+2*c,   y+2*c,   start= 90, extent=90, style="arc")
    canvas.create_arc(x+w-2*c, y+h-2*c, x+w, y+h, start=270, extent=90, style="arc")
    canvas.create_arc(x+w-2*c, y,   x+w, y+2*c,   start=  0, extent=90, style="arc")
    canvas.create_arc(x,   y+h-2*c, x+2*c,   y+h, start=180, extent=90, style="arc")
    canvas.create_line(x+c, y,   x+w-c, y    )
    canvas.create_line(x+c, y+h, x+w-c, y+h  )
    canvas.create_line(x,   y+c, x,     y+h-c)
    canvas.create_line(x+w, y+c, x+w,   y+h-c)

import tkinter
root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.grid(row=0,column=0)

# The width and height has been changed from the original solution
rounded_rect(canvas, 10, 10, 330, 290, 10)
root.mainloop()

输出

【问题讨论】:

    标签: python-3.x tkinter tkinter-canvas


    【解决方案1】:

    一种解决方案是使用具有自定义样式的 ttk 框架,该样式使用图像作为角落。

    以下示例改编自我在 2007 年写的 tcl/tk 解决方案。它使用奇怪的颜色作为焦点,并且需要白色背景,但您可以创建自己的图像来替换此解决方案中使用的图像(或在本例中编辑图像1)

    # adapted from http://wiki.tcl.tk/%0920152
    import tkinter as tk
    from tkinter import ttk
    
    focusBorderImageData = '''
        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
        Ry/99NIz//oGrZpUUEAAOw==
    '''
    
    borderImageData = '''
        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
    '''
    
    root = tk.Tk()
    style = ttk.Style()
    borderImage = tk.PhotoImage("borderImage", data=borderImageData)
    focusBorderImage = tk.PhotoImage("focusBorderImage", data=focusBorderImageData)
    
    style.element_create("RoundedFrame",
                         "image", borderImage,
                         ("focus", focusBorderImage),
                         border=16, sticky="nsew")
    style.layout("RoundedFrame",
                 [("RoundedFrame", {"sticky": "nsew"})])
    
    frame1 = ttk.Frame(style="RoundedFrame", padding=10)
    text1 = tk.Text(frame1, borderwidth=0, highlightthickness=0, wrap="word",
                    width=40, height=4)
    text1.pack(fill="both", expand=True)
    
    text1.bind("<FocusIn>", lambda event: frame1.state(["focus"]))
    text1.bind("<FocusOut>", lambda event: frame1.state(["!focus"]))
    text1.insert("end", "This widget has the focus")
    
    frame2 = ttk.Frame(style="RoundedFrame", padding=10)
    text2 = tk.Text(frame2, borderwidth=0, highlightthickness=0, wrap="word",
                    width=40, height=4)
    text2.pack(fill="both", expand=True)
    text2.bind("<FocusIn>", lambda event: frame2.state(["focus"]))
    text2.bind("<FocusOut>", lambda event: frame2.state(["!focus"]))
    text2.insert("end", "This widget does not have the focus")
    
    root.configure(background="white")
    frame1.pack(side="top", fill="both", expand=True, padx=20, pady=20)
    frame2.pack(side="top", fill="both", expand=True, padx=20, pady=20)
    
    frame1.focus_set()
    
    root.mainloop()
    

    1图片数据是base64编码的gif。如果您对数据进行解码并将其保存为 .gif 文件,则可以对其进行编辑以使用所需的任何颜色。

    【讨论】:

    • 谢谢,布莱恩。这正是我需要的样式
    • @Bryan:text1 的 FocusOut 也应该影响frame1。非作者不允许编辑 1 个字符的更改。
    • @Bryan:我一直在寻找有关如何使用 style.element_create (ttk::style element create) 的文档。但是 tcl.tk 网站没有更多信息表明该方法存在。除了挖掘 ttk 源代码,你知道在哪里可以找到更多信息吗?
    • @rioV8:这有一些有用的信息:tkdocs.com/tutorial/styles.html
    • @Bryan:谢谢。当我想修改布局和样式时,我已经阅读了这个 URL。但它并没有说明如何从头开始创建新样式,否则它是可能的。我将像底部的 URL 建议那样深入研究 src 代码。
    【解决方案2】:

    您的画布根本不够大。使用放大

    canvas = tkinter.Canvas(root, width=500, height=500)
    

    或者使用根窗口调整大小

    canvas = tkinter.Canvas(root)
    canvas.grid(row=0,column=0, sticky='NSEW')
    root.rowconfigure(0, weight=1)
    root.columnconfigure(0, weight=1)
    

    【讨论】:

    • 它有效。谢谢。这是正确的:如何创建圆角文本小部件?我想我想创建一个圆形画布并用没有边框的文本框填充整个画布。
    【解决方案3】:

    除了主窗口外,我也遇到了这个问题。我正在为某人制作一个便笺应用程序,他们希望窗口的角是圆角的。

    我在 4 个角上有 4 个画布,并带有基于角的弧形图像。然后我将这些图像的颜色设置为透明,效果出奇的好,所以我想分享它。

    代码如下:

    from tkinter import *
    from PIL import Image,ImageTk
    
    def drag(event,win):
        x = win.winfo_pointerx() - win.offsetx
        y = win.winfo_pointery() - win.offsety
        win.geometry('+{x}+{y}'.format(x=x,y=y))
    
    def click(event,win):
        win.offsetx = event.x
        win.offsety = event.y
    
    root = Tk()
    root.resizable(False,False)
    root.geometry("610x260")
    img = ImageTk.PhotoImage( Image.open("src/ARC.png").resize((150,150)), Image.ANTIALIAS )
    img2 = ImageTk.PhotoImage( Image.open("src/ARC 2.png").resize((150,150)), Image.ANTIALIAS )
    img3 = ImageTk.PhotoImage( Image.open("src/ARC 3.png").resize((150,150)), Image.ANTIALIAS )
    img4 = ImageTk.PhotoImage( Image.open("src/ARC 4.png").resize((150,150)), Image.ANTIALIAS )
    fr = Frame(root, bg = "yellow", bd = 0)
    fr.pack( expand = True, fill = 'both')
    canvas = Canvas(fr, bg = "yellow", width = 60, height = 60, bd=0, highlightthickness=0, relief='ridge')
    canvas.create_image(-2,-2, image = img, anchor = "nw")
    canvas2 = Canvas(fr, bg = "yellow", width = 60, height = 60, bd=0, highlightthickness=0, relief='ridge')
    canvas2.create_image(62,-2, image = img2, anchor = "ne")
    canvas3 = Canvas(fr, bg = "yellow", width = 60, height = 60, bd=0, highlightthickness=0, relief='ridge')
    canvas3.create_image(-2,62, image = img3, anchor = "sw")
    canvas4 = Canvas(fr, bg = "yellow", width = 60, height = 60, bd=0, highlightthickness=0, relief='ridge')
    canvas4.create_image(62,62, image = img4, anchor = "se")
    Grid.columnconfigure(fr, 0, weight = 1)
    Grid.columnconfigure(fr, 1, weight = 1)
    Grid.rowconfigure(fr, 1, weight = 1)
    canvas.grid( row = 0, column = 0, sticky = 'NW' )
    canvas2.grid( row = 0, column = 1, sticky = 'NE' )
    canvas3.grid(row = 1, column = 0, sticky = 'SW' )
    canvas4.grid(row = 1, column = 1, sticky = 'SE' )
    root.overrideredirect(True)
    root.wm_attributes('-transparentcolor', "#222222")
    root.bind('<Button-1>', lambda e, root = root: click(e,root))
    root.bind('<B1-Motion>', lambda e, root = root: drag(e,root))
    root.mainloop()
    

    现在您可能会根据您在窗口中的需要更改画布的行和列,但这是一个好的开始。

    【讨论】:

      猜你喜欢
      • 2019-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多