2012-08-09 166 views
1

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

根据这个网站:http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas.create_window-method,我不能把上的小工具(使用create_window法)顶部的任何帆布项目,但我必须这样做,因为我的一些小部件的使用画布渲染。

有关如何做到这一点的任何建议?我在这里无能为力。

编辑:Bryan Oakley证实用画布渲染是不可能的。那么是否可以有一个自定义边框颜色的框架?如果是这样,有人可以举个简单的例子吗?我有点新的python。

+0

我不明白的问题,你的编辑使它更加明确。是的,可以使用画布创建带有自定义边框的框架。这与在小部件顶部绘制画布项无关 - 这是两个不同的问题。 – 2012-08-10 01:53:38

+0

我以为有bordercolor属性......这不适用于顶级框架,对吧? – MiJyn 2012-08-10 02:06:44

+0

我没有确认“用画布渲染是不可能的”。我只是确认,您不能在画布中嵌入的小部件顶部绘制画布项目。当然,您可以使用画布呈现边框和自定义标题栏。 – 2012-08-10 02:12:01

回答

2

您可以使用画布,就好像它是一个框架,以绘制您自己的窗口边框。然而,就像你说的那样,你不能在画布中嵌入的小部件上画画布;小部件始终具有最高的堆叠顺序。这是没有办法的,尽管目前还不清楚你是否真的需要这样做。

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

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() 
+0

感谢您的解释!我已更新我的问题 – MiJyn 2012-08-10 00:52:48

+0

好的,谢谢,我现在看到了!还有一个关于这个的问题,我将如何用4个画布(1xH或者Wx1)围绕一个框架? – MiJyn 2012-08-12 17:09:37

1

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

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←

+0

谢谢!我想我必须找出一种方法在每一面上制作4幅画布(以及中间的一幅画框)。 – MiJyn 2012-08-10 16:16:00