|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
2004 г. Особенности работы с "русским" Excel'емАлександр Шабля, Королевствo Delphi Написанное приложение, прекрасно работающие с Excel'ем на собственном компьютере, часто, после переноса приложения на другой компьютер, оказывается неработоспособным! Отчего так происходит? В этой статья я собираюсь описать разницу в работе русской версии Excel'я из VBA и через COM интерфейс (библиотеку типов, TLB) из Delphi. Почему возникли расхождения? Ответа на эти вопросы у Microsoft я не нашел… Примечание: Описание типов объектов, применяемых в примерах: XL: TExcelApplication; WB: TExcelWorkbook; ASheet: TExcelWorksheet; R: Range; // ExcelRange - для Delphi7 Используемые в примерах "дополнительные" модули: У вас русская версия Excel?Определить наличие русской версии Excel возможно так: if XL.LanguageSettings.LanguageID[msoLanguageIDUI] = 1049 Английская версия Excel (English United States) вернет 1033 (или $0409), немецкая (German Standard) - $0407. Значения соответствуют LCID, описанным в MS SDK Help "Language Identifiers". LCID интерфейса пользователя и файла Excel.exe файла может быть неодинаковым (например, после установки MUI). Константа msoLanguageIDUI находится в модуле Office2000.pas и описана так: const msoLanguageIDUI = $00000002; Примечание: Далее мы рассмотрим приемы работы с "русским" Excel'ем. Работа со свойством объекта Range NumberFormatNumberFormat и NumberFormatLocal четко работают в VBA и полностью соответствуют своему содержанию в названиях, но только не при работе из Delphi. В Excel2000.pas (D7) они описаны как ExcelRange = dispinterface
['{00020846-0000-0000-C000-000000000046}']
...
property NumberFormat: OleVariant dispid 193;
property NumberFormatLocal: OleVariant dispid 1097;
Но, при попытке записи форматов из Delphi, выясняется, что NumberFormat и NumberFormatLocal ведут себя идентично, причем NumberFormat соответствует NumberFormatLocal (лучше было бы наоборот :). Т.е. в русской версии все форматы нужно писать "по-русски" (можно прямо в NumberFormat, в VBA - нельзя). Формат датыКод на VBA (эталон): Sub Test1()
Dim R As Range
Set R = Range("a1")
R.Clear ' очистим формулы и форматы
R.Value2 = Date ' запишем текущую дату
R.NumberFormat = "d/mm/yy" ' работает
R.NumberFormatLocal = "ДД.ММ.ГГ" ' работает
' дальше не работает
R.NumberFormat = "ДД.ММ.ГГ" ' не работает
R.NumberFormatLocal = "d/mm/yy" ' ОШИБКА!
Set R = Nothing
End Sub
Код на Delphi: R := ASheet.Range['A1', EmptyParam]; R.Value2 := Date; R.NumberFormat := 'd/mm/yy'; // ОШИБКА! R.NumberFormat := 'ДД.ММ.ГГ'; // работает R.NumberFormatLocal := 'ДД.ММ.ГГ'; // работает R.NumberFormatLocal := 'd/mm/yy'; // ОШИБКА Формат чисел. Разделители. (DecimalSeparator, ThousendSeparator)Почитайте "диалог" на Круглом столе http://www.delphikingdom.com/asp/answer.asp?IDAnswer=15340 - вроде бы все понятно ("а все и делов то в запятой")! А нет, не все! В "International" (в русском "Язык и стандарты") можно установить любые DecimalSeparator и ThousandsSeparator, отличные от принятых по-умолчанию фирмой Microsoft для русской версии Windows. Я, например, всегда меняю принятые по-умолчанию десятичную точку "," на "." и разделитель тысяч с " " (пробел) на "'" (апостроф, как в калькуляторе). Так формат "# ##0,00" у меня работать не будет... И это еще не все! Заходим в настройки Excel'я "Сервис/Параметры" переходим на закладку "Международные" и видим опять "Разделитель целой и дробной части", "Разделитель разрядов" и чекбокс "Использовать системные разделители". Т.е. использование системных разделителей не может гарантировать правильного применения при форматировании чисел в Excel'е. Решение: использовать свойство ExcelApplication.International (о нем дальше). Причем, даже при установленном свойстве ExcelApplication.UseSystemSeparators = False и отличных от системных ExcelApplication.DecimalSeparator и ExcelApplication.ThousandsSeparator, ExcelApplication.International отработает корректно. Далее рассмотрим примеры работы (или не работы), приняв "стандартные" настройки для русских Windows: Код на VBA (эталон): Sub Test2()
Dim R As Range
Set R = Range("a1")
R.Clear
R.Value = 1234567.89
R.NumberFormat = "#,##0.00" ' работает
R.NumberFormatLocal = "# ##0,00" '
Код на Delphi: R := ASheet.Range['A1', EmptyParam]; R.Value2 := 1234567.89; R.NumberFormat := '#,##0.00'; // не работает R.NumberFormatLocal := '# ##0,00'; // Примечание: Решения (с использованием ExcelApplication.International): Для получения формата даты можно написать функцию: function XL_GetShortDateFormat(XLApp: ExcelApplication): String;
var d, m, y: Integer;
begin
if XLApp.International[xlDayLeadingZero, lcid]
then d := 2 else d := 1;
if XLApp.International[xlMonthLeadingZero, lcid]
then m := 2 else m := 1;
if XLApp.International[xl4DigitYears, lcid]
then y := 4 else y := 2;
Result := Format('%1:s%0:s%2:s%0:s%3:s', [
DateSeparator,
StringOfChar(VarToStr(XLApp.International
Для формата валюты: function XL_GetCurrencyFormat(XLApp: ExcelApplication): String;
begin
Result := Format('%s "%s"', [
XL_GetNumberFormat(XLApp),
XLApp.International[xlCurrencyCode, lcid]
]);
end;
Тот же принцип можно применить к времени и другим типам. Также смотрите другие индексы для свойства International (их там много) в справке VBA. Например, получить "основной" (general) формат можно так: GenFmt := XL.International[xlGeneralFormatName, lcid]; Примечание: Цвет в форматеК сожалению, не лучше обстоит дело и с цветом в форматах. Т.е. цвет в Delphi можно задавать только по-русски: R.NumberFormat := 'Основной;[красный]-Основной';Перечень цветов по-русски, которые можно задавать в формате: черный, красный, зеленый, синий, фиолетовый, желтый, белый. Список небогатый. Формулы на листеК счастью, работа со свойствами Formula и FormulaLocal в VBA и Delphi идентична и соответствуют своим названиям. Хочется отметить только один нюанс (это, кстати, действительно и для VBA) - при написании "русских" формул нужно учитывать системную переменную ListSeparator. Так, если на другом компьютере пользователь изменит его со стандартного для русской версии Windows символа ";" на "," (например, как это делаю я :), то присвоение Range.FormulaLocal := '=округл(A1*B1; 2)'; вызовет ошибку! Поэтому, с учетом "разделителя элементов списка" нужно писать так: Range.FormulaLocal := Format('=округл(A1*B1%s 2)',
Здесь приятней и проще пользоваться английскими формулами. Но, иногда, существует необходимость писать формулы из вариантного массива… Примечание: Запись формул из Variant-ного массиваЗапись в свойство Formula, FormulaLocal, Value, Value2 из Variant-ного массива идентична в русском Excel'е и при работе из Delphi. Но, если мы хотим вставлять формулы прямо из массива, все они должны быть только русскими! Вот здесь то и всплывает необходимость определения наличия русской версии Excel'я (впрочем, это уже касалось задания цвета в свойстве NumberFormat). Код на VBA:Sub TestVariant() Dim MyVar(2, 2) As Variant ' 3 строки, 3 колонки Dim R As Long, C As Byte ' первая строка MyVar(0, 0) = 10.72 MyVar(0, 1) = 3.05 ' MyVar(0, 2) = "=round(RC[-1]*RC[-2], 2)" ' ошибка #ИМЯ? MyVar(0, 2) = "=округл(RC[-1]*RC[-2]; 2)" ' Код на Delphi (тут мы применим знание написания русских формул, описанный выше, а именно ListSeparator): var MyVar: Variant; IsRusXL: Boolean; begin ... MyVar := VarArrayCreate([0, 2, 0, 2], varVariant); // Примечание: Создание колонтитуловДавайте запустим запись макроса создания колонтитула (меню в Excel "Сервис/Макрос/Начать запись…"). Теперь откроем параметры страницы (меню "Файл/Параметры страницы…"). Создадим центральный нижний колонтитул "Лист &[Страница] из &[Страниц]" шрифтом "Arial", "полужирный" и размером 8pt. Слова "Лист" и "из" с начертанием "обычный". После "сокращения" макроса получим: Sub Макрос1()
'
ActiveSheet.PageSetup.CenterFooter = _
"&""Arial""&8Лист &""Arial,полужирный""&P" & _
"&""Arial,обычный"" из &""Arial,полужирный""&N"
End Sub
Т.е. при выводе на печать мы хотим, чтоб в нижний колонтитул по центру выводился текст, к примеру "Лист 1 из 5". Примечание: Внимание! Суммарная длина текста в нижнем или верхнем (левый + по_центру + правый) колонтитулах не должна превышать 250 символов (как и в ячейке).
Вроде бы все ясно, осталось только переписать его под Delphi: ASheet.PageSetup.CenterFooter := '&"Arial"&8Лист &"Arial,полужирный"&P' + '&"Arial,обычный" из &"Arial,полужирный"&N'; Проверяем в Excel'е "Предварительный просмотр" - оба, и не работает! А как же должно работать? Припоминая русификацию еще Excel'я 4-й версии, напишем русские эквиваленты: ASheet.PageSetup.CenterFooter :=
'&"Arial"&8Лист &"Arial,полужирный"&С' + //
Сработало! Ну, и теперь добавим распознавание русской версии: if XL.LanguageSettings.LanguageID[msoLanguageIDUI] = $0419 then ASheet.PageSetup.CenterFooter := // Вывод: при вставке кодов форматирования из Delphi в русский Excel должны вставляться только русские коды форматирования. А где их взять? Вот список кодов форматирования, полученных методом пробы:
И еще один опыт: ASheet.PageSetup.CenterFooter :=
'&"Arial"&8Лист &"Arial,bold"&С&"Arial,normal"
Работает! Т.е. начертания (Style у класса TFont в Delphi) шрифтов можно уверенно писать по-английски. Или заменить на коды форматирования: ASheet.PageSetup.CenterFooter := Примечание: ASheet.PageSetup.CenterFooter := 'Первая строка' ВыводыПри работе с русским Excel'ем из Delphi необходимо соблюдать следующие правила:
Мне не удалось найти документацию, касающуюся моментов описанных выше. Весь материал построен чисто на собственном опыте. И еще: не было возможности проверить на полностью английских версиях Windows и Office. Скачать проект: RusExcel.zip (4,6К) Все примеры тестировались на Delphi 6, Delphi 7, на русских версиях WindowsXP + OfficeXP, Windows98SE + Office2000 SR?1. |
|
CITForum © 1997–2025