Последние записи
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
- Сравнение языков на массивах. Часть 2
- wprintf как напечатать кириллицу
- Взаимодействие через командную строку
- Сравнение языков на массивах. Часть 1
- Сравнение языков по скорости
- Чтение огромных xml-файлов
- Как в Python+Selenium webdriver открыть новую вкладку в уже открытом браузере?
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
22nd
Дек
[Delphi] При копировании из редактора кода или текстовых полей разработанного приложения русский текст вставляется крокозябрами / в испорченной кодировке
Posted by obzor under Delphi
Иногда так бывает, что надо скопировать текст/код, содержащий кириллические буквы, из редактора кода или текстовых полей разработанного приложения.
Проблема состоит в том, что, когда такой текст вставляется в другие текстовые редакторы, кириллические символы вставляются в неверной кодировке. Например, такой код:
// комментарии
procedure TForm1.FormCreate(Sender: TObject);
begin
showMessage('Всё хорошо')
end;
end.
Может быть вставлен в таком виде:
Решение проблемы:
Перед тем, как копировать текст, переключите язык ввода на русский. Всё должно скопироваться и вставиться нормально.
Ещё одно решение проблемы
Переключение языка ввода перед копированием текста – пожалуй, рабочий вариант во всех случаях. Но он не всегда удобен в том плане, что конечному пользователю надо сообщать дополнительно (либо в справочной документации, либо на форме самого приложения) о необходимости переключения языка ввода. Можно переключать язык ввода автоматически перед работой с буфером обмена (далее — БО), но, как я говорил ранее, проблема возникает и тогда, когда происходит копирование из стороннего приложения в наше. Если способ отследить такое и существует, мне он неизвестен. Потом, переключение языка ввода без ведома пользователя — в некотором роде моветон, с моей точки зрения, поэтому такой способ здесь не рассматривается.
Сейчас я расскажу о способе решения проблемы, который был найден мной в ходе разработки своей небольшой программы.
Во-первых, вам нужно подключить модуль RusClipboard.pas (согласно информации в Интернете, автор — Игорь Цысь (Igoreha), igoreha@i.com.ua)
Код модуля:
unit RusClipboard;
interface
uses Clipbrd;
type
TRusClipboard = class(TClipboard)
private
procedure SetCodePage(const CodePage: longint);
public
procedure Open; override;
procedure Close; override;
end;
implementation
uses Windows;
{ TRusClipboard }
procedure TRusClipboard.Close;
begin
SetCodePage($0419);
inherited;
end;
procedure TRusClipboard.Open;
begin
inherited;
SetCodePage($0419);
end;
procedure TRusClipboard.SetCodePage(const CodePage: longint);
var
Data: THandle;
DataPtr: Pointer;
begin
// Назначить кодовую страницу для буфера обмена
Data:= GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, 4);
try
DataPtr := GlobalLock(Data);
try
Move(CodePage, DataPtr^, 4);
SetClipboardData(CF_LOCALE, Data);
finally
GlobalUnlock(Data);
end;
except
GlobalFree(Data);
end;
end;
var
NewClipboard: TClipboard;
OldClipboard: TClipboard;
initialization
NewClipboard := TRusClipboard.Create;
OldClipboard := SetClipboard(NewClipboard);
OldClipboard.Free;
end.
Говорят, его надо просто подключить к проекту. В секции uses укажите имя модуля – rusClipboard. Но у меня так не работало. Здесь может быть неясно, как его использовать. Хорошо, что я сразу догадался использовать класс, написанный в этом модуле – TRusClipboard. Значит, вторым шагом после подключения модуля будет создание переменной типа TRusClipboard в секции private класса вашей формы:
type
TForm1 = class(TForm)
...
private
{ Private declarations }
clipboard: TRusClipboard; // <----
public
{ Public declarations }
end;
В обработчике создания формы надо выделить для него память
procedure TForm1.FormCreate(Sender: TObject);
begin
clipboard:=TRusClipboard.Create; // <---
end;
А в обработчике закрытия формы память освободить:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
clipboard.Free; // <---
end;
Решая проблему кодировки при копировании символов, я заметил, что всё копируется нормально, если при помещении информации в БО просто обратиться к свойству asText переменной БО, то есть, clipboard.asText. Из этого следует, что нам нужен обработчик помещения (текстовой) информации в БО. В отличие от двух предыдущих, средства Delphi 7 не позволяют автоматически подготовить для него код, поэтому его надо написать самому. Для этого в секции private класса нашей формы надо записать заголовок обработчика:
type
TForm1 = class(TForm)
...
private
{ Private declarations }
clipboard: TRusClipboard;
procedure drawClipboard(var AMsg: TWMDrawClipboard); message WM_DRAWCLIPBOARD; // <---
public
{ Public declarations }
end;
Справа от заголовка процедуры располагается ключевое слово message, за которым следует имя обрабатываемого сообщения. Это означает, что эта процедура будет являться обработчиком сообщения о помещении в буфер обмена информации. Далее, в разделе implementation необходимо написать реализацию этого обработчика. Здесь я рекомендую поставить курсор на строку с заголовком этого обработчика и воспользоваться комбинацией клавиш CTRL+SHIFT+C. В этом случае IDE создаст для вас заготовку для обработчика автоматически. Как я говорил ранее, при помещении текста в БО, надо обратиться к свойству asText переменной clipboard. Таким образом, реализация обработчика будет иметь следующий код:
procedure TForm1.drawClipboard(var AMsg: TWMDrawClipboard);
begin
clipboard.AsText; // <---
end;
Я не разбирался, как работает класс БО в Delphi, и частности его дочерний TRusClipboard, поэтому для меня это – танцы с бубном, особенно, если учесть, что, asText – это не подпрограмма.
Чтобы это работало, нам надо разместить окно нашего приложения в цепочке наблюдателей БО. Для этого сначала мы создадим приватное поле с типом HWND:
type
TForm1 = class(TForm)
...
private
{ Private declarations }
clipboard: TRusClipboard;
nextWindowHandle: HWND; // <---
procedure drawClipboard(var AMsg: TWMDrawClipboard); message WM_DRAWCLIPBOARD;
public
{ Public declarations }
end;
а в обработчике создания формы вызовем функцию setClipboardViewer, которой передадим дескриптор главного окна программы. Эта функция размещает окно, дескриптор которого мы передаём, в цепочке наблюдателей БО, и возвращает дескриптор следующего окна в цепочке. Имеем:
procedure TForm1.FormCreate(Sender: TObject);
begin
clipboard:=TRusClipboard.Create;
nextWindowHandle:=SetClipboardViewer(handle); // <---
end;
Обратите внимание на порядок строк в этом обработчике. Размещать окно в цепочке необходимо ПОСЛЕ выделения памяти для БО.
В обработчике закрытия формы нам надо изъять помещённое ранее окно из цепочки наблюдателей. Для этого вызывается функция changeClipboardChain. Она принимает два аргумента, первый из которых – дескриптор извлекаемого окна, а второй дескриптор замещающего окна. Мы его получали ранее, это окно, следующее за нашем в цепочке. Имеем:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
changeClipboardChain(handle, nextWindowHandle); // <---
clipboard.Free;
end;
Я считаю, что возвращаемый результат этой функции нам не нужен в данном случае, поэтому я его ничему не присваиваю.
Все эти операции достаточно выполнить в модуле основной формы. Во всех остальных формах вашего проекта работа с БО также будет происходить корректно.
Демонстрацию работы данного способа я размещаю как в приложении, так и во внешней ссылке.
Сейчас настройки форума таковы, что для скачивания вложений вам необходимо зарегистрироваться.
Ссылка на демо-проект на яндексДиске: https://yadi.sk/d/3JpEtpV6UpruSQ
Вложение: D.rar
Смотрите важное продолжение здесь: http://www.programmersforum.ru/showp…15&postcount=4
Случайные статьи
Купить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)