问题描述
我想在粘贴发生到TEdit控件之前(同时使用Ctrl + V和上下文菜单“粘贴”)检查剪贴板字符串。如果剪贴板中包含特定字符串,则TEdit控件不应粘贴该字符串。剪贴板文本应保持原样,不应清除。
解决方法
对于CTRL-V
,您可以创建一个OnKeyPress
事件处理程序,以在粘贴之前验证剪贴板中的文本。
我将检查一个有效字符表中的单个字符与检查无效字符串中的完整粘贴进行了组合。
注意:仍然可以手动输入无效字符串,因为这只是检查粘贴文本中的无效字符串。如果您需要检查以确保用户一次不会输入一个字符的错误字符串,请在valid_string()
事件处理程序中调用OnChange
。
#include <Clipbrd.hpp>
#include <algorithm>
#include <vector>
// A function to validate a pasted string against a number of blacklisted strings
bool valid_string(const UnicodeString& InStr) {
static const std::vector<UnicodeString> BadStrings{" ","--"};
return std::find_if(BadStrings.begin(),BadStrings.end(),[&](const auto& badstr) {
// return true if the current badstr was found
return
std::search(InStr.begin(),InStr.end(),badstr.begin(),badstr.end()) != InStr.end();
}) == BadStrings.end(); // true if a bad string was NOT found
}
// OnKeyPress event handler
void __fastcall TForm1::Edit1KeyPress(TObject *Sender,System::WideChar &Key)
{
TEdit& se = *static_cast<TEdit*>(Sender);
using StrType = decltype(se.Text);
// A lambda to validate a single character:
static const auto validkey = [](auto Ch) {
// example of valid characters:
static const StrType Accepted = "0123456789 -()";
return std::find(Accepted.begin(),Accepted.end(),Ch) != Accepted.end();
};
if(Key >= ' ') { // don't validate control characters
// Single key validation
if(not validkey(Key)) Key = 0;
} else if(Key == 22) { // CTRL-V - check that the whole clipboard buffer is ok
auto& c = *Clipboard();
if(c.HasFormat(CF_UNICODETEXT)) {
// Extract the pasted string
StrType paste = StrType(c.AsText.c_str());
// Use the lambda on all characters
bool all_chars_ok = std::all_of(paste.begin(),paste.end(),validkey);
if(not (all_chars_ok && valid_string(paste))) { // reject the whole paste
Key = 0;
}
}
}
}
这是在OnChange
处理程序中执行所有操作的示例。这样应该可以从上下文菜单中捕获不良粘贴,以及用户键入任何非法组合(即使它包含有效字符)也是如此。
#include <utility>
void __fastcall TForm1::Edit1Change(TObject *Sender)
{
TEdit& se = *static_cast<TEdit*>(Sender);
using StrType = decltype(se.Text);
static StrType old_text;
// A lambda to validate a single character:
static const auto validkey = [](auto Ch) {
// example of valid characters:
static const StrType Accepted = "0123456789 -()";
return std::find(Accepted.begin(),Ch) != Accepted.end();
};
// Making an unnecessary copy of the text.
// Using se.Text's iterators directly fails for some reason.
auto txt = se.Text;
// Use the lambda on all characters
bool all_chars_ok = std::all_of(txt.begin(),txt.end(),validkey);
if(all_chars_ok && valid_string(txt)) {
// All is ok,save this text
old_text = std::move(txt);
} else {
// Revert back to the old text
se.Text = old_text;
se.SelStart = old_text.Length();
// se.Undo(); // May be a better idea to use instead.
}
}