【问题标题】:Tkinter Resizable Objects Python CanvasTkinter 可调整大小的对象 Python 画布
【发布时间】:2012-09-03 23:18:12
【问题描述】:

我正在尝试使用它,以便可以使用旋转框调整 Tkinter 画布上的多个对象的大小/重新定位,旋转框中的值用作原始坐标的乘数。为了使事情稍微复杂一点,旋转框默认情况下是不可见的,它位于顶层窗口中,按下按钮时可以打开该窗口。

总结一下:
我需要使用旋转框值作为乘数(或其他方式)来更改画布上对象的坐标,该乘数本身位于顶层窗口中,并将这些更改“实时”显示在画布上。

对于上下文,我已经包含了负责设置对象等的关键外围代码。

UI 模块的基本部分:


import Canvas_1 (module for drawing shapes)

root=Tk()

#root geometry, title set up
#UI then commands set up
canvasBlank=Canvas(root, width... etc) #Blank canvas that is drawn at start
canvasBlank.grid(row... etc)
canvasBlank.bind('Button-3', rightclickcanvas) #Right click function that opens a popup for canvas options
#Other misc commands, I'm using a menubar with drop down options over actual Tk.Buttons
#'New' option in menubar has Command to create objects in UI like:

def createObject():
     Objects=MyObjects(root, width... etc)
     Objects.grid(row... etc) #Same as layout for canvasBlank
     Objects.bind('<Button-3>', rightclickcanvas)
     Objectslist.append(Objects) #Stop garbage disposal and makes sure the canvas displays

-MyObjects 类(在单独的模块中)的形式类似于:

from Coordinate_Generator import * #imports coordinate arrays

class MyObjects(tk.Canvas)
    def __init__(self, master, **kw)
        tk.Canvas.__init__(self, master, **kw)
        self.create_oval(coordinates[0], dimensions[0], fill... etc)
        self.create_oval(coordinates[1], dimensions[1], fill... etc)
#A series of bindings relating to moving objects under mouse clicks

坐标是使用“a”确定的,一个任意值。我尝试乘以: 缩放器=[] a=70*scaler[-1]

这种方法似乎也不起作用,如果它起作用了,它也意味着可能会在彼此之间绘制大量的画布,这是我想避免的。我希望这能证明我需要更清楚地尝试和使用的方法。我已经使用给出的建议编写了一些代码,虽然它可能对我计划的程序的另一部分有用,但它并没有完全实现我所追求的。所以我拼凑了这个“演示”来说明我正在尝试做的事情。

工作代码(解决方案)

from Tkinter import *
from numpy import *
import Tkinter as tk

scale=1

class Demonstrator:

   def __init__(self, master=None): 
      global full_coordinates, dimensions, scale
      self.master=master
      self.master.title( "Demonstrator 2")
      self.master.grid()
      self.master.rowconfigure(0, weight=1)
      self.master.columnconfigure(0, weight=1)

      self.canvas = Canvas(self.master, width=300, height=300, bg='grey')
      self.canvas.grid(row=0, rowspan=3, column=0)
      self.canvas.create_rectangle(full_coordinates[0],dimensions[0], activefill='blue', fill='red')
      self.canvas.create_rectangle(full_coordinates[1],dimensions[1], activefill='blue', fill='red')
      self.canvas.create_line(full_coordinates[0],full_coordinates[1], fill='red')

      a=9*scale
      Originx=10
      Originy=35
      coordinates1=[]
      coordinates2=[]

      x,y,i=Originx,Originy,1
      x1,y1,i=Originx,Originy,1

      while len(coordinates1)<=25:
       coordinates1.append((x,y))
       coordinates2.append((x1,y1))

       i+=1
       if i % 2 == 0:
            x,y=x+a,y
            x1,y1=x1,y1+a
       else:
            x,y=x,y+a
            x1,y1=x1+a,y1

       full_coordinates=list(set(coordinates1+coordinates2))
       b=array(full_coordinates)
       k=b+10
       dimensions=k.tolist()

class Settings:
    def __init__(self, parent):

        top = self.top = tk.Toplevel(parent)
        self.top.title('Settings')

        self.spinbox_Label= tk.Label(top, text='Change Scale Factor?')
        self.spinbox_Label.grid(row=0, column=0, columnspan=2)

        self.spinbox_Label= tk.Label(top, width=30, text='Scale factor:')
        self.spinbox_Label.grid(row=1, column=0)

        self.spinbox= tk.Spinbox(top, from_=1, to=10, increment=0.1, command=self.change)
        self.spinbox.grid(row=1, column=1)


    def change(self):
        global scale
        scale=float(self.spinbox.get())
        MG=Demonstrator(root) #This just generates a new Demonstrator with original coordinates

def onClick():
    inputDialog = Settings(root)
    root.wait_window(inputDialog.top)

def onClick2():
    print scale

class coords:
    global full_coordinates, dimensions, scale
    print scale
    a=9*scale
    Originx=10
    Originy=35
    coordinates1=[]
    coordinates2=[]

    x,y,i=Originx,Originy,1
    x1,y1,i=Originx,Originy,1

    while len(coordinates1)<=25:
       coordinates1.append((x,y))
       coordinates2.append((x1,y1))

       i+=1
       if i % 2 == 0:
            x,y=x+a,y
            x1,y1=x1,y1+a
       else:
            x,y=x,y+a
            x1,y1=x1+a,y1

       full_coordinates=list(set(coordinates1+coordinates2))
       b=array(full_coordinates)
       k=b+10
       dimensions=k.tolist()    




root=Tk()
root.minsize=(700,700)
root.geometry=('600x600')
MG=Demonstrator(root)
mainButton2 = tk.Button(root, width=20, text='Print "scale"', command=onClick2)
mainButton2.grid(row=1, column=1)
mainButton = tk.Button(root, width=20, text='Settings', command=onClick)
mainButton.grid(row=2, column=1)
root.mainloop()
mainButton2.grid(row=1, column=1)
mainButton = tk.Button(root, width=20, text='Settings', command=onClick)
mainButton.grid(row=2, column=1)
root.mainloop()

问题
使用旋转框更改画布上对象的大小(通过更改坐标)的最佳方法是什么?
我希望这足以提供信息,当然如果需要我可以提供更多信息。我也提前为这个问题的格式道歉,我是新手:)
(添加解决方案) 任何帮助都是极好的。干杯。
标记

【问题讨论】:

  • 我在这里没有看到问题。您是在问如何使用旋转框吗?顶层窗户?整数变量?您需要帮助调整画布上的对象大小吗?您希望我们为您编写代码吗?
  • 抱歉,为了清楚起见,我将编辑帖子。我知道如何使用微调框、顶级窗口和 IntVars,我正在寻找一种方法来使用顶级窗口中的微调框调整画布上对象的大小。我也会发布我的尝试。我也不需要明确编写的代码,尽管类似的示例可能有用。对于不够清晰,我深表歉意。
  • 即将尝试实施您的建议,感谢您的帮助,如果可行,我会通知您。

标签: python class canvas tkinter


【解决方案1】:

解决方案没有什么特别之处。您只需为调整画布项目坐标的微调框定义一个回调(可以使用画布的coords 方法完成)。

首先,您可能想要创建一个 dict 来包含每个项目的基本宽度和高度。这个字典的键也可以是与画布项目相关联的标签。例如:

self.base_dimensions = {
    "obj1": (10,10),
    "obj2": (20,20),
    ...
}

接下来,使用这些键作为标签在画布上创建项目。例如:

...
self.canvas.create_rectangle(..., tags=("obj1",))
self.canvas.create_rectangle(..., tags=("obj2",))
...

最后,您可以使用相同的键将微调框小部件保存在字典中(这样您就可以将微调框与画布对象相关联),并为微调框分配一个回调来调整大小。例如:

self.spinbox = {
    "obj1": tk.Spinbox(..., command=lambda self.do_resize("obj1")),
    "obj2": tk.Spinbox(..., command=lambda self.do_resize("obj2")),
    ...
}

给定一个标签,您的回调可以使用它来获取对旋转框小部件的引用并获取它的值,然后使用该标签告诉画布对象要调整哪些项目的大小。例如:

def do_scale(self, tag):
    factor = int(self.spinbox[tag].get())
    (width, height) = self.default[tag]
    (x0,y0,x1,y1) = self.canvas.coords(tag)
    width = factor * width
    height = factor * height
    x1 = x0 + width
    y1 = y0 + height
    self.canvas.coords(tag, x0,y0,x1,y1)

当然,组织数据的方法有很多种;我所展示的不是最好的方法,也不是唯一的方法。它甚至可能不适用于您组织代码的方式。无论您选择什么,归结为能够从旋转框中获取值并使用它来调整画布项目的坐标。

【讨论】:

  • 感谢您的回复,我已经尝试实现您的方法,但我认为它与我的坐标生成方式不兼容。我的坐标在一个长度为 30+ 的数组中,这意味着标记每个条目会很耗时。我只是在寻找一种将整个数组乘以旋转框的值的方法。然后当 spinbox 的值改变时,画布会立即用新的坐标更新。效果是用户会去 File -> Resize (spinbox widget) -> altering spinbox 实时改变所有画布对象。抱歉我的蹩脚解释。
  • @MarkyD43:我不明白你关于标记坐标的评论。我不太清楚你的意思是什么,我不明白你为什么认为这会很耗时。打字很费时间?跑步?至于实时更新项目,我的示例说明了这一点。当用户点击旋转框时,您可以轻松调整数百个甚至数千个项目的大小。
  • 我很可能误解了你的建议,但我的坐标是在一个单独的模块中由几个方程和一个变量自动生成的(在我给出的示例中,这是我改变后的变量它只是'a'),因此我无法像您的示例中那样为每组坐标添加标签。如果我从头开始构建它,我会使用你的方法,但不幸的是,这是我添加到一个几乎完成的程序中的一个功能。我已经用代码的基本布局更新了我上面的尝试,希望能给出上下文。再一次,很抱歉在这方面做得很慢,自学成才
  • @MarkyD43:只要您可以将原始坐标与画布上的每个项目相关联,您如何操作都没有关系。关键是,您在 spinbox 上使用回调将原始值乘以 spinbox 的值,并使用coords 方法更新画布上的项目。
  • 好的,我再试一次。我想知道我在尝试执行此操作时遇到的错误是否来自坐标生成器(构建坐标数组的位置)、构建对象的画布类以及旋转框所在的 UI在三个独立的模块中?我想我只是感到困惑,不过我很感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2014-05-15
  • 2016-07-26
  • 1970-01-01
  • 2022-01-15
  • 2020-11-22
  • 2021-08-24
相关资源
最近更新 更多