【问题标题】:Tkinter custom windowTkinter 自定义窗口
【发布时间】:2012-08-07 05:11:05
【问题描述】:

我想在 Tk 中创建一个具有自定义标题栏和框架的窗口。我在这个网站上看到了很多关于这个的问题,但我正在寻找的是使用画布实际渲染框架,然后将内容添加到画布。我不能使用框架来执行此操作,因为边框是渐变的。

根据这个网站:http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas.create_window-method,我不能将任何其他画布项目放在小部件之上(使用 create_window 方法),但我需要这样做,因为我的一些小部件是使用画布呈现的.

关于如何做到这一点的任何建议?我在这里一无所知。

编辑:Bryan Oakley 确认使用画布进行渲染是不可能的。那么是否有可能有一个具有自定义边框颜色的框架?如果是这样,有人可以举一个简单的例子吗?我对python有点陌生。

【问题讨论】:

  • 我不明白这个问题,您的编辑使它更不清楚。是的,可以使用画布创建带有自定义边框的框架。这与在小部件上绘制画布项目无关——这是两个不同的问题。
  • 我以为有一个bordercolor属性...这对顶级框架不起作用,对吧?
  • 我没有确认“用画布渲染是不可能的”。我只是确认您不能在嵌入在画布中的小部件之上绘制画布项目。当然,您可以使用画布呈现边框和自定义标题栏。
  • 你的意思是用4个画布来画边框?
  • 您可以使用任意数量的画布。整个背景+边框只有一个,或者四个,每边一个。

标签: python tkinter custom-titlebar


【解决方案1】:

您可以像使用框架一样使用画布来绘制自己的窗口边框。但是,就像您说的那样,您不能在嵌入在画布中的小部件之上绘制画布项目;小部件始终具有最高的堆叠顺序。没有办法解决这个问题,但不清楚你是否真的需要这样做。

这里有一个快速而肮脏的例子,展示了如何为自定义边框创建一个带有渐变的窗口。为了使示例简短,我没有添加任何代码来允许您移动或调整窗口大小。此外,它使用固定颜色作为渐变。

import Tkinter as tk

class GradientFrame(tk.Canvas):
    '''A gradient frame which uses a canvas to draw the background'''
    def __init__(self, parent, borderwidth=1, relief="sunken"):
        tk.Canvas.__init__(self, parent, borderwidth=borderwidth, relief=relief)
        self._color1 = "red"
        self._color2 = "black"
        self.bind("<Configure>", self._draw_gradient)

    def _draw_gradient(self, event=None):
        '''Draw the gradient'''
        self.delete("gradient")
        width = self.winfo_width()
        height = self.winfo_height()
        limit = width
        (r1,g1,b1) = self.winfo_rgb(self._color1)
        (r2,g2,b2) = self.winfo_rgb(self._color2)
        r_ratio = float(r2-r1) / limit
        g_ratio = float(g2-g1) / limit
        b_ratio = float(b2-b1) / limit

        for i in range(limit):
            nr = int(r1 + (r_ratio * i))
            ng = int(g1 + (g_ratio * i))
            nb = int(b1 + (b_ratio * i))
            color = "#%4.4x%4.4x%4.4x" % (nr,ng,nb)
            self.create_line(i,0,i,height, tags=("gradient",), fill=color)
        self.lower("gradient")

class SampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.wm_overrideredirect(True)
        gradient_frame = GradientFrame(self)
        gradient_frame.pack(side="top", fill="both", expand=True)
        inner_frame = tk.Frame(gradient_frame)
        inner_frame.pack(side="top", fill="both", expand=True, padx=8, pady=(16,8))

        b1 = tk.Button(inner_frame, text="Close",command=self.destroy)
        t1 = tk.Text(inner_frame, width=40, height=10)
        b1.pack(side="top")
        t1.pack(side="top", fill="both", expand=True)

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

【讨论】:

  • 好的,谢谢,我明白了!关于这个还有另一个问题,我如何用 4 个画布(1xH 或 Wx1)围绕一个框架?
【解决方案2】:

这是一个粗略的例子,其中框架、标题栏和关闭按钮是用画布矩形制作的:

import Tkinter as tk

class Application(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        # Get rid of the os' titlebar and frame
        self.overrideredirect(True)

        self.mCan = tk.Canvas(self, height=768, width=768)
        self.mCan.pack()

        # Frame and close button
        self.lFrame = self.mCan.create_rectangle(0,0,9,769,
                                    outline='lightgrey', fill='lightgrey')
        self.rFrame = self.mCan.create_rectangle(760,0,769,769,
                                    outline='lightgrey', fill='lightgrey')
        self.bFrame = self.mCan.create_rectangle(0,760,769,769,
                                    outline='lightgrey', fill='lightgrey')
        self.titleBar = self.mCan.create_rectangle(0,0,769,20,
                                    outline='lightgrey', fill='lightgrey')
        self.closeButton = self.mCan.create_rectangle(750,4,760, 18,
                                            activefill='red', fill='darkgrey')

        # Binds
        self.bind('<1>', self.left_mouse)
        self.bind('<Escape>', self.close_win)

        # Center the window
        self.update_idletasks()
        xp = (self.winfo_screenwidth() / 2) - (self.winfo_width() / 2)
        yp = (self.winfo_screenheight() / 2) - (self.winfo_height() / 2)
        self.geometry('{0}x{1}+{2}+{3}'.format(self.winfo_width(),
                                                self.winfo_height(),
                                                            xp, yp))

    def left_mouse(self, event=None):
        obj = self.mCan.find_closest(event.x,event.y)
        if obj[0] == self.closeButton:
            self.destroy()

    def close_win(self, event=None):
        self.destroy()

app = Application()
app.mainloop()

如果我要制作自定义 GUI 框架,我会考虑使用图像创建它,
使用 Photoshop 等程序制作,而不是渲染画布对象。
图像可以像这样放置在画布上:

self.ti = tk.PhotoImage(file='test.gif')
self.aImage = mCanvas.create_image(0,0, image=self.ti,anchor='nw')

更多信息→here←

【讨论】:

  • 谢谢!我想我必须想办法在每边制作 4 个画布(中间有一个框架)。
猜你喜欢
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多