python - tkinter,如何跨按钮拖动?

标签 python python-3.x tkinter

所以我有一个简单的程序,当您单击网格中的按钮时,它将填充一种颜色。我希望能够拖动按钮并填充它们,而不像现在您必须单击每个按钮。这可以吗?

这是我的代码,可能不是最好的:

from tkinter import *

root=Tk()

grid= Frame(root)
grid.pack()

img0=PhotoImage(file="0.png")
img1=PhotoImage(file="1.png")
img2=PhotoImage(file="2.png")

fill = 1

class button:

    def __init__(self, x, y):

        self.type=0

        self.but=Button(grid,command=self.change, image=img0, borderwidth=0)
        self.but.grid(row=y, column=x)

    def change(self):

        if self.type==fill:
            self.but.config(image=img0)
            self.type=0
        else:
            self.but.config(image=eval("img"+str(fill)))
            self.type=fill

def create(x,y):

    grid_buttons = []

    for Y in range(y):
        grid_buttons.append([])
        for X in range(x):
            grid_buttons[Y].append(button(X, Y))

create(15,15)

root.mainloop()

最佳答案

这是一种方法:

from tkinter import *

root=Tk()

grid= Frame(root)
grid.pack()

img0=PhotoImage(file="0.png")
img1=PhotoImage(file="1.png")
img2=PhotoImage(file="2.png")

fill = 1

class button:

    def __init__(self, x, y):

        self.type=0

        self.but=Button(grid,command=self.change, image=img0, borderwidth=0)
        self.but.grid(row=y, column=x)

        #Changed
        self.already_changed = False

    def change(self):
        if self.type==fill:
            self.but.config(image=img0)
            self.type=0
        else:
            self.but.config(image=eval("img"+str(fill))) #I left this in here, but you should NEVER use eval(). It's unsafe.
            self.type=fill

    #Changed
    def mouse_entered(self):
        if not self.already_changed:
            self.change()
            self.already_changed = True

    def mouse_up(self):
        self.already_changed = False

#Changed
class Container:
    def __init__(self, x, y):
        grid_buttons = []

        for Y in range(y):
            grid_buttons.append([])
            for X in range(x):
                grid_buttons[Y].append(button(X, Y))

        self.buttons = grid_buttons
        grid.bind_all("<Button-1>", self.mouse_down)
        grid.bind_all("<ButtonRelease-1>", self.mouse_up)
        grid.bind_all("<B1-Motion>", self.mouse_motion)
        self.mouse_pressed = False

    def mouse_down(self, e):
        self.mouse_pressed = True

    def mouse_up(self, e):
        self.mouse_pressed = False
        for row in self.buttons:
            for but in row:
                but.mouse_up()

    def mouse_motion(self, e):
        for row in self.buttons:
            for but in row:
                if grid.winfo_containing(e.x_root, e.y_root) is but.but:
                    but.mouse_entered()

container = Container(15,15)

root.mainloop()

现在,我注意到您所做的一些事情不太符合 Python 风格。因此,这里有一个更严格遵循 Python 约定的版本。请注意,这是完全不同的。

from tkinter import *

root = Tk()

images = {0: PhotoImage(file="0.png"),
          1: PhotoImage(file="1.png"),
          2: PhotoImage(file="2.png")}

fill = 1

class MyButton(Button): #Convention is for class names to start with uppercase letters
    def __init__(self, master):
        super(MyButton, self).__init__(master, image = images[0], borderwidth = 0)
        self.type = 0
        self.already_changed = False

    def change(self):
        if self.type == fill:
            self.type = 0
        else:
            self.type = fill
        self.config(image=images[self.type])

    def mouse_entered(self):
        if not self.already_changed:
            self.change()
            self.already_changed = True

    def mouse_up(self):
        self.already_changed = False

class Container(Frame):
    def __init__(self, master, width, height):
        super(Container, self).__init__(master)

        buttons = []

        for y in range(height):
            buttons.append([])
            for x in range(width):
                button = MyButton(self)
                button.grid(row = x, column = y)

                buttons[y].append(button)

        self.buttons = buttons

        self.bind_all("<Button-1>", self.mouse_down)
        self.bind_all("<ButtonRelease-1>", self.mouse_up)
        self.bind_all("<B1-Motion>", self.mouse_motion)

        self.mouse_pressed = False

    def mouse_down(self, e):
        self.update_containing_button(e)
        self.mouse_pressed = True

    def mouse_up(self, e):
        self.mouse_pressed = False
        for row in self.buttons:
            for button in row:
                button.mouse_up()

    def mouse_motion(self, e):
        self.update_containing_button(e)

    def update_containing_button(self, e):
        for row in self.buttons:
            for button in row:
                if self.winfo_containing(e.x_root, e.y_root) is button:
                    button.mouse_entered()

grid = Container(root, 15, 15)
grid.pack()

root.mainloop()

为什么要同时发布这两个内容?因为看起来您在实际应用程序中有更多代码(这很好,这是一个最小的示例)。我不想强制您重写我的代码以使其与您的其余代码兼容,反之亦然。

两个版本之间的功能差异:

  • 第二个版本已进行修改,因此它使用面向对象的功能而不是全局变量,使其更加灵活且更易于更改。

  • 第二个版本删除了按钮本身的绑定(bind),而是让容器处理所有内容。

关于python - tkinter,如何跨按钮拖动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46865046/

相关文章:

python - 如何删除最后打印的字符? python 3

user-interface - python 3.2 的哪个 gui 框架

python - 为什么这会不同步?

python - 删除内容后如何设置 tkinter 条目验证

python - Tkinter .after 方法卡住窗口?

python - DRF 操作中的原子事务?

python - AttributeError : 'list' object has no attribute 'isdigit' . 有效指定句子列表中每个单词的 POS?

python - U模式和w+模式下如何写文件?

Python遍历列表并计算特定值的项目

python - 带有日期索引的 pandas 数据框 -> 插入 MySQL