“记住”过去条目的方法

Posted

技术标签:

【中文标题】“记住”过去条目的方法【英文标题】:Method to "remember" past entries 【发布时间】:2015-09-16 05:39:12 【问题描述】:

我在 VB 中构建的应用程序的一部分具有终端功能,我想向它添加功能,以便它按时间顺序记住过去的命令,类似于 windows 终端的工作方式。

简而言之,我希望您能够在文本区域获得焦点时按向上箭头,并能够循环浏览之前输入的命令列表。

我对如何做到这一点有两个想法:

    一个组合框,当您按下 Enter 键时,它会读取 combobox.text 中的任何内容,无论是新输入的命令还是选择的旧命令。然后将该命令添加到组合框的项目中,以便您可以向上滚动并再次找到它。

    只是一个文本框,当按下向上箭头时,它会循环浏览一些存储的队列并相应地设置文本。这将需要第二个队列来记住循环执行的命令并替换它们,对吗?

是否有任何 Visual Basic 的内置结构会对此更好,或者有更好的方法吗?

感谢您的帮助。

【问题讨论】:

【参考方案1】:

听起来您正在寻找最近使用列表之类的东西。

您对ComboBox 的想法通常可能是正确的做法。使用TextBox 执行您的建议将在很大程度上导致...ComboBox

注意事项:

是否区分大小写? FooBar 是否匹配 fooBar? 堆栈(或队列)不是解决此问题的正确工具,因为如果他们使用列表中索引 4 中的某些内容,则无法轻松将该项目从 #4 移动到 #1。 要将其与 ComboBox 一起用作 UI 选择器,您需要使用可用作绑定源的东西。

这是一个新生的 MRU 类:

Public Class MRUList

    Private myList As BindingList(Of String)

    Public ReadOnly Property DataList As BindingList(Of String)
        Get
            Return myList '.Select(Function(f) f.Value).ToList
        End Get
    End Property

    Private myCapacity As Integer

    Public Sub New(capacity As Integer)
        myCapacity = capacity
        myList = New BindingList(Of String)
    End Sub

    Public Overloads Sub Add(item As String)

        Dim ndx As Integer = IndexOfKey(item)

        If ndx >= 0 Then
            myList.RemoveAt(ndx)
        End If

        myList.Insert(0, item)

        If myList.Count > myCapacity Then
            myList.RemoveAt(myList.Count - 1)
        End If
    End Sub

    ' case insensitive search
    Private Function IndexOfKey(s As String) As Integer

        Return myList.ToList.FindIndex(Function(f) f.Equals(s,
                   StringComparison.InvariantCultureIgnoreCase))

    End Function

End Class
当他们选择现有项目时,它会从原来的位置移到列表顶部。 不区分大小写,“Able”匹配“ABLE”。但它是区分大小写的:如果/当他们再次键入一个项目时,它会使用新的大小写。因此,如果“Ziggy”在插槽 3 的列表中,如果他们正确输入“Ziggy”,则旧的将被删除并使用新的。 有一个容量限制器,因此您不会得到长得离谱的列表。当列表过长时,旧项目会被丢弃。 它是从BindingList(Of String) 构建的,因此您可以将其绑定到ListboxComboBox

列表管理在后台非常浪费。每次我们在myList(0) 插入一个新项目时,.NET 都必须移动和调整底层数组。理想的集合类型是LinkedList,但它不能用作绑定源,而且我不怀疑您将存储 1000 多个项目。

用法:

Private myMRU As New MRUList(8)
...
' bind to CBO in form_load:
cboMRU.DataSource = myMRU.DataList

随着事物被添加到列表中,它们将自动出现在列表中。当用户做出选择时

Private Sub cboMRU_Leave(sender As Object, e As EventArgs) Handles cboMRU.Leave
    If cboMRU.Text.Length = 0 Then Exit Sub

    Dim thisCmd As String = cboMRU.Text
    myMRU.Add(thisCmd)
    cboMRU.Text = ""

End Sub

我使用了Leave 事件,因为他们可以从列表中选择从列表中选择一个项目。只要检查新项目和现有项目,您的代码不需要做任何事情,Add 方法会为您完成。

在左侧,我输入了 4 个项目,Delta 是最后一个。接下来,我正确输入了Able。该类删除了旧的,并将新的作为具有新拼写的 MRU 浮动到顶部。

由于这些对您的代码有意义,因此无论它们是什么,请在事件中使用 thisCmd。对于更复杂的事情,也许他们键入的只是其他内容的键或令牌,请在 MRU 类中使用 BindingList(of TokenItem)

【讨论】:

回答您的考虑,不,它们不区分大小写,因此您的解决方案很合适,是的,我现在明白为什么堆栈和队列在这种情况下并不理想。谢谢你的新词! “新生”我今天将努力实现这一点,感谢您的帮助!我知道一定有一些类似于 BindingSource 的结构,但不知道它是什么。感谢您的帮助。 “BindingList”允许添加的数据显示在 CBO 中,无需任何额外步骤。该类需要一个Clear 方法,可能是一个Count 函数。 Contains 可能也不错。 再评论:你能解释一下Return myList.ToList.FindIndex(Function(f) f.Equals(s, StringComparison.InvariantCultureIgnoreCase))这行吗?我在 VB 方面没有很深的经验,也没有见过以这种方式使用 Function 关键字。我问的原因是,即使我没有提到它,我确实需要区分文本和符号。例如,texttext: 应该是可区分的。目前,组合框会将它们注册为单独的项目,但cmb.Text 将始终返回先输入的内容。还有其他比较方法吗? 没关系,我意识到我可以将cmb.Text 保存在一个变量中并使用它,而不是在操作BindingList 之后引用cmb.Text 本身。感谢所有的帮助!编辑:为了清楚起见,我正在做的是将命令添加到列表中,然后引用 cmb.Text。如果我以相反的顺序做同样的事情,它就会正常工作。 BindingList 没有 Index 方法,因此 ToList 转换为 List<T> 这样做,然后 Function 是不区分大小写的比较,以查看 ABLE 是否匹配 Able。答案包括使用未更改的版本 (thisCmd)【参考方案2】:

比队列更好的是数组。队列只允许顺序访问,并且在您将其出列后,您出列的对象会“丢失”。如果你想保存它并在以后的会话中使用,你可以使用一个文件,比如 cookie 或者我喜欢的文件,也因为为未来的扩展做准备,一个嵌入式数据库,比如 sqlite 或 firebird。第二个是一个令人难以置信的强大数据库,如果你想获得一个服务器,它可以让你拥有一个强大的服务器

【讨论】:

感谢您的回答。我不打算保存 .exe 运行之外的命令,因此没有必要将其保存到文件中。数组当然可以完成工作,但它是否足够高效?由于存储方式的性质(最近存储=最容易访问),我的思绪跳到堆栈(我应该早点说堆栈,而不是队列),就像我说的那样,我可以轻松地使用两个数据结构来保持弹出项目的跟踪。而且我总是担心拥有一个动态大小的数组。我不知道要存储多少命令。 数组是最有效的数据结构。堆栈和队列是针对情况的。当您确实需要顺序访问并且最好不要保存信息时。当您进行遍历时,对服务器的调用、函数调用堆栈、树的分支等。但是如果你必须记住所有的东西,你需要存储它们。数组是更好的解决方案。 你说得对,堆栈和队列的功能方式并不适合这种情况。我想我在结构不合适的情况下过于重视简单性。感谢您的意见。

以上是关于“记住”过去条目的方法的主要内容,如果未能解决你的问题,请参考以下文章

新的数据条目会覆盖列中所有过去的条目,我该如何更正?

Delphi Seattle 在 dcc 命令行中记住过去的目录

如何在 GQL 中查询过去 6 小时(日期时间)的所有条目?

蟒蛇。创建特征向量,其中条目是过去状态的序列

Graphite 只会显示过去 24 小时的数据

MySQL 选择过去 7 天