Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: 1 [2] 3  Все   Вниз
  Печать  
Автор Тема: Запрет ввода символов  (Прочитано 87987 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
zubr
Гость
« Ответ #30 : 10-12-2008 20:16 » 

Джон, OnKeyPress у борланда - это оболочка WM_CHAR
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #31 : 10-12-2008 20:21 » 

А понятно, тогда всё в порядке. Просто есть ещё WM_KEY - по той все кнопки получаешь.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #32 : 10-12-2008 21:14 » 

Джон, совершенно верно - именно по тому и нужно делать два обработчика. Как бонус - в OnKeyPress можно обработать VK_ESCAPE для выхода из диалога и 13 - для OK.

Курсорные стрелки в OnKeyPress не попадают - тут только "символы" (backspace тоже имеет определенный код символа, а стрелкам не дали), но они есть в OnKeyDown и OnKeyUp. Эти три обработчика являются аналогами WM_KEYDOWN, WM_CHAR и WM_KEYUP.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #33 : 11-12-2008 00:11 » 

Ром, ну дык эт решение выстраданное. Ага У мнея по такому принципу построенный едит с семью разными типами работает.

BackSpace - 08
Tab - 09
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #34 : 11-12-2008 04:31 » 

От предшественников мне достался код, где вводи что хочешь, а потом типа
Код: (C++)
try { n = StrToInt(str); } catch (...) { }
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
zubr
Гость
« Ответ #35 : 11-12-2008 07:04 » 

Ну тогда удобнее StrToIntDef использовать.
Все равно считаю, что OnKeyPress - здесь лишнее.
А фишку с позицией курсора можно и в фильтре OnChange реализовать:
Если обнаружился недопустимый символ, то удаляем его и переводим курсор в позицию последнего удаленного символа. Или другой вариант - переводим курсор в конец строки (кстати, так у меня и сделано). Если же символ не удаляется, то SetWindowText не делаем (для VS).
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #36 : 11-12-2008 09:06 » 

zubr, напиши такую реализацию - потестим, проверим. Пока - не верю (с)
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
zubr
Гость
« Ответ #37 : 11-12-2008 10:27 » 

Ok. Выкладываю тест. Код:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    procedure Edit1Change(Sender: TObject);
  private
    { Private declarations }
    procedure SetFloatValue(component:TEdit);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.SetFloatValue(component:TEdit);
var
  s:string;
  i, posCur:Integer;
  IsSep, IsChange: boolean;
begin
 s := component.Text;
 posCur := component.SelStart;
 i:=1;
 IsSep := False;
 IsChange := False;
 While i<=Length(s) do
 begin
  If (not (s[i] in ['0'..'9'])) and (s[i]<>',') and (s[i] <> '-') then
  begin
   Delete(s, i, 1);
   posCur := i-1;
   IsChange := True;
   continue;
  end;
  If (s[i] = '-') and (i <> 1) then
  begin
   Delete(s, i, 1);
   posCur := i-1;
   IsChange := True;
   continue;
  end
  else
  If (s[i] = '0') and (i = 1) then
  begin
   If (Length(s) > 2) and (s[i+1] <> ',') then
   begin
    Delete(s, i, 1);
    posCur := i-1;
    IsChange := True;
    continue;
   end;
  end
  else
  If s[i] = ',' then
  begin
   If IsSep then
   begin
    Delete(s, i, 1);
    posCur := i-1;
    IsChange := True;
    continue;
   end;
   IsSep := True;
  end;
  inc(i);
 end;
 If IsChange then
 begin
  component.Text := s;
  component.SelStart := posCur;
 end;
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
 SetFloatValue(Sender as TEdit);
end;

end.
Уже понимает минус и несколько запятых.

* Project1.rar (156.2 Кб - загружено 786 раз.)
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #38 : 11-12-2008 10:31 » 

Кстати да. Я вижу оптимизацию только в выносе фильтра в отдельную ф-ю. Но заморачиваться с позициями курсора...
А если например я просто удалил несколько символов? Как тогда определить позицию курсора по OnChange? Поэтому тоже бы хотелось посмотреть на решение.
Кстати "мой" вариант - экзешник из кода в теме прицеплен. Можно будет сравнить.

зы Упс, сорри опоздал.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #39 : 11-12-2008 10:39 » 

Ага.

1. Скопировать в буфер обмена: 23456sdf,2345s34

2. Вставить в контрол -> где каретка? Ага
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
zubr
Гость
« Ответ #40 : 11-12-2008 10:47 » 

Джон, но вариант с OnKeyPress от этого не спасет.
Записан
zubr
Гость
« Ответ #41 : 11-12-2008 10:49 » 

Да и потом, а где она (каретка) должна быть, при вставке из буфера обмена?
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #42 : 11-12-2008 10:55 » 

Таки знал, что будет Паскаль... Придется транслировать в понятный вид - не могу "читать" Паскаль.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
zubr
Гость
« Ответ #43 : 11-12-2008 10:59 » 

RXL, если у меня будет время, то переведу в C++, но под VS (билдера нет).
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #44 : 11-12-2008 11:06 » 

Да я сам странслирую - просто нужно время и терпение. BCB6 у меня.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #45 : 11-12-2008 11:09 » 

Джон, но вариант с OnKeyPress от этого не спасет.

При этом варианте напрочь отпадает необходимость заботиться о позиции курсора. В моём коде этого управления нет.
Так что помогает.

Да и потом, а где она (каретка) должна быть, при вставке из буфера обмена?

Попробуй без фильтра (или на любом другом контроле, редакторе текстов и тп) и ты увидишь, что каретка ВСЕГДА стот ПОСЛЕ вставленного блока.
Во всяком случае позиция каретки (длинна - 2) не лезет ни в какие ворота.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #46 : 11-12-2008 11:15 » 

Глянул, код. Классно вам с борлнадовскими контролами. Вы вон объект в качестве параметра получаете со всеми необходимыми полями. Win API так напрямую не прокатит. Всё надо будет ручками делать.
« Последнее редактирование: 11-12-2008 11:17 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
zubr
Гость
« Ответ #47 : 11-12-2008 17:41 » 

Джон, ну если не на чистом API, а к примеру на MFC делать с использованием CString - не намного больше надо ручками делать, имхо.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #48 : 11-12-2008 19:18 » 

Джон, при вставке все таки нужно знать SelStart и SelLength - если блок текста выделен, то вставка должна заменять его, а не весь текст.

Еще один метод для действительных чисел:

Код: (C++)
//---------------------------------------------------------------------------
bool __fastcall TfrmInstallationEdit::testRealString(AnsiString str)
{
    return (str.Length() ? !regexec(&re_real, str.c_str(), RE_MATCHES_MAX, re_matches, 0) : true);
}
//---------------------------------------------------------------------------
void __fastcall TfrmInstallationEdit::dfREALKeyPress(TObject *Sender, char &Key)
{
    TEdit *ed = dynamic_cast<TEdit*>(Sender);

    if (Key == VK_ESCAPE)
        pbCancel->Click();
    else if (Key == VK_BACK)
        return;
    else
    {
        AnsiString tmp;

        if (ed->SelLength)
        {
            int beg = ed->SelStart;
            int end = beg + ed->SelLength;

            tmp = ed->Text.SubString(0, beg) + Key + ed->Text.SubString(end, ed->Text.Length() - end);
        }
        else
            tmp = ed->Text + Key;

        if (testRealString(tmp))
            return;
    }

    Key = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmInstallationEdit::dfREALChange(TObject *Sender)
{
    TEdit *ed = dynamic_cast<TEdit*>(Sender);

    if (!testRealString(ed->Text))
        ed->Text = "";
}

Здесь для проверки использую регулярные выражения - так проще и удобнее контролировать формат и состав строки. Подготовка выражения к использованию простая:

Всякие подсобные переменные:
Код: (C++)
    regex_t re_real;
    regmatch_t re_matches[RE_MATCHES_MAX];

Компиляция:
Код: (C++)
    char *re_real_str = "^[0-9]{0,6}(?:\\.[0-9]{0,2})?$";

    if (regcomp(&re_real, re_real_str, 0))
    {
        ShowMessage("Error rised on regexp compile.");
        Close();
    }

RE_MATCHES_MAX - макрос.
« Последнее редактирование: 11-12-2008 19:24 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #49 : 11-12-2008 19:37 » 

zubr, ошибаешься и CString тут совершенно не при чём. Посмотри мою ф-ю, она не получает параметра. Те мне надо самому забирать текст из окошка, опрашивать позицию курсора, устанавливать её и тд. И это всё вызывая сторонние ф-ции.

Ром, ошибаешься. По OnChange ты получаешь ВЕСЬ текст контрола, уже изменённый. Куда именно была сделана вставка и как она была сделана ты уже никогда не узнаешь. Контрол только сообщил тебе, что дескать моё содержимое изменили, теперь делайте со мной что хотите. Логика фильтра сработает и в этом случае

например было 01290, потом между 2 и 9 вставили 345абвгд678 получилось 012345абвгд67890 после фильтра осталось 01234567890. Только вот куда теперь курсор ставить? Ага

По хорошему надо отлавливать операции ДО изменения контрола. Но это уже надо смотреть, об такой наворот оплатят?

зы ЭТо ессно про виндовский системны Eidt, я знаю что у борланда свой TEdit, может там всё иначе.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #50 : 11-12-2008 19:54 » 

Джон, да - ошибся - в нужно OnKeyPress, но не в onChange...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Стася
Постоялец

ru
Offline Offline

« Ответ #51 : 15-12-2008 15:02 » 

Большое вам всем спасибо. Но я сделала так.

procedure TForm11.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if not (key in ['0'..'9',',','-',#8]) then
key:=#3;
end;

А затем в событиях каждого TEdit поменяла цифру на 1.
Записан
DrGluck
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #52 : 16-12-2008 13:59 » 

Я так понимаю, что проблема была только в том, чтоб разрешить юзеру вводить числа, а все остальное не вводить? И все это для 13 контролов?

Предложение:

1. У всех контролов устанавливаем один обработчик OnKeyPress. Там пропускаем только символы '0'..'9'  ','  '-'.
2. Обрабатываем OnChange. Тоже для всех едитов.
3. Дальше with (Sender as TEdit) do begin... (это по поводу не писать код 13 раз, вообще странный вопрос был про это. учите матчасть чтоли)
4. А дальше есть волшебная функция Val. Она позволяет преобразовывать String в Integer, Real (или как они там у вас на дельфях называюца), а если строка не правильная, то нам об этом сообщат в коде ответа. Если попробовать преобразовать одну строку в разные типы, то можно узнать какого типа данные вводил юзер. И не надо самому писать жуткие фильтры.
Более того, можно запоминать для каждой строки предыдущее перед OnChange состояние, и если Val выдает ошибку для всех преобразований, то тогда возвращать Edit.Text в предыдущее состояние.
(Есть правда одно НО. В случае отката на предыдущее значение тоже вызывается OnChange со всеми вытекающими последствиями, т.е. опять будут проверки).

з.ы. Давно не лазил на дельфовый форум, а тут опять зашел посмотреть. Ничего не меняется. Дельфисты по прежнему спрашивают друг у друга как делать элементарные вещи. "Как удалить запись в DBGride", "Как запретить ввод символов в едит", ну и конечно "Как сделать круглую кнопку".

з.з.ы. А вот еще перл "Помогите, пожалуйста, решить задачу с закладками".

RTFM, мать вашу!
Записан

Good user - dead user
zubr
Гость
« Ответ #53 : 17-12-2008 05:04 » 

DrGluck,
1. Не надо повторять то что уже было сказано другими. Если ты обратишь внимание, то универсальный код для всех эдитов был указан в предыдущих постах.
2. Твой вариант не избавляет от возможности вставки из буфера обмена практически любого текста.
3. Твой вариант не избавляет от возможности ввода нескольких минусов, запятых, а также вставки их в любом месте текста, что есть криво. Все эти моменты решаются с помощью фильтра. И причем здесь функция Val? Она только преобразует текст в число аналогично StrToInt, StrToIntDef, StrToFloat, StrToFloatDef
Записан
DrGluck
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #54 : 17-12-2008 06:20 » 

1. Согласен. Не буду.
2. Из буфера вставить можно, но при этом срабатывает OnChange. И в нем мы можем проверить то, что вставилось. И, в случае неудачи, заменить на предыдущее значение (например).
3. Функция Val позволяет легко проверить строку, которая находится в Edit.Text (т.е. не нужно самому разбираться в строке). И, если проверка не проходит, то таки-да уже можно вернуть старое значение.
4. И вообще нафига было замарачиваца. Тока что проверил виндовый калькулятор. Если в него скопипастить строку символов, то он просто игнорирует это и подставляет значение 0. Что я и предложил в своем посте.
5. Реально проблема не стоила такого длинного обсуждения.
6. В связи с 5 извиняюсь что сюда отписался.
Записан

Good user - dead user
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #55 : 17-12-2008 11:32 » 

DrGluck, проблема обсуждалась длинно, потому что дельфийцев небыло, а С++, согласись, не одно и тоже что Паскаль. Это раз. Два - с самого начала не было понятно, что нужно было сделать фильтр. Хотя RuNTiME, судя по всему обладая незаурядными телепатическими способностями, дал практически правильный ответ на половину вопроса.

Ну и последнее, ИМХО ты перегибаешь палку в своём праведном гневе. Конечно, можно перелопатить кучу мануалов, учебников и примеров кода, чтобы прийти к нужному решению, но в данном случае неопытноый начинающий программист, девушка, студентка, спортсменка и наконец просто красавица, может позволить себе спросить более опытных товарищей об оптимальном решении, чтобы сэкономить время.
« Последнее редактирование: 17-12-2008 11:34 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
MixailK
Гость
« Ответ #56 : 19-12-2008 05:47 » new

Я так понял, что проблема состоит в том, что при неправильном вводе действительного числа возникает исключение EConvertError. Стася решила подойти к этой проблеме запретом ввода в Edit всех символов кроме цифр, минуса и запятой. А ведь у многих пользователей разделителем целой и дробной части чаще стоит "точка", а не "запятая". Я предлагаю отлавливать возникновение исключения EConvertError и сообщать об этом пользователю. Например так:
var r:real;
begin
 try
  r:=StrToFloat(Edit1.Text);
 except
  on EConvertError do begin
                                      ShowMessage('Вы ввели не действительное число! Повторите ввод.');
                                      exit;
                                   end;
 end;
end;
И если подвесить этот кусочек на событие onExit у Edit'а, то никаких проблем быть не должно. И не надо городить огород с запретом ввода, пользователь все равно будет вводить чушь всякую в Edit, а запрещать ему это делать не есть хорошо. Проще, на мой взгляд, ткнуть его носом в то, что он вводит... Улыбаюсь
Записан
DrGluck
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #57 : 19-12-2008 06:19 » 

MixailK
Я, кстати, всегда так и делаю. Потому и не имею проблем с тем, что юзер может чегото скопипастить левое.
Хотя запрет ввода в OnKeyPress тоже не помешает.

з.ы. Не забываем, что по умолчанию разделителем является '.'  Юзаем DecimalSeparator если нужно использовать в качестве разделителя другой знак.
Записан

Good user - dead user
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #58 : 19-12-2008 06:38 » 

Фильтрация ввода, прежде всего - вопрос удобства и надежности GUI и простоты дальнейшей обработки. А еще это просто красиво. Вполне достаточно создать такой контрол один раз, оформить в пакет и пользоваться, не думая о сложностях ввода.

Кстати, разделитель - хорошая мысль - стоит ввод "." и "," преобразовать в DecimalSeparator - удобнее будет при вводе с numpad при включенной русской раскладке.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
zubr
Гость
« Ответ #59 : 19-12-2008 07:19 » 

DecimalSeparator - не совсем красивое решение, так как это глобальная переменная. То есть устанавливая DecimalSeparator в какойто процедуре проекта, мы устанавливаем его для всего проекта. Пример казусной ситуации: мы в проекте установили для ввода вещественных чисел в качестве разделителя ',', а какая то процедура проекта получает входные данные из какого то файла, где в качестве разделителя используется '.', причем обработка входных данных и ввода пользователя производится в разных потоках - естественно вывалится исключение. Выход из данной ситуации:
1 У входных данных (как введенных пользователем, так и полученных из файла) проверяем разделитель, к примеру с помощью функции LastDelimiter
2. В зависимости от используемого разделителя, перед вызовом функции StrToFloat делаем так:
Код:
var
  fs: TFormatSettings;
  ds: char;

begin
 ds := //какой то код проверяющий используемый сепаратор
 fs.DecimalSeparator := ds;
 StrToFloat(Edit1.Text, fs);
end;
Тогда даже если обработка будет вестись в разных потоках, казуса не произойдет.
Записан
Страниц: 1 [2] 3  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines