使用 KIvy 制作命令行

Making a command line with KIvy

我一直在尝试模拟一个命令行设计,它允许我:
- 输入命令
- 执行它
- 在我输入的命令文本window 下方输出它。
所以我需要的是:

command_one
命令一已处理,这是输出

我已经部分完成了这个,但是发生的是输出文本覆盖了输入而不是 'adding up'。我遇到的另一个问题是,每次我需要输入内容时,我都必须单击 TextInput window,而不是只能继续输入命令而无需用过我的鼠标。

是否有任何解决方法可以帮助我解决这个问题?

这是我的代码:(mainapp.py)(已更改)

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class MainWindow(BoxLayout):
    # We create a dictionary of all our possible methods to call, along with keys
    def __init__(self, **kwargs):
        super(MainWindow, self).__init__(**kwargs) #This makes sure the kivy super classes from which MainWindow descends get initialized correctly.

        self.command_dict =  {
            'one': self.command_one,
            'two': self.command_two,
            'three': self.command_three,
        }
    def process_command(self):
        # We grab the text from the user text input as a key
        command_key = self.ids.fetch_key_and_process_command.text
        old_text = command_key.strip()

        # We then use that key in the command's built in 'get_method' because it is a dict
        # then we store it into a variable for later use
        called_command = self.command_dict().get[old_text, 'default']
        try:
            # The variable is a method, so by adding we can call it by simple adding your typical () to the end of it.
            called_command()

        except TypeError:
            # However we use an exception clause to catch in case people enter a key that doesn't exist
            self.ids.fetch_key_and_process_command.text = 'Sorry, there is no command key: ' + command_key
    # These are the three commands we call from our command dict.
    def command_one(self):
        self.ids.fetch_key_and_process_command.text = "{}\n{}\n".format(old_text, "Command One has Been Processed")

    def command_two(self):
        self.ids.fetch_key_and_process_command.text = 'Command Two has Been Processed'

    def command_three(self):
        self.ids.fetch_key_and_process_command.text = 'Command Three has been Processed'



class MainApp(App):

    def build(self):
        return MainWindow()

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

(mainapp.kv)

<MainWindow>:
    Label:
        text: 'This is a label'
    TextInput:
        id: fetch_key_and_process_command
        multiline: True  
    Button:
        id: process_command_button
        text: "Process Command"
        on_release: root.process_command()

出现的错误是:

line 21, in process_command called_command = self.command_dict().get[command_key, 'default'] TypeError: 'dict' object is not callable

I have partially completed this but what happens is that the output text overwrites the input instead of 'adding up

你需要做这样的事情:

text_input = self.ids.fetch_key_and_process_command
old_text = text_input.text.strip()
new_text = "{}\n{}\n".format(old_text, "Command One has Been Processed")
text_input.text = new_text

请注意,当您需要多个点来检索某个对象时,例如 self.ids.fetch_key_and_process_command 不要一遍又一遍地这样做——效率很低。相反,检索对象一次并将对象分配给一个变量,然后从那时起使用该变量,还有一个额外的好处,那就是它更容易输入!

Another problem that I have encountered is that I have to click on the TextInput window every time I need to type something in instead of just being able to keep typing in the commands without ever using my mouse

试试这个:

  ... 
  ...
  text_input.text = new_text
  text_input.focus = True

I do realise that I have to remove the multiline:False property from the kv file, but then I will not be able to use the on_text command so I do not really know where to start.

创建一个用户在完成输入后可以单击的按钮——就像您在此处输入完问题后单击的 Post Your Question 按钮一样。然后按钮可以调用 process_command() 而不是 TextInput:

<MainWindow>:
    Label:
        text: 'This is a label'
    TextInput:
        id: fetch_key_and_process_command
        multiline: True  
    Button:
        id: process_command_button
        text: "Process Command"
        on_release: root.process_command()

回复评论:

这里有几件事需要考虑:

1) 将文本添加到 TextInput 的问题在于,当您检索第二个命令的文本时,您将得到 all TextInput 中的文本,其中将包含第一个命令的文本以及第一个命令的输出,对吗?因此,包含第一个命令以及第一个命令和第二个命令的输出的长字符串不会成为 command_dict 中的键,对吗?因此,您将不得不以某种方式处理所有这些文本并提取第二个命令。

你当然可以这样做,比如在换行符上拆分文本,但是使用一个 TextInput 用于输入而另一个 TextInput 或 Label 用于输出会更容易,然后你可以在每个命令后清除输入 TextInput。

2) 而不是每次需要访问它时都重新创建字典,就像您在这里所做的那样:

def command_dict(self):
    return {
        'one': self.command_one,
        'two': self.command_two,
        'three': self.command_three,
    }

只需创建一次字典并将其附加到自身:

def __init__(self, **kwargs):
    super(MainWindow, self).__init__(**kwargs) #This makes sure the kivy super classes from which MainWindow descends get initialized correctly.

    self.command_dict =  {
        'one': self.command_one,
        'two': self.command_two,
        'three': self.command_three,
    }

然后在 class 中的任何方法中,您可以使用 self.command_dict 检索字典,并编写如下内容:

 self.command_dict['one']

您还可以利用 __init__() 中的机会将焦点设置在 TextInput 上。

3) 您应该始终 strip() 用户输入的文本。例如,如果用户输入 'one',然后点击 return,然后意识到他们需要单击按钮,然后单击按钮。在这种情况下,文本将是 "one\n",它不会在您的字典中找到。

看这个例子:

class Dog:
    def __init__(self):
        self.command_dict = {
                'a': 1,
                'b': 2,
        }

    def bark(self):
        val = self.command_dict['a']
        print(val) #=> 1
        val = self.command_dict.get('c', "hello")
        print(val) #=> hello

        self.command_dict['c'] = 3
        val = self.command_dict.get('c', "goodbye")
        print(val)  #=> 3


    def run(self):
        print(self.command_dict['c'])  #=>3
        print(self.I_cant_spell_command_dict_correctly['a'])  #=> error



d = Dog()
d.bark()
d.run()

输出:

1
hello
3
3

Traceback (most recent call last):
  File "1.py", line 27, in <module>
    d.run()
  File "1.py", line 21, in run
    print(self.I_cant_spell_command_dict_correctly['a'])
AttributeError: 'Dog' object has no attribute 'I_cant_spell_command_dict_correctly'

如果我需要在一个方法中多次编写 self.command_dict,那么我会这样做:

cmd_dict = self.command_dict

之后我会使用 cmd_dict。

如你所知,kivy 适用于中级到高级 python 程序员。在像 gui 编程这样复杂的环境中试图弄清楚 python 的基础知识会非常令人沮丧。

回复评论:

我以为我们同意了:

Yes, you can't write some_dict() because a dictionary is not a function.

__init__() 中将字典附加到 self 后,如何通过其他方法检索字典?

答案:self.command_dict

因为 self 似乎让你感到困惑,当你需要检索字典时,只需在你的代码中这样做:

my_command_dict = self.command_dict

接下来,如何检索字典my_command_dict中的?你写了吗:

val = my_command_dict()

val = my_command_dict['some key']

??

并且如果您想在键不存在时取回默认值——而不是导致错误——因此您决定对字典使用 get() 方法,您是否编写:

my_command_dict.get['some key', 'default']

my_command_dict.get('some key', 'default')

??

仔细看看我的示例代码和您的代码:

you: called_command = self.command_dict().get[old_text, 'default']
 me:            val = self.command_dict.get('c', "hello")

你能看出你的语法和我的语法有什么不同吗?从等号开始,向右逐个字符比较每一行。