2015-07-30 3 views
1

В моем проекте я использовал кнопки Tkinter с фоном gif как изображение. Теперь у меня есть требование добавить «значок», заданный как строка base64. Tkinter Button не предоставляет возможность добавить значок или второе изображение. Вот почему я создал пользовательскую кнопку, используя canvas. Код ниже:Как отключить объект холста Tkinter

from Tkconstants import DISABLED 
from Tkinter import Tk, Canvas 
import Tkinter 
import base64 

import ImageTk 


_FONTCOLOR = "#FFFFFF" 
_BGCOLOR = "#787878" 
_ICONDATA = '''iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGXRFWHRTb2Z0d2FyZQBBZ 
G9iZSBJbWFnZVJlYWR5ccllPAAAAUJJREFUeNrsVc1qhDAQHq20FnRP7kF68iB9D+99Dp/J5+jdR9Bz8VwU 
PChbQbdo00yYLLuSrW4x9NKBjy+RL5nMZ34MxhjoDBM0h/YExoy3DCYnRtxx3BMbV8QTxxdVvaT7JGYWiV2 
OPbE1GywH9RwDh83xqEiCupHjg6Mmnixa+T5JkrelmuM4fimK4nVJF4bhM6cjLkqWu1vp69P8Q9u2MI7j/P 
OO5hV+yn9wEVEUqRI8yAZOmuc5NE0DWZbBMAznupN95o276KQryxI8z4MgCMD3fajrWqn79Tnoug5c1xVtZ 
LRq04Om8H3bBI7jQN/3oo2M/U0ToO9VVQlrkLH/UwJ2y/HHsG0b97vYRcjYV+mss5N6EWmaqhIc5zZdsWaS 
SUzqHFZW8L5Sd5CLNqgKbXeR9ttU/3vw/yb/eYJvAQYA4v5708p9noAAAAAASUVORK5CYII=''' 


class DesktopBtn(Tkinter.Button): 

    def __init__(self, parent, buttonName, connector=None, **options): 
     ''' 
     @param buttonName: Name of the button 

     ''' 
     Tkinter.Button.__init__(self, parent, **options) 
     self._imagePath = 'button.gif' 
     self._BtnPresspath = 'buttonP.gif' 
     self._BtnPressImage = Tkinter.PhotoImage(file=self._BtnPresspath) 
     self._image = Tkinter.PhotoImage(file=self._imagePath) 
     self.bind('<ButtonPress-1>', self._on_pressed) 
     self.bind('<ButtonRelease-1>', self._on_release) 
     self._parent = parent 
     self._btnName = buttonName 
     self._connector = connector 
     self.config(width=70, 
        height=65, 
        borderwidth=0, 
        compound=Tkinter.CENTER, 
        font=("Arial", 9, "bold"), 
        foreground=_FONTCOLOR, 
        activebackground=_BGCOLOR, 
        text=buttonName, 
        wraplength=64, 
        image=self._image, 
        command=self._onClickSwitch, 
        state="disabled") 

    def _on_pressed(self, event): 
     if self.cget("state") != "disabled": 
      self.config(relief="flat") 
      self.config(image=self._BtnPressImage) 

    def _on_release(self, event): 
     if self.cget("state") != "disabled": 
      self.config(image=self._image) 

    def _onClickSwitch(self): 
     self.config(relief="flat") 
     if self._connector: 
      self._connector.switchDesktop(self._btnName, 
              "test") 

    def getButtonName(self): 
     return self._btnName 

    def setConnector(self, connector): 
     self._connector = connector 


class CustomButton(Canvas): 
    def __init__(self, parent, buttonname=None, icon=None, command=None): 
     Canvas.__init__(self, parent, borderwidth=0, highlightthickness=0) 
     self.command = command 
     self._imagePath = 'button.gif' 
     self._BtnPresspath = 'buttonP.gif' 
     self._icon = icon 
     self._BtnPressImage = Tkinter.PhotoImage(file=self._BtnPresspath) 
     self._image = Tkinter.PhotoImage(file=self._imagePath) 
     self.bgimage = self.create_image(35, 35, image=self._image) 
     self.text = buttonname 
     if self._icon: 
      self._icondata = base64.b64decode(self._icon) 
      self._iconimage = ImageTk.PhotoImage(data=self._icondata) 
      self.create_image(35, 35, image=self._iconimage) 
     if self.text and self._icon: 
      self.create_text(35, 63, anchor="s", 
          state=DISABLED, 
          text=self.text, 
          font=("arial", 9, "bold"), 
          fill=_FONTCOLOR) 
     elif not self._icon: 
      self.create_text(35, 45, anchor="s", 
          state=DISABLED, 
          text=self.text, 
          font=("arial", 9, "bold"), 
          fill=_FONTCOLOR) 
     self.configure(width=70, height=70, state=DISABLED) 
