【问题标题】:Is there a way to create a bubble pop up that can be used to input text into different text inputs?有没有办法创建一个气泡弹出窗口,可用于将文本输入到不同的文本输入中?
【发布时间】:2019-11-06 12:08:50
【问题描述】:

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

我的计划是为气泡 (inputBubble)、气泡按钮 (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' object has no attribute 'bubblein'”。

【问题讨论】:

    标签: python python-3.x kivy


    【解决方案1】:

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

    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()
    

    【讨论】:

    • 谢谢!如果我想使用与 nangleInput 不同的文本输入以及具有 nangleInput(所以 App.get_running_app().root.RHS.nangleInput.text 会读取 App.get_running_app().root.RHS.ndistInput.text)我可以做这是根据我选择的文本输入动态地进行的,还是我必须为每个人创建一个气泡类?再次感谢!
    • 很抱歉问另一个问题,有没有办法绘制它,以便它可以浮动在文本输入上方,并且当我按下我添加的“完成”按钮时气泡关闭给它?如果这应该是一个单独的问题,请告诉我
    • 是的,这应该是一个单独的问题。
    • 没关系,我已经解决了,再次感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多