我有一个小型测试用例,它实际上显示了两个问题.

该应用程序的总体要点(感兴趣的部分)是构建一个控制台类型的显示,在文本输入小部件上方有一个ScrollView窗口.对于这个精简的测试用例,它应该 echo 输入的命令"t",然后将3行文本打印到ScrollView,并清除文本输入.还有其他按钮作为占位符,以使层次 struct 变得现实.

首先,我try 为FloatLayout层次 struct 中的一个小部件调用kivy函数,这真是太糟糕了.我try 过屏幕、应用程序、根、self 、什么都没有,但似乎找不到一种方法来到达层次 struct 的顶部,然后下降到感兴趣的小部件.当布尔图形用户界面界面为True时,就会显示此问题.test901.py中的第25行和第38行存在此问题. 通过在""标签右侧的文本输入块中输入"tenter"来触发它.

其次,如果我将bool GUI_MED设置为False,那么我没有传递任何显式参数的调用就会出现参数不匹配(参数太多).第75、101和127行显示此问题.此代码是从另一个应用程序中删除的,它运行良好..通过在""标签右侧的文本输入块中输入"tenter"来触发它,布尔GUI_MED设置为False.(如果不一致,我什么也不是……)

如果您有关于如何在按下输入后将注意力集中在文本输入小部件上的提示,我将更加感激!

谢谢!

这是Python文件(尽我所能做到的最低可重复性.)

# test901.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.properties import StringProperty, NumericProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock

__version__ = '0.1'

# Set GUI_MODE to True for scrollview output, to False for regular console output
GUI_MODE = True


def common_print(prompt):
    if GUI_MODE:
        print(prompt)  # For debug only
        # May need a "for row in prompt: print_gui_output(row)" here...
        ########################################################################################
        # HERE IS PROBLEM 1a, I can't figure out the addressing to get to this function....    #
        # game_screen, app, root, screen are all unrecognised                                  #
        # Error visible if GUI_MODE = True, and "t<enter>" is typed on the TextInput GUI >>>   #
        ########################################################################################
        game_screen.print_gui_output(prompt)

    else:
        print(prompt)


def common_input(prompt):
    if GUI_MODE:
        ########################################################################################
        # HERE IS PROBLEM 1b, I can't figure out the addressing to get to this function....    #
        # game_screen, app, root, screen are all unrecognised                                  #
        # Error visible if GUI_MODE = True, and "t <enter>" is typed on the TextInput GUI      #
        ########################################################################################
        my_input = game_screen.gui_input(prompt)
    else:
        my_input = input(prompt)
    return my_input


class ScrollWindow(BoxLayout):
    line_count = 0
    io_history = ObjectProperty(None)

    def gui_input(self, command):
        print("step1")
        # Add output to history
        self.line_count += 1
        if command[-1] == 13:  # got here via the enter key rather than the button
            command = command[0:-2]  # delete the "enter" keystroke
        row = HistoryOutput()
        row.line_num = str(self.line_count)
        # Here is the place we add text to the scrolling text window
        row.output_text = ' ' + command
        self.io_history.add_widget(row)
        # Here is where we prepare the input for parsing, and set the quik_param if provided
        cmd = command.lower().strip()
        cmd_list2 = cmd.split()
        quik_param = ""
        if len(cmd_list2) > 1:
            cmd = cmd_list2[0]
            quik_param = cmd_list2[1]
            # Here we interpret the command and execute it
        parse_cmd(cmd, quik_param)
        # Work-around for displayed row height issues
        print("step2")
        ########################################################################################
        # HERE IS PROBLEM 2a, I can't figure why this complains of parameter mismatch          #
        # I am not passing any explicit parameters to recalc_height, just the implicit self    #
        # Error visible if GUI_MODE = False, and "t <enter>" is typed on the TextInput GUI     #
        ########################################################################################
        Clock.schedule_once(self.recalc_height)
        print("step3")

        return command

    def print_gui_output(self, rows):
        print("Step4")
        # Add output to history
        for my_row in rows:
            self.line_count += 1
            if my_row[-1] == 13:  # got here via the enter key rather than the button
                my_row = my_row[0:-2]  # delete the "enter" keystroke
            row = HistoryOutput()
            row.line_num = str(self.line_count)
            # Here is the place we add text to the scrolling text window
            row.output_text = ' ' + my_row
            self.io_history.add_widget(row)

            # Work-around for displayed row height issues
            print("Step5")

            ########################################################################################
            # HERE IS PROBLEM 2b, I can't figure why this complains of parameter mismatch          #
            # I am not passing any explicit parameters to recalc_height, just the implicit self    #
            # Error visible if GUI_MODE = False, and "t <enter>" is typed on the TextInput GUI     #
            ########################################################################################
            Clock.schedule_once(self.recalc_height)
            print("Step6")

    def recalc_height(self):
        """ A method to add and remove a widget from the io_history to force
            the recalculation of its height. Without this, the scrollview will
            not work correctly.
        """
        work_around = Widget()
        self.io_history.add_widget(work_around)
        self.io_history.remove_widget(work_around)


class HistoryOutput(BoxLayout):
    def collapse_row(self, app, lbl):
        if lbl.shorten:
            lbl.shorten = False
        else:
            lbl.shorten = True

            print("Step7")
        ########################################################################################
        # HERE IS PROBLEM 2c, I can't figure why this complains of parameter mismatch          #
        # I am not passing any explicit parameters to recalc_height, just the implicit self    #
        # Error visible if GUI_MODE = False, and "t <enter>" is typed on the TextInput GUI     #
        ########################################################################################
        Clock.schedule_once(app.root.recalc_height)


class ScrollBox(Button):
    pass

    index = NumericProperty(0)
    text_name = StringProperty("")


class GameScreen(Widget):
    pass


class test901App(App):
    def build(self):
        return GameScreen()


Window.clearcolor = (1, 1, 1, 1)
Window.size = (1700, 936)


# from dateutil.parser import parse


def parse_cmd(cmd, quik_param):
    if cmd == "t":
        common_print("This is line 1\nThis is line 2\nThis is line 3")
    else:
        common_print("Unrecognized command, try again")


def get_string(prompt):
    # my_string = "" + common_input(prompt)
    my_string = common_input(prompt)
    if my_string == "q":
        # print("*** Quick Exit from get_string ***")
        raise KeyboardInterrupt
    return my_string


if __name__ == '__main__':
    game_screen = test901App().run()
    print("Stage2")


# Command line parser
while True:
    try:
        print("Stage_Get_Command")
        cmd2 = get_string(
            "\n\nEnter a command ")
        cmd2 = cmd2.lower().strip()
        cmd_list = cmd2.split()
        quik_param2 = ""
        if len(cmd_list) > 1:
            cmd2 = cmd_list[0]
            quik_param2 = cmd_list[1]
            # print("Long Command")
        parse_cmd(cmd2, quik_param2)
    except KeyboardInterrupt:
        continue

这是kivy文件test901.ð

#:kivy 2.3.0

<ScrollBox>:
    size_hint_y: None
    height: 16

    canvas:
    Button:
        size_hint_y: None
        height: 16
        halign: 'left'
        font_size: 13
        font_name: 'RobotoMono-Regular'
        text_size: self.width, self.height
        background_normal: str(False)
        #on_press: self.parent.parent.parent.parent.make_selection(self.parent.index)
        text:"Hi World"

<GameScreen>:
    id: game_screen
    canvas:
        Color:
            rgba: 0, 0, 1, 1  # Blue (For the border)
        Rectangle:
            pos: root.x, root.y
            size: root.width, root.height
        Color:
            rgba: 1, 1, 1, 1  # White
        Rectangle:
            pos: root.x + 5, root.y + 5
            size: root.width - 10, root.height - 10

    FloatLayout:
        pos: 0,0
        size: root.width, root.height
        id: float_layout

        # Floating array of Top Buttons, most of which are MultiSelectSpinners

        Button:
            text: 'Hi World'
            pos_hint: {'x': .006, 'y': .89 }
            size_hint: 0.045, .1
            font_size: 22
            bold: True
            background_normal: ''
            background_color: 0.2, 0.7, .2, 1 # Green
            halign: 'center'

        ScrollWindow:
            id: scroll_window
            pos_hint: {'x': .005, 'y': .15 }
            size_hint: 0.988, .7

        # Grid of bottom buttons
        GridLayout:
            cols: 2
            pos_hint: {'x': .05, 'y': .01}
            size_hint: None, None
            size: root.width * .9, root.height * .1
            color: 1, 1, 0, 1
                # rgba: 0, 1, 0, 1 # Black text

            Button:
                text: 'Selection'

            Button:
                text: 'Add'


