【问题标题】:TStringList always doing line breakTStringList 总是换行
【发布时间】:2023-03-13 11:03:01
【问题描述】:

我正在开发一个键盘挂钩并使用 SetWindowsHookEx,并将每个击键添加到 TStringList 中。为了操作 TStringList 中的击键,我总是使用“.Text”属性。例如,要添加键入的击键,我使用:

KeyStrokes.Text:= KeyStrokes.Text + AChr;

如果我检测到 [backspace],我会尝试使用以下方法删除 StringList 中的最后一个字符:

KeyStrokes.Text := Copy(KeyStrokes.Text, 1, length(KeyStrokes.Text) - 1);

当我使用相同的“.Text”属性在 TMemo 中添加时,所有这些都正常工作。但是自从我放入 TStringList 时,在保存的 Log.txt 文件中(使用 .SaveToFile 属性)我得到的日志是这样的:

H

E

L

L

而不是“你好”。我尝试了“.Append”、“.Add”属性,但总是一样。当然,删除最后一个字母的退格键不再起作用......如何正确输入击键?这甚至可以在 TStringList 中做到吗?

【问题讨论】:

  • 如果 String 不超过一个,为什么还要使用 StringList?
  • 我们说的是什么版本的 Delphi?
  • Delphi 2010...关于使用简单字符串变量的问题只是在下面的其他答案中评论...

标签: delphi


【解决方案1】:

TStringList 似乎不是适合这项工作的工具,至少如果您要使用 Text 属性则不是。正如您从文档中知道的那样,读取 Text 属性会将列表中的所有项目与换行符连接起来。在每个换行符处写入该属性拆分新值,并在列表中为每个项目创建一个单独的条目。

如果您尝试跟踪击键,您不希望数据结构通过插入和删除看起来像击键但不代表真实击键的内容来默默地修改数据。 (特别注意,读取Text 属性将在结果末尾追加一个换行符。这会影响您的退格逻辑。)

使用普通的旧字符串来跟踪字符串输入的当前状态。

【讨论】:

  • 使用简单字符串的问题是因为我在检测到 [backspace] 时删除最后一个字符的方式相同,在检测 [enter] 时我正在换行,我会输此功能带有一个简单的字符串变量。没有其他类可以像 TMemo 一样使用吗?易于操作/保存到文件,但只能在内存中......像TStringStream一样,可以工作吗?
  • TMemo 使用TStrings 后代将字符串数据存储在备忘录的窗口中。 TStringListTStrings 的后代,将字符串数据存储在内存中。您遇到的问题发生在 TStrings 本身,而不是它的后代中,因此无论您使用哪种类型的基于 TStrings 的对象,您都应该遇到同样的问题。
【解决方案2】:

TStringList 可以将换行符保存到文件的唯一方法是,当您调用 SaveToFile() 时,TStringList 中有多个字符串。原因是因为读取Text 属性会在末尾插入一个隐式换行符,在写回Text 之前不会剥离。所以每次击键都会作为列表中的一个新字符串结束。

就像其他人所说的那样,TStringList 首先是这个工作的错误工具。请改用简单的String

KeyStrokes: String;
...
KeyStrokes := KeyStrokes + AChr;
...
Delete(KeyStrokes, Length(KeyStrokes), 1);

【讨论】:

  • 我认为 TStringList 添加换行符不是因为有多个字符串,而是因为每个键按下钩子程序都会重新开始,一个键一个键,所以 TStringList 识别为一个新的“字符串”,即使只是同一个字符串中的另一个键......而使用简单字符串的问题是因为当我检测到 [backspace] 时删除最后一个字符的方式相同,检测 [enter] 时我正在换行,并且我会用一个简单的字符串变量来失去这个功能。没有办法使用 TStringStream 或任何东西来做到这一点?
  • 您已经在读/写一个字符串,只是TStringList 管理的字符串。切换到单个 String 变量不会导致您失去任何功能。
【解决方案3】:

使用普通的字符串似乎更实用。在评论中,您担心失去某些功能,说:“我在检测 [enter] 时正在换行”。您可以通过为行尾 (EOL) 标记附加 sLineBreak 一个常量来轻松地使用普通字符串支持这一点。在 Windows 上,这等于 #13#10(回车和换行)。您唯一需要注意的是,当您使用退格键删除 EOL 时,您需要删除正确数量的字符:Windows 为 2,Linux/MAC 为 1。 Length(sLineBreak) 会告诉你有多少。

您可能要考虑的另一个选项是TStringBuilder 类。它旨在建立零碎的字符串,因此可以满足您的目的。

最后,如果你真的想使用TStringList,你可以单独操作字符串(即不使用Text属性):

FInputData: TStrings;
FInputData := TStringList.Create;
FInputData.Add(''); { Important to always have at least 1 string }

{ When adding a character "Ch" }
FInputData[FInputData.Count-1] := FInputData[FInputData.Count-1] + Ch;

{ When detecting the Enter Key }
FInputData.Add('');

{ When detecting Backspace }
S := FInputData[FInputData.Count-1];
if (S <> '') then
begin
  { Delete last character on current line }
  Delete(S, Length(S), 1);
  FInputData[FInputData.Count-1] := S;
end
else if (S = '') and (FInputData.Count > 1) then
begin
  { Go back to previous line if current is empty, but don't delete if 
    there's nothing left. (Remember: always have at least 1 string) }
  FInputData.Delete(FInputData.Count-1);
end;

{ To write the current data }
Writeln(FInputData.Text);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    相关资源
    最近更新 更多