Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Компоненты и классы
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.02.2017, 14:40
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию TWebBrowser - цвет выделенного текста, когда приложение не в фокусе

Добрый день.
Возникла такая необходимость:
При выделении текста в WebBrowser он отображается корректно, но если приложение потеряет фокус, то визуально выделение становится не видно, хотя оно и остаётся.
Можно ли как-то перенастроить TWebBrowser для того, чтобы выделение было как в браузере серым цветом при потере фокуса?

Скриншот для большего понимания:
Ответить с цитированием
  #2  
Старый 22.02.2017, 20:31
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, в принципе, можно попробовать "поправить" стили в загруженной таблице.
Ответить с цитированием
  #3  
Старый 27.02.2017, 07:37
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Ну, в принципе, можно попробовать "поправить" стили в загруженной таблице.

Т.е. подключить стиль для отображения пассивного выделения, когда приложение не в фокусе? Искал эту тему в рамках JavaScript или HTML, ничего не нашёл. Такое есть в CSS или где-то ещё?
Ответить с цитированием
  #4  
Старый 27.02.2017, 11:07
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Да, именно CSS.
Ответить с цитированием
  #5  
Старый 27.02.2017, 11:18
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Да, именно CSS.

Есть ли какие-нибудь примеры? В сети в справочниках по CSS там всего 4 свойства: color, background, background-color и text-shadow. Ничего похожего на цвет не в фокусе.
https://webref.ru/css/selection
Ответить с цитированием
  #6  
Старый 27.02.2017, 15:18
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Вообще, я так понимаю, TWebBrowser использует IE как основу, а в IE тоже воспроизводится, что выделение вне фокуса визуально не отображается. То есть это конкретно реализация браузера так выполнена.
В других браузерах визуальное выделение без фокуса везде реализовано.
Похоже, остаётся CSS, но возможно ли через него это реализовать?
Ответить с цитированием
  #7  
Старый 28.02.2017, 14:11
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Правильно понимаете, WebBrowser входит в состав системного IE как ActiveX контрол, и тянет за собой все "прелести" мелкомяконького обозревателя, нужно менять настройки там. Можно ещё при потере/получении фокуса менять цвет выделенного фрагмента текста средствами OleObject as IHTMLDocument посредством тега <span style=...>, попробовал такое, но это оказалось слишком гиморно, бросил
Ответить с цитированием
  #8  
Старый 28.02.2017, 15:47
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Цитата:
Сообщение от Alegun
Можно ещё при потере/получении фокуса менять цвет выделенного фрагмента текста средствами OleObject as IHTMLDocument посредством тега <span style=...>, попробовал такое, но это оказалось слишком гиморно, бросил

Та же идея. Полдня сегодня потратил на похожий вариант: использовать JavaScript, подменяющий выделенный фрагмент по MouseUp, точнее добавляющий по бокам нужный тег для цвета. Но всплыло сразу несколько проблем:
- выделение нескольких блоков в какой-нибудь таблице не позволит себя отформатировать, потому что внутри будет начало табличных тегов, а замена прошла за его скобками, браузер просто проигнорирует такие левые теги, нарушающие порядок тегов;
- нужно следить за тем, что теги уже были добавлены к выделенному тексту, не добавлять их повторно;
- нужно удалять теги опять же после потери выделения, что вызывает основную головную боль.

Так что да, идея реализовать через форматирование тегами (что JS, что методами TWBrowser) обречена на провал.

Цитата:
Сообщение от Alegun
"прелести" мелкомяконького обозревателя, нужно менять настройки там.

Там тоже не нашёл такой надстройки. Пробовал включать/выключать ускорители или копаться в безопасности. Ничего не помогло. Похоже, Мелкомягкие попросту не подумали об этой детали на этапе архитектуры и теперь её поддержку не могут в него внести.

Всё же в идеале реализовать это нужно через код - будет меньше зависимости от настроек в системе пользователя.
Возможно, стоит подумать в сторону хитростей. Скажем, перевыделять выделенный текст при потере фокуса и как-то его отображать потемнее.
Ответить с цитированием
  #9  
Старый 02.03.2017, 07:36
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Поменять цвет фона выделения
Код:
var
 SelObj: IHTMLSelectionObject;
 SelRange: IHtmlTxtRange;
begin
 SelObj:= (WebBrowser1.Document as IHTMLDocument2).selection;
 SelRange:= SelObj.CreateRange as IHtmlTxtRange;
 SelRange.execCommand('BackColor', false, '#FFCC00');