#   if self.cget("state") == "disabled": 
#    pass 
#   else: 
     self.bind("<ButtonPress-1>", self._on_press) 
     self.bind("<ButtonRelease-1>", self._on_release) 

    def _on_press(self, event): 
     self.itemconfig(self.bgimage,image=self._BtnPressImage) 
     print "pressed" 

    def _on_release(self, event): 
     self.itemconfig(self.bgimage,image=self._image) 
     if self.command is not None: 
      self.command() 

tk = Tk() 
but = DesktopBtn(tk, "test") 
but.pack() 
butt_blank = CustomButton(tk) 
butt_text = CustomButton(tk, buttonname="test") 
butt_icon = CustomButton(tk, icon=_ICONDATA) 
butt_icon_text = CustomButton(tk, icon=_ICONDATA, buttonname="test") 
butt_blank.pack() 
butt_text.pack() 
butt_icon.pack() 
butt_icon_text.pack() 
tk.mainloop() 

Первая кнопка (класс) - это кнопка Tkinter, которую я использовал. Теперь у меня есть только проблема. Как отключить пользовательскую кнопку canvas, как обычный Tkinter Button. Он должен быть серого и игнорировать события мыши. Согласно Tkinter 8.5 reference с использованием состояния DISABLED на create_image или даже на холсте, моя пользовательская кнопка должна вести себя как старая кнопка. Я использую Python 2.7.

Вот кнопки изображение, используемое (button.gif и buttonP.gif): button.gif buttonP.gif

+0

, а не изобретать колесо, не лучше ли использовать библиотеку изображений python для объединения изображений в один? таким образом вы могли бы просто использовать стандартный (надежный) виджет? –

+0

@JamesKent хорошо это одно возможное обходное решение. Но все же я хочу знать, почему состояние инвалидов не работает. Может быть, позже я захочу добавить некоторые эффекты для Button, поэтому в любом случае мне понадобится холст. – VRage

ответ

0

Вот еще один обходной путь, он рисует rectangle поверх других элементов, залейте его белым цветом и stipple его с Bitmap в моем примере gray50: self.create_rectangle(-1,-1,70,70, stipple="gray50", fill="white")

Вот как выглядит код:

from Tkconstants import DISABLED, NORMAL 
from Tkinter import Tk, Canvas 
import Tkinter 
import base64 

import ImageTk 


_FONTCOLOR = "#FFFFFF" 
_BGCOLOR = "#787878" 
_ICONDATA = '''iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGXRFWHRTb2Z0d2FyZQBBZ 
G9iZSBJbWFnZVJlYWR5ccllPAAAAUJJREFUeNrsVc1qhDAQHq20FnRP7kF68iB9D+99Dp/J5+jdR9Bz8VwU 
PChbQbdo00yYLLuSrW4x9NKBjy+RL5nMZ34MxhjoDBM0h/YExoy3DCYnRtxx3BMbV8QTxxdVvaT7JGYWiV2 
OPbE1GywH9RwDh83xqEiCupHjg6Mmnixa+T5JkrelmuM4fimK4nVJF4bhM6cjLkqWu1vp69P8Q9u2MI7j/P 
OO5hV+yn9wEVEUqRI8yAZOmuc5NE0DWZbBMAznupN95o276KQryxI8z4MgCMD3fajrWqn79Tnoug5c1xVtZ 
LRq04Om8H3bBI7jQN/3oo2M/U0ToO9VVQlrkLH/UwJ2y/HHsG0b97vYRcjYV+mss5N6EWmaqhIc5zZdsWaS 
SUzqHFZW8L5Sd5CLNqgKbXeR9ttU/3vw/yb/eYJvAQYA4v5708p9noAAAAAASUVORK5CYII=''' 


class DesktopBtn(Tkinter.Button): 

    def __init__(self, parent, buttonName, connector=None, **options): 
     ''' 
     @param buttonName: Name of the button 

     ''' 
     Tkinter.Button.__init__(self, parent, **options) 
     self._imagePath = 'button.gif' 
     self._BtnPresspath = 'buttonP.gif' 
     self._BtnPressImage = Tkinter.PhotoImage(file=self._BtnPresspath) 
     self._image = Tkinter.PhotoImage(file=self._imagePath) 
     self.bind('<ButtonPress-1>', self._on_pressed) 
     self.bind('<ButtonRelease-1>', self._on_release) 
     self._parent = parent 
     self._btnName = buttonName 
     self._connector = connector 
     self.config(width=70, 
        height=65, 
        borderwidth=0, 
        compound=Tkinter.CENTER, 
        font=("Arial", 9, "bold"), 
        foreground=_FONTCOLOR, 
        activebackground=_BGCOLOR, 
        text=buttonName, 
        wraplength=64, 
        image=self._image, 
        command=self._onClickSwitch 
        ) 

    def _on_pressed(self, event): 
     if self.cget("state") != "disabled": 
      self.config(relief="flat") 
      self.config(image=self._BtnPressImage) 

    def _on_release(self, event): 
     if self.cget("state") != "disabled": 
      self.config(image=self._image) 

    def _onClickSwitch(self): 
     self.config(relief="flat") 
     if self._connector: 
      self._connector.switchDesktop(self._btnName, 
              "test") 

    def getButtonName(self): 
     return self._btnName 

    def setConnector(self, connector): 
     self._connector = connector 


class CustomButton(Tkinter.Canvas): 
    def __init__(self, parent, buttonname=None, icon=None, command=None, **options): 
     Tkinter.Canvas.__init__(self, parent, borderwidth=0, highlightthickness=0,**options) 
     self.command = command 
     self._imagePath = 'button.gif' 
     self._BtnPresspath = 'buttonP.gif' 
     self._icon = icon 
     self._BtnPressImage = Tkinter.PhotoImage(file=self._BtnPresspath) 
     self._image = Tkinter.PhotoImage(file=self._imagePath) 
     self.bgimage = self.create_image(35, 35, image=self._image) 
     self.text = buttonname 
     if self._icon: 
      self._icondata = base64.b64decode(self._icon) 
      self._iconimage = ImageTk.PhotoImage(data=self._icondata) 
      self.create_image(35, 35, image=self._iconimage) 
     if self.text and self._icon: 
      self.create_text(35, 63, anchor="s", 
          text=self.text, 
          font=("arial", 8, "bold"), 
          fill=_FONTCOLOR) 
     elif not self._icon: 
      self.create_text(35, 45, anchor="s", 
          text=self.text, 
          font=("arial", 8, "bold"), 
          fill=_FONTCOLOR) 
     self.configure(width=70, height=70) 
     self._activation() 

    def disable(self): 
     self.config(state=DISABLED) 
     self._activation() 

    def enable(self): 
     self.config(state=NORMAL) 
     self._activation() 

    def _activation(self): 
     if self.cget("state") == "disabled": 
      self.create_rectangle(-1,-1,70,70, stipple="gray50", fill="white") 
      self.unbind("<ButtonPress-1>") 
      self.unbind("<ButtonRelease-1>") 
     else: 
      self.bind("<ButtonPress-1>", self._on_press) 
      self.bind("<ButtonRelease-1>", self._on_release) 

    def _on_press(self, event): 
     self.itemconfig(self.bgimage, image=self._BtnPressImage) 
     print "pressed" 

    def _on_release(self, event): 
     self.itemconfig(self.bgimage, image=self._image) 
     if self.command is not None: 
      self.command() 

tk = Tk() 
but = DesktopBtn(tk, "test") 
but.config(state="disabled") 
but.pack() 
butt_blank = CustomButton(tk) 
butt_text = CustomButton(tk, buttonname="test", state=DISABLED) 
butt_icon = CustomButton(tk, icon=_ICONDATA) 
butt_icon_text = CustomButton(tk, icon=_ICONDATA, buttonname="test") 
butt_blank.pack() 
butt_text.pack() 
butt_icon.pack() 
butt_icon_text.disable() 
butt_icon_text.pack() 
tk.mainloop() 

в результате почти то же самое, но вы должны реализовать два метода для отключения и включения этого «виджета». Вот почему я все еще жду решения для своего Вопроса.

1

, как указано в комментариях один обходной путь был бы сделать составное изображение.
простого пример этого:

#!python3 

import tkinter as tk 
from PIL import Image, ImageTk 

root = tk.Tk() 
bgim = Image.open("bg.gif") 
bgphoto = ImageTk.PhotoImage(bgim) 

button1 = tk.Button(root, image=bgphoto) 
button1.pack() 

newim = Image.open("bg.gif").convert('RGBA') # ensure both images are in a mode that supports transparency 
iconim = Image.open("Icon.png").convert('RGBA') 
newim.paste(iconim, (-30,-40), iconim) # paste second image into first image 
newphoto = ImageTk.PhotoImage(newim) 
button2 = tk.Button(root, image=newphoto) 
button2.pack() 

root.mainloop() 

bg.gif является одним из изображений из оригинального поста, другая простой PNG иконка с прозрачностью.

для получения дополнительной информации о слиянии изображений см это post

+0

Пожалуйста, объясните, как сделать изображение композитом с альфой влияет на поведение кнопки. – martineau

+0

это не позволяет ему подклассифицировать кнопку (как он уже делает), чтобы разрешить использование фонового изображения и значка вместе, прозрачность казалась логичной вещью для включения, а также для аккуратности полученного изображения, которое работа лучший. –

Смежные вопросы