#:set padding_base 2
#:set sm_button_width 36

<HistoryOutput@BoxLayout>
    height: output_label.height
    orientation: 'horizontal'
    size_hint: 1, None
    line_num: "0"
    output_text: "???"
    ToggleButton:
        height: self.texture_size[1] + sp(padding_base)
        id: output_label
        size_hint: 1, None
        font_name: 'RobotoMono-Regular'
        font_size: 14
        text: root.output_text
        text_size: self.size[0], None
        background_color: {'normal': (0,0,0,1), 'down': (1,1,0,1)} [self.state]  # Black / Green
        background_normal: "1"

<ScrollWindow>:
    io_history: io_history
    orientation: 'vertical'
    padding: sp(padding_base), sp(padding_base)
    # Scrolling text window
    ScrollView:
        BoxLayout:
            height: sum([c.height for c in self.children]) + (2 * sp(padding_base))
            id: io_history
            orientation: 'vertical'
            size_hint: 1, None

    # Console Input Line
    BoxLayout:
        height: sp(32)
        orientation: 'horizontal'
        size_hint: 1, None
        Label:
            id: prompt_label
            size_hint: None, 1
            color: 0, 0, 0, 1  # Black
            text: ">>>"
            width: sp(sm_button_width)
        TextInput:
            id: main_input
            multiline: False
            on_text_validate: root.gui_input(main_input.text); main_input.text=""

        Button:
            on_press: root.gui_input(main_input.text)
            size_hint: None, 1
            text: "Enter"
            width: self.texture_size[0] + (8 * sp(padding_base))

将bool GUI_MED设置为True,并将命令"t enter"输入到文本输入小部件中,我会得到以下错误跟踪:

