Изменить регистр? Легко!
© 2003 Сергей Каптарь
Многие сталкиваются с проблемой изменения регистра строковых полей во всей базе данных. Можно конечно сделать программу, которая приведёт все записи к нужному регистру, а если программно это сделать невозможно, ведь в названиях могут встречаться аббревиатуры, сокращения и так далее. В этом случае можно облегчить труд вашего пользователя с помощью частичной автоматизации. Автоматизация заключается в том, что пользователю не нужно будет заново вводить весь текст, он сможет выделить нужный ему кусок текста и двумя-тремя действиями изменит весь фрагмент!
В своей первой статье хочу рассказать о том, как можно довольно быстро расширить функциональность TEdit (при желании, вы можете сами легко доработать код под нужный вам компонент).
Итак, что требуется?
При нажатии клавиши, например F11, в любом TEdit любой формы программы, необходимо получить диалоговое окно:

рис.1 Диалог изменения текста.
с помощью которого преобразовать введённую в TEdit строку целиком или фрагмент строки. При чём если TEdit недоступен для изменения (ReadOnly=True или Enabled=False) или PasswordChar не равен #0, то диалогового окна показывать ненужно!
Цель ясна, приступаем...
Создаём форму (TForm2) изображённую на рис.1. Стиль формы делаем bsDialog и прячем кнопки максимизации и сворачивания окна. Всем компонентам TRadioButton устанавливаем следующие обработчики:
procedure TForm2.RadioButton1DblClick(Sender: TObject); begin ModalResult:=mrOk; end; procedure TForm2.RadioButton1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key=VK_Return then ModalResult:=mrOk; end;
Кнопкам "ОК" и "Отмена" устанавливаем ModalResult в mrOk и mrCancel соответственно, дополнительно для кнопки "Отмена" устанавливаем Cancel=True.
В форму добавляем функцию, которая будет возвращать пользовательский выбор:
TForm2 = class(TForm)
...
public
{ Public declarations }
function GetUserChoice: integer;
end;
...
function TForm2.GetUserChoice: integer;
begin
if RadioButton1.Checked then Result:=1
else
if RadioButton2.Checked then Result:=2
else
if RadioButton3.Checked then Result:=3
else
if RadioButton4.Checked then Result:=4
else
if RadioButton5.Checked then Result:=5
else
Result:=-1;
end;
Теперь переходим к главной форме проекта (TForm1). Исходный код будет поясняться в комментариях:
TForm1 = class(TForm)
...
private
{ Private declarations }
...
procedure AppMessage(var Msg: TMsg; var Handled: Boolean); //глобальный обработчик
procedure ChangeRegister(Msg: TMsg); //процедура изменения текста
...
public
{ Public declarations }
...
end;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
...
Application.OnMessage:=AppMessage; //устанавливаем глобальный обработчик сообщений
...
end;
//==============================================================================
//Глобальный обработчик сообщений
//==============================================================================
procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
...
//если нажата клавиша F11, то...
if (Msg.message=WM_KEYDOWN) and (Msg.wParam=VK_F11) then ChangeRegister(Msg);
...
end;
//==============================================================================
//Функция возвращает имя класса по хэндлу (Handle)
//==============================================================================
function GetClassNameStr(h: HWND): String;
var
ClsName: array[0..127] of Char;
begin
GetClassName(h,ClsName,128);
Result:=Trim(StrPas(ClsName));
end;
//==============================================================================
//Функция возвращает истину, если указанному хэндлу соответствует имя класса
//==============================================================================
function IsClass(h: HWND; ClassName: String): boolean;
begin
Result:=UpperCase(GetClassNameStr(h))=UpperCase(ClassName);
end;
//==============================================================================
//Функция возвращает истину, если окно на которое указывает хэндл имеет стиль ReadOnly
//==============================================================================
function IsReadOnly(h: HWND): boolean;
begin
Result:=(GetWindowLong(h,GWL_STYLE) and ES_READONLY)<>0;
end;
//==============================================================================
//Функция возвращает текст окна на который указывает хэндл
//==============================================================================
function GetText(h: HWND): String;
var
TXT: PChar;
Size: integer;
begin
//определяем размер
Size:=GetWindowTextLength(h)+1;
//выделяем память
GetMem(TXT,Size);
//получаем текст заданного размера
GetWindowText(h,TXT,Size);
Result:=StrPas(TXT);
//освобождаем память
FreeMem(TXT,Size);
end;
//==============================================================================
// Следующие пять функций для обработки строк:
//TextToLowerCase, TextToUpperCase, TextToFirstUpperCase,
//TextToInversCase, ChangeLocalStr
//Во всех функциях входные параметры одинаковые:
//S: String; StartPos,EndPos: integer
//где S - изменяемая строка
// StartPos,EndPos - начальная и конечная позиция для указания изменяемого
//фрагмента
//==============================================================================
//==============================================================================
//Функция приводит фрагмент строки к нижнему регистру
//==============================================================================
function TextToLowerCase(S: String; StartPos,EndPos: integer): String;
var
i: integer;
begin
//проверяем границы диапазона
if EndPos>Length(S) then EndPos:=Length(S);
if StartPos<1 then StartPos:=1;
//перебираем все символы от начальной позиции до конечной
for i:=StartPos to EndPos do
S[i]:=AnsiLowerCase(S[i])[1];
Result:=S;
end;
//==============================================================================
//Функция приводит фрагмент строки к верхнему регистру
//==============================================================================
function TextToUpperCase(S: String; StartPos,EndPos: integer): String;
var
i: integer;
begin
//проверяем границы диапазона
if EndPos>Length(S) then EndPos:=Length(S);
if StartPos<1 then StartPos:=1;
//перебираем все символы от начальной позиции до конечной
for i:=StartPos to EndPos do
S[i]:=AnsiUpperCase(S[i])[1];
Result:=S;
end;
//==============================================================================
//Функция приводит фрагмент строки к нижнему регистру, а так же первые буквы
//каждого слова к верхнему регистру
//==============================================================================
function TextToFirstUpperCase(S: String; StartPos,EndPos: integer): String;
var
i: integer;
isSpase: boolean; //True - предыдущий символ был пробел, False - предыдущий символ не пробел
begin
//проверяем границы диапазона
if EndPos>Length(S) then EndPos:=Length(S);
if StartPos<1 then StartPos:=1;
if StartPos=1 then
isSpase:=True
else
isSpase:=S[StartPos-1]=#32;
//перебираем все символы от начальной позиции до конечной
for i:=StartPos to EndPos do
begin
if (S[i]<>#32) then
begin
//если предыдущий символ был пробел, то текущий символ приводим к верхнему регистру
if isSpase then
begin
S[i]:=AnsiUpperCase(S[i])[1];
isSpase:=False;
end
else
S[i]:=AnsiLowerCase(S[i])[1];
end
else isSpase:=True;
end;
Result:=S;
end;
//==============================================================================
//Функция выполняет инверсию регистра в выделенном фрагменте строки
//==============================================================================
function TextToInversCase(S: String; StartPos,EndPos: integer): String;
var
i: integer;
function IsLowerCase(Ch: Char): boolean;
begin
Result:=Ch=AnsiLowerCase(Ch);
end;
begin
//проверяем границы диапазона
if EndPos>Length(S) then EndPos:=Length(S);
if StartPos<1 then StartPos:=1;
//перебираем все символы от начальной позиции до конечной
for i:=StartPos to EndPos do
if IsLowerCase(S[i]) then
S[i]:=AnsiUpperCase(S[i])[1]
else
S[i]:=AnsiLowerCase(S[i])[1];
Result:=S;
end;
//==============================================================================
//qwerty<>йцукен
//==============================================================================
function ChangeLocalStr(S: String; StartPos,EndPos: integer): String;
const
EnStr='`~@#$^&|qQwWeErRtTyYuUiIoOpP[{]}aAsSdDfFgGhHjJkKlL;:'+''''+'"zZxXcCvVbBnNmM,<.>/?';
RuStr='ёЁ"№;:?/йЙцЦуУкКеЕнНгГшШщЩзЗхХъЪфФыЫвВаАпПрРоОлЛдДжЖэЭяЯчЧсСмМиИтТьЬбБюЮ.,';
var
i, ien, iru: integer;
begin
//проверяем границы диапазона
if EndPos>Length(S) then EndPos:=Length(S);
if StartPos<1 then StartPos:=1;
//перебираем все символы от начальной позиции до конечной
for i:=StartPos to EndPos do
begin
//ищем позицию в "английской" строке
ien:=pos(S[i],EnStr);
//если нашёл, то заменяем символ на соответствующий символ "русской" строки
if ien>0 then
S[i]:=RuStr[ien]
else
begin
//Ищем позицию в "русской" строке
iru:=pos(S[i],RuStr);
if iru>0 then S[i]:=EnStr[iru]
end;
end;
Result:=S;
end;
//==============================================================================
//Процедура смены регистра введённого текста в TEdit. (По нажатии F11)
//==============================================================================
procedure TForm1.ChangeRegister(Msg: TMsg);
var
Form2: TForm2;
UserChoice, StartPos, EndPos, i, OriginalStartPos, OriginalEndPos: integer;
isSelected: boolean;
S, S1: String;
isOk: boolean;
begin
//если ссылка указывает на TEdit и этот элемент управления видимый (Visible),
//разрешённый (Enabled), не ReadOnly и PasswordChar=#0, то...
if IsClass(Msg.hwnd,'TEDIT') and //проверяем класс элемента на который указывает Handle
IsWindowVisible(Msg.hwnd) and //Visible ?
(IsWindowEnabled(Msg.hwnd)) then //Enabled ?
if not IsReadOnly(Msg.hwnd) and //ReadOnly?
(SendMessage(Msg.hwnd,EM_GETPASSWORDCHAR,0,0)=0) then //PasswordChar ?
begin
//получаем текст окна
S:=GetText(Msg.hwnd);
//если текст есть, то...
if S<>'' then
begin
//создаём форму TForm2
Form2:=TForm2.Create(Application);
//определяем начальную и конечную позицию выделенного блока
StartPos:=0; EndPos:=0;
i:=SendMessage(Msg.hwnd,EM_GETSEL,StartPos,EndPos);
//запоминаем результат для дальнейшего восстановления выделения
OriginalStartPos:=LoWord(i);
OriginalEndPos:=HiWord(i);
//а с этими значениями мы будем работать
StartPos:=OriginalStartPos;
EndPos:=OriginalEndPos;
//если есть выделенный текст, то устанавливаем галочку "Изменить только выделенный текст"
Form2.CheckBox1.Enabled:=StartPos<>EndPos;
Form2.CheckBox1.Checked:= Form2.CheckBox1.Enabled;
//открываем диалоговое окно и запоминаем на какую кнопку пользователь нажал (ОК или Отмена)
isOk:=Form2.ShowModal=mrOk;
//если пользователь нажал кнопку "ОК", то...
if isOk then
begin
//запоминаем пользовательский выбор
UserChoice:=Form2.GetUserChoice; //выбор пользователя
isSelected:=Form2.CheckBox1.Checked; //изменять только выделенный текст
end else
begin
UserChoice:=-1;
isSelected:=False;
end;
//освобождаем память занимаемую диалоговым окном
Form2.Free;
if isOk then
begin
//если пользователь выбрал "Изменить только выделенный текст", то...
//устанавливаем границы, так как строки в pascal нумеруются с 1, то...
StartPos:=StartPos+1;
if isSelected then
begin
//проверяем и при необходимости корректируем границы диапазона
if StartPos=EndPos then
begin
StartPos:=1;
EndPos:=Length(S);
end;
if StartPos>EndPos then
begin
i:=StartPos;
StartPos:=EndPos;
EndPos:=i;
end;
end
else
begin
//выбираем весь диапазон
StartPos:=1;
EndPos:=Length(S);
end;
//в зависимости от выбора пользователя вызываем ту или иную функцию
//для обработки текста
case UserChoice of
1: S1:=TextToLowerCase(S,StartPos,EndPos);
2: S1:=TextToUpperCase(S,StartPos,EndPos);
3: S1:=TextToFirstUpperCase(S,StartPos,EndPos);
4: S1:=TextToInversCase(S,StartPos,EndPos);
5: S1:=ChangeLocalStr(S,StartPos,EndPos);
end;
//если текст изменился, то сохраняем его в TEdit
if S1<>S then
begin
SetWindowText(Msg.hwnd,PChar(S1));
//восстанавливаем курсор в исходное положение, а так же
//восстанавливаем выделение, если оно было.
SendMessage(Msg.hwnd,EM_SETSEL,OriginalStartPos,OriginalEndPos);
end;
end;
end;
end;
end;
Вот и всё! Буду рад услышать ваши предложения и замечания по статье!
Желающие могут взглянуть на пример (161K) и его исходные тексты (5.74K)
Copyright© 2003 Сергей Каптарь Специально для Delphi Plus
| 2011 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2010 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2009 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2008 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2007 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2006 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2005 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2004 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2003 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2002 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2001 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 2000 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 1999 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
- Компания по разработке программного обеспечения
- Услуги аутсорсинга в области программирования
- Как продлить срок службы картриджей
- Мошенничество во Всемирной Паутине. Осторожно: фишинг!
- Web-студия
- Как легально поднять уровень индекса цитирования.
- Мы реально сможем помочь вам в управлении предприятием
- Создание сайтов – популяризация вашего замысла
- Свой сайт. Управление ресурсом
- Семантическое ядро сайта или правила подбора ключевых фраз
- Программирование в среде Delphi 8 for .NET
- Практикум по Delphi для решения прикладных задач
- Фундаментальные алгоритмы и структуры данных в Delphi
- Delphi 6. Программирование на Object Pascal
- Delphi и технология COM
- Delphi в шутку и всерьез: что умеют хакеры
- Программирование в Delphi глазами хакера
- Delphi 2005. Секреты программирования
- Искусство создания компонентов Delphi
- Приемы программирования в Delphi на основе VCL
- Программирование баз данных в Delphi 7
- Программирование баз данных в Delphi
- Программирование в среде Delphi
- Программирование в Delphi 7
- Язык SQL в Delphi 5