【问题标题】:How to draw an arc on a tkinter canvas?如何在 tkinter 画布上绘制弧线?
【发布时间】:2017-09-10 23:56:37
【问题描述】:

我正在研究自动机理论,我被要求编写一个自动机的图形(树),它看起来或多或少像:

到目前为止,我得到了这个(我正在使用 tkintercanvas 来绘制):

from tkinter import Tk, Canvas, mainloop

def circle(canvas, x, y, r, width):
   id = canvas.create_oval (x-r, y-r, x+r, y+r, width = width)
   return id

def line (canvas, x1, y1, x2, y2, width):
    canvas.create_line (x1, y1, x2, y2, width = width)

def text (canvas, x, y, text):
    canvas.create_text (x, y, text = text, font = ("bold", 20))

w = Canvas(Tk (), width=1000, height=600, bg = "white")

circle (w , 150, 300, 70, 3)
circle (w , 150, 300, 50, 3)
circle (w , 370, 300, 70, 3)
circle (w , 640, 300, 70, 3)
circle (w , 910, 300, 70, 3)

line (w, 10, 300, 80, 300, 3)
circle (w, 73, 300, 5, 6)
line (w, 220, 300, 300, 300, 3)
circle (w, 293, 300, 5, 6)
line (w, 440, 300, 570, 300, 3)
circle (w, 567, 300, 5, 6)
line (w, 710, 300, 840, 300, 3)
circle (w, 837, 300, 5, 6)

text (w, 150, 300, "q0")
text (w, 370, 300, "q1")
text (w, 640, 300, "q2")
text (w, 910, 300, "q3")

w.pack()
mainloop()

显示这个:

我不需要箭头,因为我将使用点来代替。问题是我需要从圆 q3 到圆 q0 以及从圆 q0 到圆 q0 画一条线(“圆环”)。我尝试了canvas.create_arc() 方法,但我无法掌握它。有替代方案吗?关于如何绘制“bucle”的任何想法?

【问题讨论】:

  • canvas.create_arc() 方法你有什么不明白的地方?要具体,或者更好的是,展示您使用它的尝试。顺便说一句,canvas.create_line() 方法支持箭头。
  • 我不明白该方法需要的坐标,所以我可以在任何圆上画一个圆环(我认为它是起点、终点和高度)。我如何画箭头?谢谢!
  • 你读过这个吗? infohost.nmt.edu/tcc/help/pubs/tkinter/web/create_arc.html “画布上的弧形对象,最一般的形式,是从椭圆中取出的楔形切片。...点 (x0, y0) 是左上角,(x1, y1)椭圆适合的矩形的右下角。如果这个矩形是正方形,你会得到一个圆形。"
  • " extent : 切片的宽度(以度为单位)。切片从 start 选项给出的角度开始,逆时针扩展为 extent 度数。"
  • @jcfollower:FWIW,您以原始形式提供的链接与我原始评论中的第一个超链接相同。也许应该更仔细地阅读……

标签: python canvas tkinter graphics tree


【解决方案1】:

这里有一些实用函数,它们提供了另一种在tkinter.Canvas 上绘制弧线的方法。与通常的两点规范不同,(x0, y0)(x1, y1) 定义一个封闭的矩形,圆弧函数接受在 [0..360) 度的开放范围内的开始和停止 角度

它还说明了如何在直线(但不是弧线)的末端绘制箭头,因为您也问过这个问题。

from tkinter import Canvas, mainloop, Tk

def circle(canvas, x, y, r, width):
    return canvas.create_oval(x+r, y+r, x-r, y-r, width=width)

def circular_arc(canvas, x, y, r, t0, t1, width):
    return canvas.create_arc(x-r, y-r, x+r, y+r, start=t0, extent=t1-t0,
                             style='arc', width=width)

def ellipse(canvas, x, y, r1, r2, width):
    return canvas.create_oval(x+r1, y+r2, x-r1, y-r2, width=width)

