如何通过'on_<属性>'回调将文本插入TextInput

0 投票
1 回答
1339 浏览
提问于 2025-04-18 05:55

我正在用kivy做一个简单的计算器,想用TextInput来显示屏幕上的内容。我不太确定用TextInput还是Label更好,不过我觉得TextInput可能更合适(也许我错了?)。现在界面基本搭建好了,所有的按钮和它们对应的文本框('0', '1', '2', '+', '='等等)都已经准备好了。每次用户按下一个按钮,那个按钮上的文本就会被添加到calc_string中,当按下'='按钮时,这个字符串会被计算。基本上,功能都正常,但我的输出全都打印在控制台上,因为我无法把字符串插入到TextInput的显示区域。我尝试在一个回调函数(screen_callback)中设置TextInput的文本,这个回调是通过一个绑定到TextInputon_property方法触发的,但没有成功。我该怎么做才能实现这个功能?这是可能的吗?

main.py:

#!/usr/bin/env python

import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.properties import ListProperty, ObjectProperty, StringProperty, NumericProperty

class Screen(TextInput):
    pass

class Calculator(BoxLayout):

    function_btns = ListProperty(['+', '-', '*', '/', '^', 'Mem <-', 'Mem ->', 'Clear'])
    digit_btns = ListProperty(['7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.', '+/-'])
    eval_string = StringProperty() # one of these strings is probably unnecessary
    calc_string = StringProperty()
    result = NumericProperty(0)

    def build_calc(self):
        # add screen textinput
        self.add_widget(Screen(text='0', multiline=False, on_calc_string=self.screen_callback))

        #create inner boxlayout to hold 2 button gridlayouts
        main_buttons_box = BoxLayout(orientation='horizontal', size_hint=(1, 0.75))

        # create 2 button gridlayouts
        digit_grid = GridLayout(cols=3, rows=4, size_hint=(0.5, 1))
        function_grid = GridLayout(cols=1, size_hint=(0.5, 1))

        # populate grids with buttons
        for i in self.digit_btns:
            digit_grid.add_widget(Button(text=str(i), on_press=self.button_callback))

        for f in self.function_btns:
            function_grid.add_widget(Button(text=str(f), on_press=self.button_callback))

        # add grids to inner boxlayout
        main_buttons_box.add_widget(digit_grid)
        main_buttons_box.add_widget(function_grid)

        # add inner boxlayout to main grid(root)
        self.add_widget(main_buttons_box)

        # finally, add boxlayout at bottom of main grid and insert equals btn
        equals_box = BoxLayout(size_hint=(1, 0.25))
        equals_box.add_widget(Button(text='=', on_press=self.button_callback))
        self.add_widget(equals_box)

    def button_callback(self, instance):
        value = instance.text
        if value == '=':
            try:
                self.result = eval(self.eval_string)
                self.calc_string = str(self.result)
                self.eval_string = ''
            except SyntaxError:
                self.calc_string = 'Error: Invalid Input'
        else:
            self.eval_string += value
            self.calc_string = self.eval_string

        print self.calc_string

    def screen_callback(self, instance):
        instance.text = self.calc_string # not working
        print 'seeing this!!!' # not working


class CalcApp(App):

    def build(self):
        calc = Calculator()
        calc.build_calc()
        return calc

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

kv文件:

#kivy: 1.0

<Screen>:
    size_hint: 1, 0.25

<Calculator>:
    orientation: 'vertical'

1 个回答

1

你的 Screen 组件没有 calc_string 这个属性,所以 on_calc_string 在这里没有任何作用:

self.add_widget(Screen(text='0', multiline=False, on_calc_string=self.screen_callback))

你需要把这个绑定到 Calculator 上。Kivy 提供了一个很方便的 setter 方法来帮助你实现这一点:

scr = Screen(text='0', multiline=False)
self.add_widget(scr)
self.bind(calc_string=scr.setter('text'))

而且,使用 kv 语言可以让这个过程变得简单得多。你可以在 kv 文件中定义整个组件的布局……我不会重构你整个组件,但这里有个例子:

<Calculator>:
    orientation: 'vertical'

    Screen:
        text: root.calc_string

root 指的是规则中的根组件,这里是 Calculator。每当 root.calc_string 被修改时,Screentext 属性会自动更新。

撰写回答