C:\Users\rick\AppData\Local\Programs\Python\Python310\python.exe C:/Users/rick/PycharmProjects/cruise2cruise/test901.py
[INFO   ] [Logger      ] Record log in C:\Users\rick\.kivy\logs\kivy_24-05-02_34.txt
[INFO   ] [deps        ] Successfully imported "kivy_deps.angle" 0.4.0
[INFO   ] [deps        ] Successfully imported "kivy_deps.glew" 0.3.1
[INFO   ] [deps        ] Successfully imported "kivy_deps.sdl2" 0.7.0
[INFO   ] [Kivy        ] v2.3.0
[INFO   ] [Kivy        ] Installed at "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\__init__.py"
[INFO   ] [Python      ] v3.10.5 (tags/v3.10.5:f377153, Jun  6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)]
[INFO   ] [Python      ] Interpreter at "C:\Users\rick\AppData\Local\Programs\Python\Python310\python.exe"
[INFO   ] [Logger      ] Purge log fired. Processing...
[INFO   ] [Logger      ] Skipped file C:\Users\rick\.kivy\logs\kivy_24-04-27_47.txt, PermissionError(13, 'The process cannot access the file because it is being used by another process')
[INFO   ] [Logger      ] Purge finished!
[INFO   ] [Factory     ] 195 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2 (img_pil, img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2
[INFO   ] [Window      ] Provider: sdl2
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] GLEW initialization succeeded
[INFO   ] [GL          ] Backend used <glew>
[INFO   ] [GL          ] OpenGL version <b'4.6.0 Compatibility Profile Context 22.20.27.09.230330'>
[INFO   ] [GL          ] OpenGL vendor <b'ATI Technologies Inc.'>
[INFO   ] [GL          ] OpenGL renderer <b'AMD Radeon RX 5700 XT'>
[INFO   ] [GL          ] OpenGL parsed version: 4, 6
[INFO   ] [GL          ] Shading version <b'4.60'>
[INFO   ] [GL          ] Texture max size <16384>
[INFO   ] [GL          ] Texture max units <32>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[WARNING] [Factory     ] Ignored class "HistoryOutput" re-declaration. Current -  module: None, cls: <class '__main__.HistoryOutput'>, baseclass: None, filename: None. Ignored -  module: None, cls: None, baseclass: BoxLayout, filename: C:\Users\rick\PycharmProjects\cruise2cruise\test901.kv.
[INFO   ] [Base        ] Start application main loop
[INFO   ] [GL          ] NPOT texture support is available
[INFO   ] [Base        ] Leaving application in progress...
 Traceback (most recent call last):
   File "C:\Users\rick\PycharmProjects\cruise2cruise\test901.py", line 170, in <module>
     game_screen = test901App().run()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\app.py", line 956, in run
     runTouchApp()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\base.py", line 574, in runTouchApp
     EventLoop.mainloop()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\base.py", line 341, in mainloop
     self.window.mainloop()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\core\window\window_sdl2.py", line 776, in mainloop
     if self.dispatch('on_key_down', key,
   File "kivy\\_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch
   File "kivy\\_event.pyx", line 1307, in kivy._event.EventObservers.dispatch
   File "kivy\\_event.pyx", line 1231, in kivy._event.EventObservers._dispatch
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\core\window\__init__.py", line 163, in _on_window_key_down
     return self.dispatch('on_key_down', keycode, text, modifiers)
   File "kivy\\_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch
   File "kivy\\_event.pyx", line 1307, in kivy._event.EventObservers.dispatch
   File "kivy\\_event.pyx", line 1231, in kivy._event.EventObservers._dispatch
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\uix\textinput.py", line 2984, in keyboard_on_key_down
     self._key_down(key)
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\uix\textinput.py", line 2890, in _key_down
     self.dispatch('on_text_validate')
   File "kivy\\_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch
   File "kivy\\_event.pyx", line 1307, in kivy._event.EventObservers.dispatch
   File "kivy\\_event.pyx", line 1191, in kivy._event.EventObservers._dispatch
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\lang\builder.py", line 60, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "C:\Users\rick\PycharmProjects\cruise2cruise\test901.kv", line 117, in <module>
     on_text_validate: root.gui_input(main_input.text); main_input.text=""
   File "C:\Users\rick\PycharmProjects\cruise2cruise\test901.py", line 67, in gui_input
     parse_cmd(cmd, quik_param)
   File "C:\Users\rick\PycharmProjects\cruise2cruise\test901.py", line 155, in parse_cmd
     common_print("This is line 1\nThis is line 2\nThis is line 3")
   File "C:\Users\rick\PycharmProjects\cruise2cruise\test901.py", line 25, in common_print
     game_screen.print_gui_output(prompt)
 NameError: name 'game_screen' is not defined. Did you mean: 'GameScreen'?
step1
This is line 1
This is line 2
This is line 3

Process finished with exit code 1

将布尔GUI_MED设置为False,并将命令"t enter"输入到文本输入小部件中,我会得到以下错误跟踪:

C:\Users\rick\AppData\Local\Programs\Python\Python310\python.exe C:/Users/rick/PycharmProjects/cruise2cruise/test901.py
[INFO   ] [Logger      ] Record log in C:\Users\rick\.kivy\logs\kivy_24-05-02_35.txt
[INFO   ] [deps        ] Successfully imported "kivy_deps.angle" 0.4.0
[INFO   ] [deps        ] Successfully imported "kivy_deps.glew" 0.3.1
[INFO   ] [deps        ] Successfully imported "kivy_deps.sdl2" 0.7.0
[INFO   ] [Kivy        ] v2.3.0
[INFO   ] [Kivy        ] Installed at "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\__init__.py"
[INFO   ] [Python      ] v3.10.5 (tags/v3.10.5:f377153, Jun  6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)]
[INFO   ] [Python      ] Interpreter at "C:\Users\rick\AppData\Local\Programs\Python\Python310\python.exe"
[INFO   ] [Logger      ] Purge log fired. Processing...
[INFO   ] [Logger      ] Skipped file C:\Users\rick\.kivy\logs\kivy_24-04-27_47.txt, PermissionError(13, 'The process cannot access the file because it is being used by another process')
[INFO   ] [Logger      ] Purge finished!
[INFO   ] [Factory     ] 195 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2 (img_pil, img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2
[INFO   ] [Window      ] Provider: sdl2
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] GLEW initialization succeeded
[INFO   ] [GL          ] Backend used <glew>
[INFO   ] [GL          ] OpenGL version <b'4.6.0 Compatibility Profile Context 22.20.27.09.230330'>
[INFO   ] [GL          ] OpenGL vendor <b'ATI Technologies Inc.'>
[INFO   ] [GL          ] OpenGL renderer <b'AMD Radeon RX 5700 XT'>
[INFO   ] [GL          ] OpenGL parsed version: 4, 6
[INFO   ] [GL          ] Shading version <b'4.60'>
[INFO   ] [GL          ] Texture max size <16384>
[INFO   ] [GL          ] Texture max units <32>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[WARNING] [Factory     ] Ignored class "HistoryOutput" re-declaration. Current -  module: None, cls: <class '__main__.HistoryOutput'>, baseclass: None, filename: None. Ignored -  module: None, cls: None, baseclass: BoxLayout, filename: C:\Users\rick\PycharmProjects\cruise2cruise\test901.kv.
[INFO   ] [Base        ] Start application main loop
[INFO   ] [GL          ] NPOT texture support is available
step1
This is line 1
This is line 2
This is line 3
step2
step3
[INFO   ] [Base        ] Leaving application in progress...
 Traceback (most recent call last):
   File "C:\Users\rick\PycharmProjects\cruise2cruise\test901.py", line 170, in <module>
     game_screen = test901App().run()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\app.py", line 956, in run
     runTouchApp()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\base.py", line 574, in runTouchApp
     EventLoop.mainloop()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\base.py", line 339, in mainloop
     self.idle()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\base.py", line 379, in idle
     Clock.tick()
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\clock.py", line 733, in tick
     self.post_idle(ts, self.idle())
   File "C:\Users\rick\AppData\Local\Programs\Python\Python310\lib\site-packages\kivy\clock.py", line 776, in post_idle
     self._process_events()
   File "kivy\\_clock.pyx", line 620, in kivy._clock.CyClockBase._process_events
   File "kivy\\_clock.pyx", line 653, in kivy._clock.CyClockBase._process_events
   File "kivy\\_clock.pyx", line 649, in kivy._clock.CyClockBase._process_events
   File "kivy\\_clock.pyx", line 218, in kivy._clock.ClockEvent.tick
 TypeError: ScrollWindow.recalc_height() takes 1 positional argument but 2 were given

