使用 KIvy 制作命令行

Posted

技术标签:

【中文标题】使用 KIvy 制作命令行【英文标题】:Making a command line with KIvy 【发布时间】:2018-07-28 04:44:19 【问题描述】:

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

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

我已经部分完成了这项工作,但结果是输出文本覆盖了输入,而不是“加起来”。我遇到的另一个问题是,每次需要输入内容时,我都必须单击 TextInput 窗口,而不是在不使用鼠标的情况下继续输入命令。 p>

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

这是我的代码:(mainapp.py)(changed)

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

出现的错误说:

第 21 行,在 process_command 中 called_command = self.command_dict().get[command_key, 'default'] TypeError: 'dict' 对象不可调用

【问题讨论】:

【参考方案1】:

看这个例子:

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 的基础知识会非常令人沮丧。

对评论的回应:

我以为我们同意了:

是的,你不能写 some_dict() 因为字典不是函数。

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

回答:self.command_dict

因为 self 似乎让您感到困惑,所以当您需要检索 dict 时,只需在您的代码中执行此操作:

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

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

【讨论】:

在我的答案底部查看我的回复。【参考方案2】:

我已经部分完成了,但结果是输出 文本覆盖输入而不是“加起来”

你需要做这样的事情:

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 不要一遍又一遍地这样做——它效率低下。取而代之的是,检索一次对象并将对象分配给一个变量,然后从那时起使用该变量,还有一个额外的好处是更容易键入!

我遇到的另一个问题是我必须点击 每次我需要输入内容而不是 只是能够在不使用我的情况下继续输入命令 鼠标

试试这个:

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

我确实意识到我必须删除 multiline:False 属性 kv 文件,但是我将无法使用 on_text 命令,所以 我真的不知道从哪里开始。

创建一个用户在完成输入后可以单击的按钮——就像您在此处输入问题时单击的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,
    

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

 self.command_dict['one']

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

3) 您应该始终strip() 用户输入的文本。例如,如果用户输入“一个”,然后点击返回,然后意识到他们需要点击按钮,他们点击了按钮。在这种情况下,文本将为“one\n”,不会在您的字典中找到。

【讨论】:

text_input = self.ids.fetch_key_and_process_command old_text = text_input.text.strip() new_text = "\n\n".format(old_text, "Command One 已被处理") text_input .text = new_text 我将这段代码放在什么函数中以使属性“自我”工作? @Robert Demka,在您想要添加到 TextInput 中已有文本的任何函数中。 33 非常感谢家人 @RobertDemka,请参阅我答案底部的评论。 它出现错误“名称“kwargs”未定义”。有什么办法吗?

以上是关于使用 KIvy 制作命令行的主要内容,如果未能解决你的问题,请参考以下文章

命令行制作随机密码

如何为命令行程序制作 gui?

kivy学习三:打包成window可执行文件

30天自制操作系统——第十七天制作命令行窗口

Xcode 命令行工具和制作

尝试使用 ImageMagick 制作 9 张图像的 3 x 3 蒙太奇,但命令行命令出错