def elliptical_arc(canvas, x, y, r1, r2, t0, t1, width):
    return canvas.create_arc(x-r1, y-r2, x+r1, y+r2, start=t0, extent=t1-t0,
                             style='arc', width=width)

def line(canvas, x1, y1, x2, y2, width, start_arrow=0, end_arrow=0):
    arrow_opts = start_arrow << 1 | end_arrow
    arrows = {0b10: 'first', 0b01: 'last', 0b11: 'both'}.get(arrow_opts, None)
    return canvas.create_line(x1, y1, x2, y2, width=width, arrow=arrows)

def text(canvas, x, y, text):
    return canvas.create_text(x, y, text=text, font=('bold', 20))


w = Canvas(Tk(), width=1000, height=600, bg='white')

circle(w, 150, 300, 70, 3)  # q0 outer edge
circle(w, 150, 300, 50, 3)  # q0 inner edge
circle(w, 370, 300, 70, 3)  # q1
circle(w, 640, 300, 70, 3)  # q2
circle(w, 910, 300, 70, 3)  # q3

# Draw arc from circle q3 to q0.
midx, midy = (150+910) / 2, 300
r1, r2 = 910-midx, 70+70
elliptical_arc(w, midx, midy, r1, r2, 30, 180-30, 3)

line(w,  10, 300,  80, 300, 3, end_arrow=1)
line(w, 220, 300, 300, 300, 3, end_arrow=1)
line(w, 440, 300, 570, 300, 3, end_arrow=1)
line(w, 710, 300, 840, 300, 3, end_arrow=1)

text(w, 150, 300, 'q0')
text(w, 370, 300, 'q1')
text(w, 640, 300, 'q2')
text(w, 910, 300, 'q3')

w.pack()
mainloop()

这就是它的画法:

它没有像你想要的那样画一个“扣”,部分原因是画“一条从圆 q3 到圆 q0,从圆 q0 到圆 q0 的线”不像你问题开头的插图一个画在两个圆圈之间(如果我理解正确的话)。

但是,它确实为您提供了另一种在canvas 上绘制弧线的方法。

【讨论】:

    【解决方案2】:

    您可以使用 tkinter 画布使用 Canvas 排列点线(应该被包围)来绘制您的“桶”。这是我用“桶”形状绘制返回角度的示例。我使用 python 3.9

    import tkinter as tk
    
    def P(x,y):
        """
        For convenience only.
        Transform point in cartesian (x,y) to Canvas (X,Y)
        As both system has difference y direction:
        Cartesian y-axis from bottom-left - up 
        Canvas Y-axis from top-left - down 
        """
        X = M + (x/xmax) * (W-2*M)
        Y = M + (1-(y/ymax)) * (H-2*M)
        return (X,Y)
    
    def draw(window):
        """"
        Draw the lines
        """
        c = tk.Canvas(window, width=W, height=H)
        c.grid()
        
        # tuple of points to shape a 'bucket'
        points = P(60,0), P(90,50), P(50,100), P(10,50), P(40,0)
        
        fracture = c.create_line(points, arrow='last', fill='yellow')
        smooth = c.create_line(points, arrow='last', smooth=1)
       
    """
    xmin is minimum value along cartesian x-axis
    xmax is maximum value along cartesian x-axis
    ymin is minimum value along cartesian y-axis
    ymax is maximum value along cartesian y-axis
    W is canvas width, in pixel
    H is canvas height, in pixel
    M is minimum margin inside canvas to ensure objects like arrow fully shown.
    
    """
    M = 4  
    W = 310
    H = 210
    xmin = 0
    xmax = 100
    ymin = 0
    ymax = 100    
    
    window = tk.Tk()
    draw(window)
    window.mainloop()
    

    如果你运行上面的代码你会看到 黄色断裂线是原始点线和 同一条线的黑色平滑线,选项 Smooth 设置为 1,选项箭头设置为 'last'。

    这里是结果

    【讨论】:

      猜你喜欢
      • 2023-02-16
      • 1970-01-01
      • 2014-12-31
      • 2021-10-30
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      相关资源
      最近更新 更多