Process finished with exit code 1

详情请参阅上文

推荐答案

您可以通过替换来访问print_gui_output()方法:

game_screen.print_gui_output(prompt)

与:

App.get_running_app().root.ids.scroll_window.print_gui_output(prompt)

App.get_running_app()获取当前运行的App,然后root获取App的根小部件(这是由您的build()方法返回的GameScreen实例),然后ids.scroll_window获取包含print_gui_output()方法的ScrollWindow的实例.

请注意,kv中指定的ids仅添加到它们出现的规则的根中.因此game_screen id只会出现在GameScreen实例中.事实上,由于id只会引用自己,因此id不包括在GameScreen ids中.

有关recalc_height()方法的错误是由于Clock.schedule_once()在调用recalc_height()时添加了dt参数引起的.您只需将*args添加到recalc_height()的签名中即可处理此问题:

def recalc_height(self, *args):

Python相关问答推荐

将两个收件箱相连导致索引的列标题消失

如何推迟对没有公钥的视图/表的反射?

pandas MultiIndex是SQL复合索引的对应物吗?

在for循环中保存和删除收件箱

在Python中添加期货之间的延迟

合并其中一个具有重叠范围的两个框架的最佳方法是什么?

如何使用scikit-learn Python库中的Agglomerative集群算法以及集群中声明的对象数量?

从Python调用GMP C函数时的分段错误和内存泄漏

给定数据点,制定它们的关系

是什么导致对Python脚本的jQuery Ajax调用引发500错误?

Image Font生成带有条形码Code 128的条形码时出现枕头错误OSErsor:无法打开资源

优化在numpy数组中非零值周围创建缓冲区的函数的性能

如何在图片中找到这个化学测试条?OpenCV精明边缘检测不会绘制边界框

对于一个给定的数字,找出一个整数的最小和最大可能的和

如何让程序打印新段落上的每一行?

大小为M的第N位_计数(或人口计数)的公式

log 1 p numpy的意外行为

ODE集成中如何终止solve_ivp的无限运行

driver. find_element无法通过class_name找到元素'""

剪切间隔以添加特定日期