TEdit — игнорировать операцию вставки, если буфер обмена содержит определенную строку

#borland-c #rad-studio

#borland-c #rad-студия #rad-studio

Вопрос:

Я хочу проверить строку буфера обмена перед вставкой в элемент управления TEdit (используя как Ctrl V, так и контекстное меню «Вставить»). Если буфер обмена содержит в себе определенную строку, то TEdit control не должен вставлять эту строку. Текст в буфере обмена должен оставаться как есть, не должен очищаться.

Ответ №1:

Для 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 UnicodeStringamp; InStr) {
    static const std::vector<UnicodeString> BadStrings{"  ", "--"};

    return std::find_if(BadStrings.begin(), BadStrings.end(), [amp;](const autoamp; 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 amp;Key)
{
    TEditamp; 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
        autoamp; 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 amp;amp; valid_string(paste))) { // reject the whole paste
                Key = 0;
            }
        }
    }
}
  

Вот пример выполнения всего этого в OnChange обработчике вместо этого. Это должно выявить неправильные вставки из контекстного меню, а также если пользователь вводит какие-либо недопустимые комбинации (даже если они состоят из допустимых символов).

 #include <utility>

void __fastcall TForm1::Edit1Change(TObject *Sender)
{
    TEditamp; 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(), Accepted.end(), 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 amp;amp; 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.
    }
}
  

Комментарии:

1. Вы должны проверить CF_UNICODETEXT вместо или, по крайней мере, в дополнение к CF_TEXT . В C Builder 2009 TEdit::Text и TClipboard::AsText будет UnicodeString , и TClipboard::AsText будет использоваться CF_UNICODETEXT внутри.