用方法create_bitmap在Canvas上生成xbm文件图像创建win10风格工具栏

win10和winXP程序工具栏有很大不同,工具栏中没有传统按钮等组件,而是由很多图形代替按钮的功能,如下图。这是win10画图程序选择画图类型的工具栏,这些图形只能选择其中一个,并保持选中状态,直到选中其它图形。当鼠标移到图形上方,图形背景改变颜色。当单击图形被选中,图形背景变为另一种颜色,并保持这种颜色。这些图形按钮是互斥的。
在这里插入图片描述
本文介绍用Python实现该风格工具栏的方法。基本思路是创建多个Canvas实例,其中一个作为工具栏。用Canvas的方法create_bitmap在作为工具栏的Canvas上生成多个由xbm格式文件定义的位图图像,这些图像都能响应鼠标单击事件,用事件函数完成指定工作。这里把自己的一些思路过程写在这里,如感觉无用,可直接看最后有关用Canvas的方法create_bitmap创建工具栏部分。
首先想到最简单方法,用Canvas的create_多个方法在Canvas上放置多个图形(不包括图像),例如矩形、直线和椭圆等,它们都能响应鼠标单击事件,这些图形都有属性activefill和fill,如是封闭图形,这两个属性是填充色,如是线,是线的颜色。其中activefill是在鼠标移到图形上方显示的颜色。属性fill可在未选中是一种颜色,选中是另一种颜色。这样就能基本实现上述功能。缺点是明显的,鼠标各种动作,显示的图形颜色的面积都不同,特别是线,只是线的颜色改变。这对程序使用者来说,界面不友好。
另一思路是作为按钮的图形由两部分组成,一个正方形在下边作为背景,能响应鼠标事件,其属性activefill设定指定颜色,未被选中时fill颜色和Canvas底色相同,选中时设定为指定颜色。正方形上方是要显示的相应图形,如矩形、直线和椭圆等,比底部正方形要小一些,不响应鼠标事件,颜色保持不变,仅仅为显示图形。当时觉得方法不错,编写了完整程序,见下面。运行后发现,当鼠标移到上边图形外轮廓线时,其下方正方形不能按属性activefill颜色而改变,单击上边图形外轮廓线时,其下方正方形不响应单击事件。尽管上边图形外轮廓线很细,影响很小,但对程序使用者来说,界面也不友好。

import tkinter as tk
root = tk.Tk()
root.geometry('300x300')
def cleanAllGround(event):  #使画线、画矩形和画椭圆图形都不被选中,即下方正方形填充色和Canvas底色相同
    global useTag
    cv1.itemconfig('G', fill='#CCFFFF')     #所有tag为'G'的图形其填充色和Canvas底色相同
    useTag='stop'           #停止画图标志为Stop
def chooseButton(event):
    global useTag
    allID=cv1.find_closest(event.x,event.y)  #返回列表包含被单击处所有图形ID
    if len(allID) > 0:       #列表长度为0,没有图形被选中,如不为0,选中图形ID为allID[0]
    #返回列表包括该图形所有tag值,这里列表值是['G','line'或'rectangle'或'oval','current']    
        allTag=cv1.gettags(allID[0])
        useTag=allTag[1]        #第2个可能是'line'或'rectangle'或'oval'
        cv1.itemconfig('G', fill='#CCFFFF')     #3个图形都不被选中,背景色为工具栏底色          
        cv1.itemconfigure(allID[0],fill='#00CCFF')  #被点击图形被选中,背景色为较浅蓝色
cv1 = tk.Canvas(root, height=40, width=300,bg='#CCFFFF')           #工具栏Canvas,注意底色bg='#CCFFFF'
cv1.pack()
cv1.create_bitmap(120,20,bitmap="error",foreground='red',activebackground='lightskyblue',tag='stop')#python自带位图
#下方正方形,响应事件,根据需要改变正方形activefill和fill颜色,
cv1.create_rectangle(5,5,35,35,fill='#CCFFFF',activefill='lightskyblue',outline='#CCFFFF',tag=('G','line'))
cv1.create_line(10, 10, 30, 30) #所生成的线在上句生成的正方形上方,不响应事件,不改变颜色,仅仅显示图形
cv1.create_rectangle(40,5,70,35,fill='#CCFFFF',activefill='lightskyblue',outline='#CCFFFF',tag=('G','rectangle'))
cv1.create_rectangle(45, 10, 65, 30)
cv1.create_rectangle(75,5,105,35,fill='#CCFFFF',activefill='lightskyblue',outline='#CCFFFF',tag=('G','oval'))
cv1.create_oval(80,10,100,30)
cv = tk.Canvas(root,height=250,width=300,bg='#FFFFFE')      #画图的Canvas
cv.pack()
cv1.tag_bind("stop",'<Button-1>',cleanAllGround)
cv1.tag_bind('G','<Button-1>',chooseButton)
useTag='stop'       #程序根据此变量值,决定画那种图形。
root.mainloop()#tag=("A"+n,"R")

Canvas方法create_bitmap有属性background和activebackground,头一个属性是背景色,当该图像选中或未被选中时,图像背景色能被改变,第二个属性是当鼠标移到图像上方时的背景色。而方法create_image没有这两个属性,只能用create_bitmap方法实现。首先想到的是创建位图文件,用如下代码使用,但报错,此路不通。

p = tk.PhotoImage(file='pic/myBitmap.bmp')
cv.create_bitmap(20,20,bitmap=p)	      #bitmap不接受实例ID,似乎只能是带路径文件名

发现方法create_bitmap方法可使用xbm格式位图文件。因此首先要创建xbm格式位图文件。具体方法如下:用win10画图程序画一个图形,例如矩形、直线或椭圆等,其外边界宽高各为30像素,然后保存为24位位图(.bmp;.dib)格式,未实验保存为其它格式,如png格式,能否转换为xbm格式。打开网页https://convertio.co/zh/jpg-xbm/。在网页中将要被转换文件的扩展名改为:BMP,选择并上传要转换的BMP文件后,点击转换,完成后下载即可得到XBM文件。
创建4个xbm文件,用下边4条语句生成4个xbm文件定义的图形,单击图形以选择画直线、画矩形、画椭圆和停止画图。首先要将这4个文件拷贝到要运行的python源程序所在文件夹的子文件夹pic中。语句中属性bitmap="@pic/line.xbm"是到指定文件夹中读取line.xbm文件。activebackground是鼠标移到图形上方时背景的颜色。前3条语句有2个tag值,共同的’G’,通过它可以为3个图形绑定共同的鼠标单击事件函数,也可以通过它操作3个图形的共同属性,例如,去掉被选中状态,即设定背景色为工具栏的底色,也就是令background=’#CCFFFF’。根据第2个tag值,确定单击本图形画那种图形,是直线、矩形还是椭圆。具体代码如下。

cv1.create_bitmap(20,20,bitmap="@pic/line.xbm",activebackground='lightskyblue',tag=('G','line'))
cv1.create_bitmap(60,20,bitmap="@pic/rec.xbm",activebackground='lightskyblue',tag=('G','rectangle'))
cv1.create_bitmap(100,20,bitmap="@pic/circle.xbm",activebackground='lightskyblue',tag=('G','oval'))
cv1.create_bitmap(140,20,bitmap="@pic/stop.xbm",activebackground='lightskyblue',tag='stop')

分别为tag='G’和tag='stop’的图形绑定鼠标单击事件的事件函数。

cv1.tag_bind("stop",'<Button-1>',cleanAllGround)
cv1.tag_bind('G','<Button-1>',chooseButton)

事件函数cleanAllGround()功能,停止画图形,使画直线、画矩形和画椭圆图形都不被选中,即tag='G’的图形背景色为工具栏底色。变量useTag=‘stop’。
事件函数chooseButton功能,首先找到被点击处的图形ID,首先使tag='G’的所有图形都不被选中,再根据被点击处的图形ID,使该图形被选中,即选中被单击的图形,变量useTag根据选中图形,被设置为:‘line’、‘rectangle’或’oval’,告诉程序当前要画那种图形。
下边是完整程序。特别注意,4个xbm文件要拷贝到要运行的python源程序所在文件夹的子文件夹pic中。仅仅拷贝源程序不能运行。

import tkinter as tk
root = tk.Tk()
root.geometry('300x300')
def cleanAllGround(event):
    global useTag
    cv1.itemconfig('G', background='#CCFFFF')#设置tag='G'的图形背景色为工具栏底色,即都不被选中
    useTag='stop'   #停止画图标志为Stop
def chooseButton(event):
    global useTag
    allID=cv1.find_closest(event.x,event.y)     #返回列表包含被单击处所有图形ID
    if len(allID) > 0:      #列表长度为0,没有图形被选中,如不为0,选中图形ID为allID[0]
    #返回列表包括该图形所有tag值,这里列表值是['G','line'或'rectangle'或'oval','current']
        allTag=cv1.gettags(allID[0])
        useTag=allTag[1]        #第2个可能是'line'或'rectangle'或'oval'
        cv1.itemconfig('G', background='#CCFFFF')  #3个图形都不被选中,背景色为工具栏底色         
        cv1.itemconfigure(allID[0],background='#00CCFF') #被点击图形被选中,背景色为较深蓝色
cv1 = tk.Canvas(root, height=40, width=300,bg='#CCFFFF')   #工具栏Canvas,注意底色bg='#CCFFFF'
cv1.pack()
#cv1.create_bitmap(20,20,bitmap=b1,foreground='red',activebackground='lightskyblue')#报错
#文件line.xbm、rec.xbm、circle.xbm和stop.xbm要拷贝到本程序源文件所在的文件夹的子文件夹pic
cv1.create_bitmap(20,20,bitmap="@pic/line.xbm",activebackground='lightskyblue',tag=('G','line'))
cv1.create_bitmap(60,20,bitmap="@pic/rec.xbm",activebackground='lightskyblue',tag=('G','rectangle'))
cv1.create_bitmap(100,20,bitmap="@pic/circle.xbm",activebackground='lightskyblue',tag=('G','oval'))
cv1.create_bitmap(140,20,bitmap="@pic/stop.xbm",activebackground='lightskyblue',tag='stop')
cv1.tag_bind("stop",'<Button-1>',cleanAllGround)
cv1.tag_bind('G','<Button-1>',chooseButton)
useTag='stop'                   #程序根据此变量值,决定画那种图形。
cv = tk.Canvas(root,height=250,width=300,bg='#7FFFFE')          #画图的Canvas
cv.pack()
root.mainloop()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值