在Kivy Python中改变按钮的背景形状和样式,比如阴影效果等

9 投票
2 回答
15250 浏览
提问于 2025-04-18 01:06

我了解到在Qt中,我们可以通过以下几种方式来制作QpushButton:

  1. 添加阴影效果
  2. 通过将setFlat属性设置为True来让按钮看起来更平坦
  3. 当鼠标悬停在按钮上时,改变鼠标指针的样式,比如使用pushButton_18.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))

我也想在Kivy中让按钮的行为类似。这样做可以吗?我发现我们可以把按钮的背景图像换成圆角形状的图像,在Kivy中改变按钮的背景颜色

但这样做效果并不理想,因为按钮看起来还是很普通。没有阴影效果。即使我们在按钮的边角点击,系统也会把它当作按钮被点击了。

我查看了Kivy按钮和标签的文档,尝试改变按钮的外观和行为。有没有人能给我一些建议,让按钮看起来更好?我们可以尝试添加:

  1. 阴影效果
  2. 背景动画效果
  3. 圆角边缘等等
  4. 我们能不能把动画GIF图像作为背景来做动画(我试过,但它不再动了)

下面是我刚创建的代码,用来进一步探索Kivy中的按钮:

__author__ = 'pbatra'
#Good info about background
#https://stackoverflow.com/questions/20181250/changing-the-background-color-of-a-button-    in-kivy/20181407#20181407

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.image import Image
from kivy.graphics import Color


gui = '''
<MenuScreen>:
    canvas.before:
        BorderImage:
            # BorderImage behaves like the CSS BorderImage
            border: 10, 10, 10, 10
            texture: self.background_image.texture
            pos: self.pos
            size: self.size
    GridLayout:
        size_hint: .1, .1
        pos_hint: {'center_x': .5, 'center_y': .5}
        rows: 1
        Button:
            text: 'Play'
            font_size: 20
            font_name: 'DroidSans'
            bold: True
            italic: True
            height: 10
            background_color: (0.5, 0.7, 0.5, 0.9)
            #Read more about them from documentation
            background_normal: './images/orange.png'
            background_down: './images/green.png'
            border: 30,30,30,30
            color: (1, .3, .8, .5)

        on_press: self.text = 'Oh yeah'

'''


class MenuScreen(Screen):
    background_image = ObjectProperty(
                                Image(
                                    source='../Examples/examples/widgets/sequenced_images/data/images/button_white_animated.zip',
                                    anim_delay=.5))
    Builder.load_string(gui)
    pass

# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))


class MyJB(App):
    def build(self):
        return sm

if __name__ == '__main__':
    MyJB().run() 

2 个回答

1
from kivy.app import App from  
kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button


class lay(FloatLayout):
    def __init__(self, **kwargs):
       super(lay,self).__init__(**kwargs)
       self.btn = Button(background_normal='image_state_on.png',
       background_down='image_state_off', size_hint_x = .50, size_hint_y = .50)
       self.add_widget(self.btn)

class ImageButton_APP(App):
    def build(self):
           return lay()


ImageButton_APP().run()

我觉得这样更有效。我使用了两种不同的图片。

14

Kivy中的按钮是从一个叫做 ButtonBehavior 开始的,这个按钮行为和一个 Label 结合在一起,增加了一些属性,比如背景的正常状态和按下状态,用来处理画布上的纹理。

知道了这些,你可以简单地把ButtonBehavior和你选择的任何其他小部件结合起来。例如:

from kivy.base import runTouchApp
from kivy.lang import Builder

kv = '''
<ButImage@ButtonBehavior+AsyncImage>

FloatLayout:
    # we don't specify anything here so float layout takes the entire size of the window.
    ButImage:
        id: but
        # take 50% size of the FloatLayout
        size_hint: .5, .5
        # Make Button change it's opacity when pressed for visual indication
        opacity: 1 if self.state == 'normal' else .5
        source: 'http://www.victoriamorrow.com/sitebuildercontent/sitebuilderpictures/enter_button.gif'
        # Introduce Label incase you want text on top of the image
        Label:
            center: but.center
            # change text acc to but state
            text: "Normal" if but.state == 'normal' else 'down'
'''

if __name__ == '__main__':
    runTouchApp(Builder.load_string(kv))

在这里,我们只是把ButtonBehavior和一个 AsyncImage 结合在一起,这个AsyncImage会从网上下载图片作为背景。

你应该能看到像这样的效果screenshot asyncimage button

背景的动画效果

这就像把源文件换成动画GIF或者一个包含多张图片的.zip文件一样简单。

from kivy.base import runTouchApp
from kivy.lang import Builder


kv = '''
<ButImage@ButtonBehavior+AsyncImage>

FloatLayout:
    ButImage:
        id: but
        size_hint: .5, .5
        opacity: 1 if self.state == 'normal' else .5
        allow_stretch: True
        keep_ratio: False
        source: 'http://media1.policymic.com/site/article-items/2095/1_gif.gif'
        Label:
            center: but.center
            text: "Normal" if but.state == 'normal' else 'down'


'''

if __name__ == '__main__':
    runTouchApp(Builder.load_string(kv))

看看这个 序列图像示例。这个示例是在ButtonBehaviors出现之前做的,所以它甚至有一个使用旧方法的 AnimatedButton 类的例子,这种方法现在基本上不再需要了。

阴影效果:

实现阴影效果的方法有很多。

你可以给一个小部件或布局添加阴影,然后让按钮放在这个小部件或布局的上面,按钮的空间要比阴影小,这样就能响应阴影上的触摸。

或者,你可以创建一个自定义的CustomButtonBehavior类,继承自ButtonBehavior,重写 collidepoint 方法,只在自定义碰撞时返回True。这里有一个关于 自定义碰撞 的示例。你甚至可以把图片的 keep_data 属性设置为True,然后检查 像素 数据的透明度,以决定是否要返回True进行碰撞检测。

圆角等效果。

只需使用一张带有圆角的图片,Kivy支持使用BorderImage指令,这在功能上相当于CSS的border-image。Kivy自带的按钮默认就使用这个效果。尝试并实验一下 BorderImage 的边框属性。

撰写回答