Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > Delphi > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Ответ
 
Опции темы
Старый 01.11.2018, 19:54   #1
Вадим Мошев
гигаМодератор :)
Заслуженный модератор
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес:
Сообщений: 7,797
Репутация: 3781
По умолчанию [РЕШЕНО][Delphi] При копировании из редактора кода или текстовых полей разработанного приложения русский текст вставляется крокозябрами / в испорченной кодировке.

Иногда так бывает, что надо скопировать текст/код, содержащий кириллические буквы, из редактора кода или текстовых полей разработанного приложения.

Проблема состоит в том, что, когда такой текст вставляется в другие текстовые редакторы, кириллические символы вставляются в неверной кодировке. Например, такой код:
Код:

// комментарии
procedure TForm1.FormCreate(Sender: TObject);
begin
 showMessage('Всё хорошо')
end;

end.

Может быть вставлен в таком виде:

_________
Решение проблемы:
Перед тем, как копировать текст, переключите язык ввода на русский. Всё должно скопироваться и вставиться нормально.
См. следующее сообщение, там ещё одно решение.
____________
Ключевые слова для поиска темы
Текст код из Делфи Delphi вставляется криво крокозябрами кракозябрами в испорченной неверной кодировке

Последний раз редактировалось Вадим Мошев; 24.11.2018 в 21:37.
Вадим Мошев вне форума   Ответить с цитированием
Старый 24.11.2018, 19:00   #2
Вадим Мошев
гигаМодератор :)
Заслуженный модератор
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес:
Сообщений: 7,797
Репутация: 3781
По умолчанию Ещё одно решение проблемы

Переключение языка ввода перед копированием текста – пожалуй, рабочий вариант во всех случаях. Но он не всегда удобен в том плане, что конечному пользователю надо сообщать дополнительно (либо в справочной документации, либо на форме самого приложения) о необходимости переключения языка ввода. Можно переключать язык ввода автоматически перед работой с буфером обмена (далее - БО), но, как я говорил ранее, проблема возникает и тогда, когда происходит копирование из стороннего приложения в наше. Если способ отследить такое и существует, мне он неизвестен. Потом, переключение языка ввода без ведома пользователя - в некотором роде моветон, с моей точки зрения, поэтому такой способ здесь не рассматривается.

Сейчас я расскажу о способе решения проблемы, который был найден мной в ходе разработки своей небольшой программы.

Во-первых, вам нужно подключить модуль 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

Последний раз редактировалось Вадим Мошев; 14.12.2018 в 13:17.
Вадим Мошев вне форума   Ответить с цитированием
Старый 24.11.2018, 19:23   #3
Аватар
Модератор
Заслуженный модератор
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Адрес: Северодонецк.ua
Сообщений: 18,097
Репутация: 6385
По умолчанию

Самое простое решение - перейти на юникодный делфи. И танцы с бубном отпадут )
__________________
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар на форуме   Ответить с цитированием
Старый 11.12.2018, 19:04   #4
Вадим Мошев
гигаМодератор :)
Заслуженный модератор
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес: Адрес:
Сообщений: 7,797
Репутация: 3781
По умолчанию

Как я заметил, неприятность выше описанного метода заключается в том, что иногда при помещении текста в буфер обмена, появляется ошибка "Не могу открыть буфер обмена" ("can't open clipboard" или как-то так), при этом текст копируется без проблем.

Чтобы избежать появления этой ошибки, я советую тело обработчика помещения текста в буфер обмена обернуть в try/except.
В секции except писать ничего не надо - текст копируется нормально, но задача состоит в том, чтобы избежать появления сообщения об ошибке.
Возможно, это быдлокод, но лучшего / более красивого решения я пока не могу предложить.
Таким образом, этот код будет выглядеть так:
Код:

procedure TForm1.drawClipboard(var AMsg: TWMDrawClipboard);
begin
  try
    clipboard.AsText;
  except
  end;
end;

Вадим Мошев вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Редактор кода Delphi 10.2: новый код button вставляется в модуль куда хочет KBO Общие вопросы Delphi 13 17.03.2018 03:48
Защита значений текстовых полей от HEX редактора. Вавел из ГМТУ Общие вопросы Delphi 7 18.03.2017 11:48
Ошибка Дан произвольный русский текст. Проверить каких букв в нем больше: гласных или согласных(Delphi) Sunshinee Помощь студентам 6 15.12.2015 20:14
текст из текстовых полей Kolombina Microsoft Office Word 12 25.02.2011 18:31


15:42.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru