Страница 1 из 1

[РЕШЕНО] ShowMessage не отображает табуляцию

СообщениеДобавлено: 11.08.2021 22:38:16
artem78
Почему диалоговое окно не отображает табуляцию как в Delphi, а выводит два слова слитно?
Код: Выделить всё
ShowMessage('one' + #9 + 'two');

20210811_213408.png
20210811_213408.png (18.05 КБ) Просмотров: 17947

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 11.08.2021 23:48:34
Seenkao
{$mode delphi} - поможет?
вероятнее всего "не читаемый" символ (что довольно странно, как минимум пробел должен быть).
Может ещё из-за кодировки? Хотя... (по моему мнению) не должно. Но стоит попробовать.

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 12.08.2021 01:21:14
runewalsh
Dialogs.ShowMessage работает через WinAPI TaskDialog (а не ShowMessageW), и вот сама эта TaskDialog — да, тупо игнорирует табы, только что сам проверил. Скорее всего, с этим ничего нельзя сделать, смирись и/или заменяй на пробелы руками.

Попробовал сделать хитровывернутую UTF8-версию замены на пробелы сам:
Код: Выделить всё
{$mode objfpc} {$h+} {$codepage utf8}
const
   Tab = #9;

function ReplaceTabs(const s: utf8string; tabWidth: SizeUint): utf8string;
var
   pass: boolean;
   sp, se, rp, sLitStart: pChar;
   curWidth, nSpaces: SizeUint;
   cpLen: SizeInt;
begin
   result := '';
   for pass in boolean do
   begin
      sp := pChar(pointer(s)); se := sp + length(s); sLitStart := sp; rp := pChar(pointer(result));
      curWidth := 0;
      while sp < se do
         case sp^ of
            #13, #10:
               begin
                  sp += 1;
                  rp += 1;
                  curWidth := 0;
               end;
            #9:
               begin
                  nSpaces := tabWidth - curWidth mod tabWidth;
                  if pass then
                  begin
                     Move(sLitStart^, (rp - (sp - sLitStart))^, (sp - sLitStart) * sizeof(char));
                     FillChar(rp^, nSpaces, ' ');
                  end;
                  sp += 1;
                  sLitStart := sp;
                  rp += nSpaces;
                  curWidth += nSpaces;
               end;
            else
               begin
                  cpLen := UTF8CodepointLen(sp, se - sp, true);
                  if cpLen <= 0 then begin sLitStart := sp; break; end;
                  sp += cpLen;
                  rp += cpLen;
                  curWidth += 1;
               end;
         end;
      if pass then Move(sLitStart^, (rp - (sp - sLitStart))^, (sp - sLitStart) * sizeof(char));

      if not pass then
         if sLitStart = pChar(pointer(s)) then exit(s) else SetLength(result, rp - pChar(pointer(result)));
   end;
end;

begin
   writeln(ReplaceTabs('Hello' + Tab + 'World' + LineEnding + 'Привет,' + Tab + 'мир.', 9));
end.

Правда, она не будет такой красивой для пропорциональных шрифтов (с переменной шириной символов), какие, собственно, используются в GUI.

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 12.08.2021 06:18:52
скалогрыз
runewalsh писал(а):тупо игнорирует табы, только что сам проверил. Скорее всего, с этим ничего нельзя сделать, смирись и/или заменяй на пробелы руками.

а раз это поведение системозависимое, логично, если менять табы на пробелы будет WS.
по-моему, вполне достойно багрепорта.

на крайняк, т.к. тип диалога передаётся (idDialogBase) то для такого типа использовать MessageBox()
но сами MS рекомендуют TaskDialog

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 12.08.2021 20:47:00
artem78
Seenkao писал(а):{$mode delphi} - поможет?

Не помогло.

runewalsh писал(а):Dialogs.ShowMessage работает через WinAPI TaskDialog (а не ShowMessageW)

А в Delphi 7 используется ShowMessage, как я догадываюсь?

Также проверил Application.MessageBox и MessageDlg - там то же самое.

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 12.08.2021 21:26:08
runewalsh
artem78 писал(а):А в Delphi 7 используется ShowMessage, как я догадываюсь?

Да, TaskDialog появились в Windows Vista, а Delphi 7 вышел гораздо раньше.
Более новые версии Delphi импортируют TaskDialog динамически и при его отсутствии откатываются на ShowMessageW (хотя нет, судя по статье https://www.gunsmoker.ru/2015/12/debugg ... ase-1.html — даже не ShowMessageW, а ручную реализацию через полноценную VCL-форму). Во всяком случае, те, что поддерживают Windows XP — я не интересовался, поддерживается ли она до сих пор.

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 12.08.2021 21:54:13
artem78
runewalsh писал(а):смирись и/или заменяй на пробелы руками.


Нет уж. Тогда лучше собственный класс диалога от TForm создать.

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 13.08.2021 18:38:27
Vadim
В Linux работает.
А не пробовали вместо "#9" ставить "Char(9)"? Или ещё идея: преобразовать Вашу строку к PChar()...
Screenshot_20210813_213227.png

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 13.08.2021 21:02:03
Сквозняк
Vadim писал(а):В Linux работает.
А не пробовали вместо "#9" ставить "Char(9)"? Или ещё идея: преобразовать Вашу строку к PChar()...


Ага, счас. Пробел есть, но маленький. Ширина таба хз от чего зависит.
Изображение
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
s5: ansistring;
q2,e2: longint;
begin
s5:=char(9);
writeln('___ ',length(s5));
for e2:=1 to length(s5) do begin val(s5[e2],q2); write(q2,#13#10) end;
ShowMessage('one' + char(9) + 'two');
end;   

Код: Выделить всё
$ ./project1
___ 1
0

Зато вот так работает
Код: Выделить всё
ShowMessage('one' + #32#32#32#32 + 'two');

Но не моноширинный шрифт гадит.

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 13.08.2021 21:34:17
Alex2013
"За что погибли мухи !" :roll: Одну строчку добавить .
Код: Выделить всё
Procedure myShowMessage(S:String);
begin
  StringReplace(S,#9,#32#32#32#32,[rfReplaceAll]);
ShowMessage(S);
end;

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 13.08.2021 21:35:35
runewalsh
Сквозняк
И что это значит? Ты вообще понимаешь, что делает val(s, q)? Ты пытаешься преобразовать символ табуляции (s) в число (q). Это преобразование проваливается, потому что строка из одной табуляции не содержит корректного числа, и устанавливает q в 0. У Val есть версия с тремя аргументами — Val(s, q, code), которая при успехе выставляет code = 0, а при неудаче возвращает в code номер первого символа в строке, с которого что-то пошло не так. В случае табуляции code = 2 — за концом строки (а не 1), потому что val допускает (и пропускает) пробельные символы в начале числа, и табуляция считается пробельным символом.
dd.png
dd.png (9.02 КБ) Просмотров: 17755


Вообще, таб — это не просто N пробелов, таб добивает позицию в тексте до ближайшей фиксированной колонки. Например,
a(tab)b
aa(tab)bb
aaa(tab)bbb
— выровняет «b», «bb» и «bbb». По крайней мере, текстовые редакторы, в т. ч. редактор Lazarus'а, это соблюдают.
tabs.png
tabs.png (584 байт) Просмотров: 17753

Re: ShowMessage не отображает табуляцию

СообщениеДобавлено: 13.08.2021 22:20:35
artem78
Vadim писал(а):В Linux работает.


Программа (на данный момент) предназначена только для ОС Windows, поэтому работа в других ОС меня пока не интересует.

Преобразовать табуляцию в пробелы мне не подходит, т.к. шрифт НЕ моноширный и выводимый текст такого плана:
20210813_205359.png
20210813_205359.png (2.87 КБ) Просмотров: 17743


Вообщем, решил проблему путём создания отдельной формы с Label-ом на всё окно.

Re: [РЕШЕНО] ShowMessage не отображает табуляцию

СообщениеДобавлено: 13.08.2021 23:40:07
Сквозняк
runewalsh писал(а):И что это значит? Ты вообще понимаешь, что делает val(s, q)? Ты пытаешься преобразовать символ табуляции (s) в число (q). Это преобразование проваливается, потому что строка из одной табуляции не содержит корректного числа,

Нда, не так достал данные из строки/буквы, для получения гарантированного значения байта надо было использовать
Код: Выделить всё
writeln(byte(char(9)));

Или ord использовать.