{Вернуть дефолтный 
 SelRange.execCommand('BackColor', false, 'false');
}
end;

Последний раз редактировалось Alegun, 02.03.2017 в 07:40.
Ответить с цитированием
Этот пользователь сказал Спасибо Alegun за это полезное сообщение:
Droltromed (02.03.2017)
  #10  
Старый 02.03.2017, 09:01
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Цитата:
Поменять цвет фона выделения

Спасибо большое, действительно работает. В USES для него пришлось подцепить MSHTML.
Повесил на ApplicationEvents.OnDeactivate - выделяет выделенный текст цветом при потере фокуса формой.
Но появилась проблема - если повесить
Код:
SelRange.execCommand('BackColor', false, 'false');
на OnActivate, то текст сначала сбрасывает выделение при клике на форме, а уже потом срабатывает сброс цвета, т.е. у ничего.

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

Спасибо, практически идеальное решение) Попытаюсь решить вопрос с получением формой фокуса, чтобы сбросить цвет до сброса выделения и отпишусь об успехе или неудаче.
Ответить с цитированием
  #11  
Старый 02.03.2017, 09:27
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Вот пример HTML редактора для разборки, у меня правда не пошёл, среда не та
Вложения
Тип файла: zip htmleditor.zip (103.5 Кбайт, 11 просмотров)
Ответить с цитированием
  #12  
Старый 02.03.2017, 12:03
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
Хорошо

Цитата:
Вот пример HTML редактора для разборки, у меня правда не пошёл, среда не та
У меня тоже не взлетел, к сожалению. Но выглядит отменно, полноценный редактор на вид, кропотливая работа)

В общем, решение завершил.
Реализовал так:

Эту часть запихнул в ApplicationEvents.OnDeactivate
Код:
var
 SelObj: IHTMLSelectionObject;
 SelRange: IHtmlTxtRange;
begin
 SelObj:= (WebBrowser1.Document as IHTMLDocument2).selection;
 SelRange:= SelObj.CreateRange as IHtmlTxtRange;
 SelRange.execCommand('BackColor', false, '#FFCC00'); //даём цвет выделенной части
end;

И эту часть запихнул в ApplicationEvents.OnMessage:

Код:
var
 SelObj: IHTMLSelectionObject;
 SelRange: IHtmlTxtRange;
begin
 if (Msg.message=WM_LBUTTONDOWN) or (Msg.message=WM_RBUTTONDOWN) then
 begin  
  SelObj:= (Form13.WebBrowser1.Document as IHTMLDocument2).selection;
  SelRange:= SelObj.CreateRange as IHtmlTxtRange;
  SelRange.execCommand('BackColor', false, 'false'); //убираем цвет с выделения
 end;
end;

Как оказалось, OnActivate срабатывает уже после обработки события, через которое получен фокус назад (будь это alt+tab, клик мыши или что-то ещё), поэтому в нём бесполезно ловить выделенный текст: он будет уже потерян после клика мышью по окну браузера. А OnMessage срабатывает как раз перед всеми обработчиками, именно там и ловим нажатие мыши.

Повесил проверку именно левой или правой кнопки мыши, потому что выделение из браузера снять больше нечем. Провёл небольшие тесты: ни одно из событий получения фокуса (кнопки, горячие клавиши) не снимут выделение браузера, кроме левой или правой кнопки мыши и кроме одного события:

- если кликнуть на заголовок окна, то оно не засчитается в OnMessage как клик мышью. Это создало небольшую проблему. Поэтому просто берём и запихиваем в OnActivate то же самое, что и в OnDeactivate, но снимающее цвет:
Код:
var
 SelObj: IHTMLSelectionObject;
 SelRange: IHtmlTxtRange;
begin
 SelObj:= (Form13.WebBrowser1.Document as IHTMLDocument2).selection;
 SelRange:= SelObj.CreateRange as IHtmlTxtRange;
 SelRange.execCommand('BackColor', false, 'false'); //убираем цвет с выделения
end;

В итоге получаем: при снятии фокуса с приложения окрашивается цвет выделенного. При получении фокуса кликом цвет снимается через OnMessage. При получении фокуса кликом по заголовку в дело вступает OnActivate и тоже снимает цвет с выделения.

Есть в этом небольшой минус - множество холостых срабатываний если просто кликать по окну, вызывая OnMessage или когда получаем фокус кликом (срабатывает OnMessage, а следом OnActivate, получая двойной сброс цвета).

Благо предложенный код не создаёт тормоза при выполнении и не вызывает исключений, если у браузера ничего не выделено, но вызывает исключения если в браузере ничего не открыто. Поэтому если бывают случаи держать браузер пустым, то обработку можно просто завернуть в Try Except или проверять наполненность браузера.

В остальном, реализация получилась именно такой, как хотелось и задумывалось. Большое спасибо за предложенный код, Alegun .
Ответить с цитированием
  #13  
Старый 02.03.2017, 12:26
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Вообще можно было бы оставить только OnActivate и OnDeactivate, но для этого в OnActivate вместо
Код:
SelObj:= (Form13.WebBrowser1.Document as IHTMLDocument2).selection;
Нужно получать не selection, а весь текст из браузера, чтобы снять с него цвет, включая и ту часть, где был цвет действительно был. Тогда будет незачем так излишне трястись за сохранение выделения перед его потерей.
Но проблема в другом, как этой переменной внести не selection, а весь текст целиком? Пробовал вместо .selection что-нибудь в стиле .text, .all или вообще убирать - не принимает. Впрочем, сама переменная подразумевает получение IHTMLSelectionObject. Можно ли как-то SelRange подсунуть не IHTMLSelectionObject, а конкретно body, toString или какой-нибудь другой вид всего текста разом?


UPD: нашёл решение:
В ApplicationEvents.OnActivate вписываем:
Код:
var SelRange: IHtmlTxtRange;
begin
 SelRange:=((WebBrowser1.Document AS IHTMLDocument2).body AS IHTMLBodyElement).createTextRange; //получаем весь текст
 SelRange.execCommand('BackColor', false, 'false'); //сбрасываем цвет у всего текста
end;

В ApplicationEvents.OnDeactivate, соответственно, остаётся:
Код:
var
 SelObj: IHTMLSelectionObject;
 SelRange: IHtmlTxtRange;
begin
 SelObj:= (WebBrowser1.Document as IHTMLDocument2).selection;
 SelRange:= SelObj.CreateRange as IHtmlTxtRange;
 SelRange.execCommand('BackColor', false, '#FFCC00'); //устанавливаем цвет выделенной части
end;
И готово. OnMessage не требуется. Холостых срабатываний не будет - теперь цвет красится при потере фокуса и сбрасывается цвет у текста при получении фокуса. Называется "сделай своими руками фичу, имеющуюся во всех браузерах, у единственного браузера в мире, у которого её нет"

Последний раз редактировалось Droltromed, 02.03.2017 в 14:14.
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо Droltromed за это полезное сообщение:
Alegun (02.03.2017), dr. F.I.N. (03.03.2017)
  #14  
Старый 02.03.2017, 16:44
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Оффтоп: Респект за упёртость и въедчивость, хорошо ведь, когда досконально всё прорабатывается

Мож поможет:
Цитата:
Сообщение от Samum2000
... У WebBrowser...есть метод execCommand интерфейса IHTMLTxtRange (он описан в модуле MSHTML_TLB). Рассмотрим простой пример.

procedure TForm1.SpeedButton2Click(Sender: TObject);
var
Range: IHTMLTxtRange;
begin
Range:=(editor.selection.createRange as IHTMLTxtRange);
Range.execCommand('bold',false,emptyparam)
end;

Сначала в этой процедуре создается объект Range. После этого вызывается метод execCommand:

function execCommand(cmdID: WideString; ShowUI: WordBool; Value: OleVariant): wordbool;
cmdID – это строка идентификатор команды (в нашем примере 'bold' заставляет редактор переключаться между жирным и обычным начертанием текста); полный список команд смотри в приложении.
ShowUI – Show User Interface - показывать интерфейс пользователя (если таковой имеется, как правило это различные диалоговые окна). Если параметр равен False, то команда выполняется без предупреждения.
value – содержит дополнительную информацию в зависимости от команды.

Несколько слов об объекте Range. Помимо уже знакомого нам execCommand этот объект обладает еще рядом свойств и методов, некоторые из которых сейчас рассмотрим.

Text WideString Содержит текст выделения (без тегов HTML)
HTMLText WideString Полный текст выделения
moveStart(const unit_:widestring;
count:integer) procedure Перемещает начальную позицию выделения на count символов вправо (если count<0, то влево), unit_-единицы измерения смещения (чаще всего используется 'character': 1 символ). При этом конечная позиция не смещается.
moveStart(const unit_:widestring;count:integer) procedure То же самое, только для конечной позиции выделения.
PasteHTML(const html: widestring); procedure Вставляет HTML-строку
execCommandShowHelp(cmdID: widestring); Function,
wordbool Отображает помощь по команде, указанной в cmdID

...

Доступные команды

BackColor Устанавливает или получает цвет фона текущего выделения. Value должно содержать имя цвета или его шеснадцитиричный RGB эквивалент (например, #FFCC00).
Bold Переключает начертание текста текущего выделения между полужирным и нормальным.
Copy Копирует выделение в буфер обмена
CreateBookmark Получает имя якоря или создает его для текущего выделения. Value - строка, содержащая имя якоря.
CreateLink Получает URL ссылки или создает новую ссылку. Параметр Value должен содержать URL.
Cut Вырезает текущее выделение в буфер обмена.
Delete Очищает текущее выделение (удаляет всё его содержимое).
Find Находит текст, заданный в параметре Value в текущем выделении.
FontName Устанавливает шрифт для текущего выделения. Value содержит описание этого шрифта (как в теге FONT).
FontSize Устанавливает размер шрифта. Value - число от 1 до 7 включительно.
ForeColor Устанавливает цвет текста. Value должно содержать имя цвета или его шеснадцитиричный RGB эквивалент (например, #FFCC00)
FormatBlock Устанавливает или получает форматирование текущего блока. Value может содержать теги-описатели.
Indent Увеличивает отступ выделенного текста на одну единицу приращения
InsertButton Записывает идентификатор кнопки вместо текущего выделения. Value - строка, содержащая идентификатор кнопки.
InsertFieldset То же для поля ввода.
InsertHorizontalRule То же для горизонтальной полосы.
InsertIFrame То же для встроеных фреймов (IFRAME).
InsertImage То же для изображений.
InsertInputButton То же для кнопки.
InsertInputCheckbox То же для чекбоксов (checkBox).
InsertInputFileUpload То же для элемента выбора файла.
InsertInputHidden То же для скрытого поля (hidden)
InsertInputImage То же для изображения.
InsertInputPassword То же для поля ввода пароля.
InsertInputRadio То же для радио-кнопок (Radio)
InsertInputReset То же для кнопки reset.
InsertInputSubmit То же для кнопки Submit.
InsertInputText То же для поля ввода текста.
InsertParagraph Вставляет новый раздел (абзац).
InsertOrderedList Переключает стиль текущего выделения между списком и простым текстом.
InsertUnorderedList То же самое.
InsertSelectDropdown Записывает элемент Drop-down вместо текущего выделения. Value должно содержать идентификатор элемента.
InsertTextArea То же для элемента TextArea.
Italic Переключает начертание текста текущего выделения между наклонным и обычным.
JustifyCenter Устанавливает выравнивание по центру для всего блока, в котором расположено текущее выделение.
JustifyLeft Устанавливает выравнивание по левому краю для всего блока, в котором расположено текущее выделение.
JustifyRight Устанавливает выравнивание по правому краю для всего блока, в котором расположено текущее выделение.
Outdent Уменьшает отступ для всего блока, в котором расположено выделение, на одну единицу.
OverWrite Переключается между режимами вставки текста и замены текста при вводе. Value: true - замена, false - вставка.
Paste Вставляет текст из буфера обмена вместо текущего выделения.
Refresh Обновляет текущий документ.
RemoveFormat Удаляет из текущего фрагмента все теги форматирования
SelectAll Выделяет все содержимое документа.
UnBookmark Удаляет все закладки из текущего выделения.
Underline Переключает начертание текста текущего выделения между подчеркнутым и обычным.
Unlink Удаляет все гиперссылки из текущего выделенного фрагмента.
Unselect Снимает выделение.
Ответить с цитированием
  #15  
Старый 02.03.2017, 17:37
Droltromed Droltromed вне форума
Прохожий
 
Регистрация: 22.02.2017
Сообщения: 9
Версия Delphi: Delphi XE10
Репутация: 10
По умолчанию

Цитата:
Оффтоп: Респект за упёртость и въедчивость, хорошо ведь, когда досконально всё прорабатывается
Спасибо Привык обдумывать сразу все лазейки, где могут быть проблемы и оптимизировать код, избегая бесполезной обработки.

Цитата:
Мож поможет:
Хорошая статья для работы с браузером, спасибо. Думаю, определённо как-нибудь пригодится. Заодно скачаю архив из подписи, за него тоже спасибо)
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 02:12.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter