首页 > 解决方案 > 有没有办法创建一个气泡弹出窗口,可用于将文本输入到不同的文本输入中?

问题描述

我正在尝试创建一个标准数字键盘,当用户触摸屏幕上的文本输入时会弹出该键盘,以便用户无需使用鼠标和键盘即可输入数字值。我正在关注允许输入到一个文本框中的这个问题,但是当尝试使用它来将值输入到多个文本输入中时,我无法让程序正常运行。我仅限于使用 Python,而不是 Kivy 语言,所以我可以理解编码有点尴尬。

我的计划是为 Bubble (inputBubble)、Bubble Buttons (inputBubbleButtons) 和文本输入框 (text_inputs) 创建一个类,其中 text_inputs 小部件从 RHS()(我的主要布局之一)调用一个应该显示的函数泡泡。我似乎无法从 test.kv 文件中复制 app.root.text_input.text += self.text,所以我当前的错误是“text_inputs 对象没有属性'bubblein'”,我想不出的一种方式来超越这一点。

import kivy
from kivy.app import App
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.uix.bubble import Bubble, BubbleButton

class inputBubble(Bubble):
        def __init__(self, **kwargs):
                super(inputBubble, self).__init__(**kwargs)
                inputGrid = GridLayout(cols = 3)
                keypad_numbers = ['7', '8', '9', '4', '5', '6', '1', '2', '3', 'CLR', '0', '.']
                for x in keypad_numbers:
                        inputGrid.add_widget = inputBubbleButtons(text = x)
                self.add_widget(inputGrid)

class inputBubbleButtons(BubbleButton):
        def __init__(self, **kwargs):
                super(inputBubbleButtons, self).__init__(**kwargs)
                self.on_release = self.buttonfunctions

        def buttonfunctions(self):
                if self.text != 'CLR':
                        text_input.text += self.text
                else:
                        text_input.text = '0'

class text_inputs(TextInput):
        def __init__(self, **kwargs):
                super(text_inputs, self).__init__(**kwargs)
                self.id = 'text_input'
                self.cursor_blink = False
                self.multiline = False
                self.on_focus = RHS.show_input(self)

class RHS(BoxLayout):
        def __init__(self, **kwargs):
                super(RHS, self).__init__(**kwargs)
                nangleRow = BoxLayout(orientation = 'horizontal')
                self.add_widget(nangleRow)
                nangleRow.add_widget(Label(text = 'New Angle'))
                nangleInput = text_inputs()
                nangleRow.add_widget(nangleInput)

        def show_input(self, *l):
                if not hasattr(self, 'bubblein'):
                        bubblein = inputBubble()
                        self.bubblein.arrow_pos = "bottom_mid"
                        self.add_widget(bubblein)

class Root(GridLayout):
        def __init__(self, **kwargs):
                super(Root, self).__init__(**kwargs)
                self.cols = 1
                self.add_widget(RHS(),0)

class MainWindow(App):
        def build(self):
                return Root()

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

当焦点位于 nangleInput 上时,我希望这会创建一个气泡,但是我收到错误消息“AttributeError:'text_inputs' 对象没有属性'bubblein'”。

标签: pythonpython-3.xkivy

解决方案


这是您的代码的一个版本,我认为它可以满足您的需求:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.bubble import Bubble, BubbleButton

class inputBubble(Bubble):
        def __init__(self, **kwargs):
                super(inputBubble, self).__init__(**kwargs)
                inputGrid = GridLayout(cols = 3)
                keypad_numbers = ['7', '8', '9', '4', '5', '6', '1', '2', '3', 'CLR', '0', '.']
                for x in keypad_numbers:
                        inputGrid.add_widget(inputBubbleButtons(text = x))    # use add_widget to add each Button to the inputGrid
                self.add_widget(inputGrid)

class inputBubbleButtons(BubbleButton):
        def __init__(self, **kwargs):
                super(inputBubbleButtons, self).__init__(**kwargs)
                self.on_release = self.buttonfunctions

        def buttonfunctions(self):
                if self.text != 'CLR':
                        # complex path to the TextInput
                        App.get_running_app().root.RHS.nangleInput.text += self.text
                else:
                        App.get_running_app().root.RHS.nangleInput.text = '0'

class text_inputs(TextInput):
        def __init__(self, **kwargs):
                super(text_inputs, self).__init__(**kwargs)
                self.id = 'text_input'
                self.cursor_blink = False
                self.multiline = False

class RHS(BoxLayout):
        def __init__(self, **kwargs):
                super(RHS, self).__init__(**kwargs)
                nangleRow = BoxLayout(orientation = 'horizontal')
                self.add_widget(nangleRow)
                nangleRow.add_widget(Label(text = 'New Angle'))
                self.nangleInput = text_inputs()    # save a reference to text_inputs
                self.nangleInput.bind(focus=self.show_input)    # use bind to get method called when focus changes
                nangleRow.add_widget(self.nangleInput)

        def show_input(self, *l):
                if not hasattr(self, 'bubblein'):
                        self.bubblein = inputBubble()    # create attribute that is tested for in above line
                        self.bubblein.arrow_pos = "bottom_mid"
                        self.add_widget(self.bubblein)

class Root(GridLayout):
        def __init__(self, **kwargs):
                super(Root, self).__init__(**kwargs)
                self.cols = 1
                self.RHS = RHS()    # save  reference to RHS
                self.add_widget(self.RHS,0)

class MainWindow(App):
        def build(self):
                return Root()

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

问题包括:

  1. inputGrid.add_widget = inputBubbleButtons(text = x)应该是inputGrid.add_widget(inputBubbleButtons(text = x))
  2. 在您的buttonfunctions(), 您引用text_input,但尚未定义。我用一条相当复杂的路径替换了它text_inputs
  3. self.on_focus = RHS.show_input(self)运行该show_input()方法并将返回值(即None)分配给self.on_focus. 我已经删除了那条线并放入self.nangleInput.bind(focus=self.show_input)RHS课堂,我认为这实现了你的意图。
  4. 在您的show_inputs()方法中,您正在检查是否存在名为 的属性bubblein,但您的代码不会创建一个。if我已将该块中的第一行更改为self.bubblein = inputBubble()创建该属性的 。其他更改也用于访问新属性。
  5. Root课堂上,我保存了对创建RHS实例的引用以供其他地方使用。

如果您打算使用多个TextInput实例,您可以调整键盘的目标以将文本发送到不同的TextInputs. 这是执行此操作的代码的另一个版本:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.bubble import Bubble, BubbleButton

class inputBubble(Bubble):
        def __init__(self, text_input, **kwargs):
                super(inputBubble, self).__init__(**kwargs)
                self.inputGrid = GridLayout(cols = 3)    # save a reference to the grid of inputBubbleButtons
                keypad_numbers = ['7', '8', '9', '4', '5', '6', '1', '2', '3', 'CLR', '0', '.']
                for x in keypad_numbers:
                        self.inputGrid.add_widget(inputBubbleButtons(text_input, text = x))    # use add_widget to add each Button to the inputGrid
                self.add_widget(self.inputGrid)

        # this method changes the target TextInput of the keypad
        def set_text_input(self, text_input):
                for butt in self.inputGrid.children:
                        butt.text_input = text_input

class inputBubbleButtons(BubbleButton):
        def __init__(self, text_input, **kwargs):
                self.text_input = text_input    # the target TextInput
                super(inputBubbleButtons, self).__init__(**kwargs)
                self.on_release = self.buttonfunctions

        def buttonfunctions(self):
                if self.text != 'CLR':
                        self.text_input.text += self.text
                else:
                        self.text_input.text = '0'

class text_inputs(TextInput):
        def __init__(self, **kwargs):
                super(text_inputs, self).__init__(**kwargs)
                self.id = 'text_input'
                self.cursor_blink = False
                self.multiline = False

class RHS(BoxLayout):
        def __init__(self, **kwargs):
                super(RHS, self).__init__(**kwargs)
                self.orientation = 'vertical'
                self.bubblein = None
                for i in range(5):
                        nangleRow = BoxLayout(orientation = 'horizontal')
                        self.add_widget(nangleRow)
                        nangleRow.add_widget(Label(text = 'New Angle ' + str(i)))
                        self.nangleInput = text_inputs()    # save a reference to text_inputs
                        self.nangleInput.bind(focus=self.show_input)    # use bind to get method called when focus changes
                        nangleRow.add_widget(self.nangleInput)

        def show_input(self, text_input, has_focus):
                if has_focus:
                        if self.bubblein is not None:
                                # already have a keypad, just change the target TextInput to receive the key strokes
                                self.bubblein.set_text_input(text_input)
                        else:
                                self.bubblein = inputBubble(text_input)
                                self.bubblein.arrow_pos = "bottom_mid"
                                self.add_widget(self.bubblein)

class Root(GridLayout):
        def __init__(self, **kwargs):
                super(Root, self).__init__(**kwargs)
                self.cols = 1
                self.RHS = RHS()    # save  reference to RHS
                self.add_widget(self.RHS,0)

class MainWindow(App):
        def build(self):
                return Root()

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

推荐阅读