ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 07.08.20 09:38
Оценка:
Добрый день. Простите, если сообщение не по адресу, не нашел более подходящий раздел.
Есть RichEdit, делаю расцветку достаточно большого текста. Пробегаю по словам и меняю цвет через ITextFont::SetForeColor. Иногда, когда текст достаточно большой, наблюдаю, как на мгновение вертикальная полоса прокрутки дергается то вверх, то вниз. Комментирование только этой строки проблему скрывает. Само собой, я не меняю выделение текста во время этой операции, и не перемещаю текст, поэтому причину проблемы, честно сказать, понять не могу никак.
Re: ITextFont::SetForeColor дергает полосу прокрутки
От: pilgrim_ Россия  
Дата: 07.08.20 17:55
Оценка: -1
Здравствуйте, Went, Вы писали:

W>Добрый день. Простите, если сообщение не по адресу, не нашел более подходящий раздел.

W>Есть RichEdit, делаю расцветку достаточно большого текста. Пробегаю по словам и меняю цвет через ITextFont::SetForeColor. Иногда, когда текст достаточно большой, наблюдаю, как на мгновение вертикальная полоса прокрутки дергается то вверх, то вниз. Комментирование только этой строки проблему скрывает. Само собой, я не меняю выделение текста во время этой операции, и не перемещаю текст, поэтому причину проблемы, честно сказать, понять не могу никак.

Попробуйте на время изменения атрибутов шрифта заморозить отрисовку (насколько помню ITextDocument Freeze/Unfreeze).
Re[2]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 10.08.20 09:03
Оценка:
Здравствуйте, pilgrim_, Вы писали:

_>Попробуйте на время изменения атрибутов шрифта заморозить отрисовку (насколько помню ITextDocument Freeze/Unfreeze).

Фриз-анфриз делаю. Вот так:

void CSkinView::freeze_edit(Bool freeze)
{
  m_edit_frozen = freeze;

  IUnknown* pUnk = NULL;
  m_edit.SendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk);
  if (!pUnk)
    return;

  ITextDocument* pDoc = NULL;
  pUnk->QueryInterface(IID_ITextDocument, (LPVOID*)&pDoc);
  pUnk->Release();
  if (IsBadReadPtr(pDoc, sizeof(ITextDocument)))
    return;

  if (freeze) 
  {
    HRESULT hr;
    long l;
    hr=pDoc->Undo(tomSuspend, NULL);
    pDoc->Freeze(&l);
  }
  else 
  {
    long l;
    HRESULT hr;
    hr=pDoc->Unfreeze(&l);
    hr=pDoc->Undo(tomResume, NULL);
  }

  pDoc->Release();
}


Расцветку делаю так (внутри фриза)

void CSkinView::format_range(const CHARRANGE& range, const CHARFORMAT2& format)
{
  IUnknown* pUnk = NULL;
  m_edit.SendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk);
  if (!pUnk)
    return;

  ITextDocument* pDoc = NULL;
  pUnk->QueryInterface(IID_ITextDocument, (LPVOID*)&pDoc);
  pUnk->Release();
  if (IsBadReadPtr(pDoc, sizeof(ITextDocument)))
    return;

  ITextRange* pRange = NULL;
  pDoc->Range(range.cpMin, range.cpMax, &pRange);
  pDoc->Release();
  if (IsBadReadPtr(pRange, sizeof(ITextRange)))
    return;

  ITextFont* pFont = NULL;
  pRange->GetFont(&pFont);
  pRange->Release();
  if (IsBadReadPtr(pFont, sizeof(ITextFont)))
    return;

  if (format.dwMask & CFM_COLOR)
    pFont->SetForeColor(format.crTextColor);

  pFont->Release();
}


От фриза толку никакого, что с ним, что без него. Может, нельзя сразу интерфейсы освобождать?
Re: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 18.08.20 12:11
Оценка:
Здравствуйте, Went, Вы писали:

W>Добрый день. Простите, если сообщение не по адресу, не нашел более подходящий раздел.

W>Есть RichEdit, делаю расцветку достаточно большого текста. Пробегаю по словам и меняю цвет через ITextFont::SetForeColor. Иногда, когда текст достаточно большой, наблюдаю, как на мгновение вертикальная полоса прокрутки дергается то вверх, то вниз. Комментирование только этой строки проблему скрывает. Само собой, я не меняю выделение текста во время этой операции, и не перемещаю текст, поэтому причину проблемы, честно сказать, понять не могу никак.
А как ITextFont получаете?
Aml Pages Home
Re[2]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 20.08.20 12:13
Оценка:
Здравствуйте, Carc, Вы писали:
C> А как ITextFont получаете?
Вот так. Этот код вызывается на каждое слово текста.
void CSkinView::format_range(const CHARRANGE& range, const CHARFORMAT2& format)
{
  IUnknown* pUnk = NULL;
  m_edit.SendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk);
  if (!pUnk)
    return;

  ITextDocument* pDoc = NULL;
  pUnk->QueryInterface(IID_ITextDocument, (LPVOID*)&pDoc);
  pUnk->Release();
  if (IsBadReadPtr(pDoc, sizeof(ITextDocument)))
    return;

  ITextRange* pRange = NULL;
  pDoc->Range(range.cpMin, range.cpMax, &pRange);
  pDoc->Release();
  if (IsBadReadPtr(pRange, sizeof(ITextRange)))
    return;

  ITextFont* pFont = NULL;
  pRange->GetFont(&pFont);
  pRange->Release();
  if (IsBadReadPtr(pFont, sizeof(ITextFont)))
    return;

  if (format.dwMask & CFM_COLOR)
    pFont->SetForeColor(format.crTextColor);

  pFont->Release();
}

Перед форматированием большого отрезка вызываю код "замораживания":
void CSkinView::freeze_edit(Bool freeze)
{
  m_edit_frozen = freeze;

  IUnknown* pUnk = NULL;
  m_edit.SendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk);
  if (!pUnk)
    return;

  ITextDocument* pDoc = NULL;
  pUnk->QueryInterface(IID_ITextDocument, (LPVOID*)&pDoc);
  pUnk->Release();
  if (IsBadReadPtr(pDoc, sizeof(ITextDocument)))
    return;

  HRESULT hr;
  long l;
  if (freeze) 
  {
    hr = pDoc->Undo(tomSuspend, NULL);
    hr = pDoc->Freeze(&l);
  }
  else 
  {
    hr = pDoc->Unfreeze(&l);
    hr = pDoc->Undo(tomResume, NULL);
  }

  pDoc->Release();
}

Но что с ним, что без него иногда мигает текст и полоса прокрутки.
Re[3]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 20.08.20 13:49
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Carc, Вы писали:

C>> А как ITextFont получаете?
W>Вот так. Этот код вызывается на каждое слово текста.
W>
W>void CSkinView::format_range(const CHARRANGE& range, const CHARFORMAT2& format)
W>{
W>  IUnknown* pUnk = NULL;
W>  m_edit.SendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk);
W>  if (!pUnk)
W>    return;
W>

[skipped]
W>Но что с ним, что без него иногда мигает текст и полоса прокрутки.
Посмотрел внимательно. Та вродь все верно… У меня точно такой же код, разве что малость "поприлизанее". А по смыслу тютелька в тютельку.

Но вообще говоря, вертикальная полоса прокрутки дергается только, если меняется позиция выделения\курсора… И только. Такое явление наблюдалось, когда начинаются танцы с бубнами с собственными гиперссылками. В старом ITextFont (1-ой версии) нельзя было поставить аттрибут ссылки — нет в нем SetLink (есть в ITextFont2)…

Не может быть что где-то (допустим в вызывающем коде) меняется выделение или позиция каретки (EM_(EX)SETSEL)?

Я бы сюда покопал… Во всех других случаях и версиях RichEdit, SetForeColor никак не влияет на вертикальную прокрутку. Ну по крайней мере, пока не начинаем шалить уже с самими шрифтами…

Поставить какой-нить хук-субкласс, да проверить!?!
Aml Pages Home
Re[4]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 20.08.20 13:52
Оценка:
PS: RichEdit какой версии (имя класса окна)?
Aml Pages Home
Re[5]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 21.08.20 08:53
Оценка:
Здравствуйте, Carc, Вы писали:

C>PS: RichEdit какой версии (имя класса окна)?

RichEdit20A
Re[4]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 21.08.20 09:05
Оценка:
Здравствуйте, Carc, Вы писали:
C>Не может быть что где-то (допустим в вызывающем коде) меняется выделение или позиция каретки (EM_(EX)SETSEL)?
C>Я бы сюда покопал… Во всех других случаях и версиях RichEdit, SetForeColor никак не влияет на вертикальную прокрутку. Ну по крайней мере, пока не начинаем шалить уже с самими шрифтами…
Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает.
Re[5]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 21.08.20 11:08
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Carc, Вы писали:

C>>Не может быть что где-то (допустим в вызывающем коде) меняется выделение или позиция каретки (EM_(EX)SETSEL)?
C>>Я бы сюда покопал… Во всех других случаях и версиях RichEdit, SetForeColor никак не влияет на вертикальную прокрутку. Ну по крайней мере, пока не начинаем шалить уже с самими шрифтами…
W>Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает.
А если отключить нотификации от RichEdit на изменение на время вызовы SetForeColor? Через EM_SETEVENTMASK + ENM_CHANGE
Ничего не поменяется!:!

+ опять же, попробовать поймать EN_VSCOLL, оно вообще приходит в момент SetForeColor?
Просто странное какое-то дело… У меня аккурат ITextFont::SetForeColor и используется в фоне налево и направо, по любому чиху: ввод, изменение, скроллинг и ни разу ничего подобного года не видел на SetForeColor…
Aml Pages Home
Re[6]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 21.08.20 11:09
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Carc, Вы писали:


C>>PS: RichEdit какой версии (имя класса окна)?

W>RichEdit20A
А почему не юникодный RichEdit20W?
Aml Pages Home
Re[7]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 24.08.20 05:32
Оценка:
Здравствуйте, Carc, Вы писали:

C>Здравствуйте, Went, Вы писали:


W>>Здравствуйте, Carc, Вы писали:


C>>>PS: RichEdit какой версии (имя класса окна)?

W>>RichEdit20A
C>А почему не юникодный RichEdit20W?
Да у меня все приложение как-то исторически в мультибайте пашет. А где надо работать с юникодом, работаю через Widechar-сообщения. Понятно, что костылики, но нет времени переводить всё приложение на Widechar.
Re[6]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 24.08.20 06:10
Оценка:
Здравствуйте, Carc, Вы писали:

W>>Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает.

C>А если отключить нотификации от RichEdit на изменение на время вызовы SetForeColor? Через EM_SETEVENTMASK + ENM_CHANGE
C>Ничего не поменяется!:!
Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет.

C>+ опять же, попробовать поймать EN_VSCOLL, оно вообще приходит в момент SetForeColor?

C>Просто странное какое-то дело… У меня аккурат ITextFont::SetForeColor и используется в фоне налево и направо, по любому чиху: ввод, изменение, скроллинг и ни разу ничего подобного года не видел на SetForeColor…
Нет, нотификация EN_VSCROLL не вызывается (даже если явно разрешить ее через SetEventMask).

Вот здесь записал видео, видно как дергается при вводе (и даже при прокрутке, пока происходит парсинг)
То есть получается, пока я парсю текст (сейчас я это делаю в основном потоке, но небольшими порциями по айдлу), полоса прокрутки дергается (заметь, она не только дергается, но и меняет размер), возможно, в то место, где парсила, а возможно, и куда-то непонятно куда. Если я ввожу строго по одному символу (ввел-подождал-ввел-подождал), то ничего не дергается. Если я меняю текст в процессе парсинга (быстро ввожу символы) — дергается.
Отредактировано 24.08.2020 6:14 Went . Предыдущая версия .
Re[8]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 24.08.20 07:08
Оценка:
Здравствуйте, Went, Вы писали:

W>Да у меня все приложение как-то исторически в мультибайте пашет. А где надо работать с юникодом, работаю через Widechar-сообщения. Понятно, что костылики, но нет времени переводить всё приложение на Widechar.

Знакомо…
Aml Pages Home
Re[7]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 24.08.20 07:23
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Carc, Вы писали:


W>>>Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает.

C>>А если отключить нотификации от RichEdit на изменение на время вызовы SetForeColor? Через EM_SETEVENTMASK + ENM_CHANGE
C>>Ничего не поменяется!:!
W>Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет.
Дык по ходу получается что дергает не сама SetForeColor, а парсер!?! Вроде как так?
У меня похожая реализация, парсится в основном потоке, но маленькими порциями (только видимая часть текста).

Но есть "но". Парсится не сразу на всяких там EN_SELCHANGE, EN_VSCROLL (проскролили текст) или EN_CHANGE, а парсится отложено.

Ну, если "на пальцах", в двух словах, то грубо говоря запоминается время нотификации, когда надо парсить. Взводится таймер. Когда таймер срабатывает, то проверяется время последнего события (нотификации, когда пора начинать парсить) и если таймаут прошел, тогда начинаем парсить (предполагается, что закончился активный скролл или изменение текста пользователем).

Если пока таймер "собирается" придет еще нотификация, то время прихода нотификации опять же новое и таймаут на срабатывании таймера будет меньше заданного. Тогда еще ждем, пока таймаут между последней нотификацией и срабатыванием таймера не превысит захордкоденный какой-то лимит.

Ну, это так… Принципиальная схема, так сказать. В принципе и без таймера можно. Через соседний поток, который спит-спит, нотификацией пробуждается (дергаем какой-нить примитив), ну а потом уже этот фоновый поток выполняет по сути "работу" таймера. Ну это уже детали реализации. Тут кому что нравится, кому поп, а кому попова дочка…
Aml Pages Home
Re[8]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 24.08.20 08:25
Оценка:
Здравствуйте, Carc, Вы писали:

W>>Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет.

C>Дык по ходу получается что дергает не сама SetForeColor, а парсер!?! Вроде как так?
Но если я комментирую только одну строчку с SetForeColor, то ничего уже не дергается. То есть все манипуляции парсера ничего не меняют, а вот вызов метода — порождает дёргалку.

C>Но есть "но". Парсится не сразу на всяких там EN_SELCHANGE, EN_VSCROLL (проскролили текст) или EN_CHANGE, а парсится отложено.

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

C>Ну, если "на пальцах", в двух словах...

Да, это я понимаю, спасибо. В будущем переделаю на поток. Но пока что хочется просто косметику поправить, чтобы не мельтешил скролл.
Re[9]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 24.08.20 09:31
Оценка:
Здравствуйте, Went, Вы писали:



C>>Но есть "но". Парсится не сразу на всяких там EN_SELCHANGE, EN_VSCROLL (проскролили текст) или EN_CHANGE, а парсится отложено.

W>Да и у меня так ) Я просто ивалидю фрагмент, а потом, по айдлу, запускаю парс. Но я парсю не только видимое, а до конца (ну, чтобы при перемотке вперед не было задержек).
А зачем до конца-то? Может там еще 50 страниц текста, которые и смотреть-то никто не будет?

Просто ловим EN_VSCROLL (или EN_SELCHANGE, если движемся по тексту кареткой с клавы), и парсим видимое + пару-тройку строк выше, и пару-тройку ниже. Аккурат, чтобы, если скользить по тексту построчно с клавиатуры стрелкой вниз(вверх), то появляющаяся строка уже была подсвечена…

Ну, да у меня несколько проще. При таком скролле стрелкой (EN_SELCHANGE), я сразу подкручиваю текст на пару строк или вниз или вверх. Чтобы была видна не только конкретная строка, но и некоторый фрагмент до-после, в зависимости от того, куда скроллились по тексту. Вроть как предполагая, что как правило, интересует некоторый плюс-минус фрагмент вокруг искомой строки, а не только она сама.
Aml Pages Home
Отредактировано 24.08.2020 9:36 Carc . Предыдущая версия .
Re[9]: ITextFont::SetForeColor дергает полосу прокрутки
От: Carc Россия http://www.amlpages.com/home.php
Дата: 24.08.20 09:35
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Carc, Вы писали:


W>>>Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет.

C>>Дык по ходу получается что дергает не сама SetForeColor, а парсер!?! Вроде как так?
W>Но если я комментирую только одну строчку с SetForeColor, то ничего уже не дергается. То есть все манипуляции парсера ничего не меняют, а вот вызов метода — порождает дёргалку.
Я бы тогда копал бы в сторону метода парсинга… Видимо он что-то проделывает. Плюс можно попробовать засабклассить скроллер-контрол, и половить изменение его позиции уже в своей WindowProc. Может выведет по стеку вызовов, с какого вдруг дергается текст…
Aml Pages Home
Re[3]: ITextFont::SetForeColor дергает полосу прокрутки
От: pilgrim_ Россия  
Дата: 06.09.20 21:44
Оценка:
Здравствуйте, Went, Вы писали:

W>От фриза толку никакого, что с ним, что без него. Может, нельзя сразу интерфейсы освобождать?


Если все еще актуально, дай знать, откопаю старый проект, где-то через неделю, сходу не вспомню, больше 10 лет прошло, но рич-едит насиловался по полной ,возможно и обновление скрола подавлялось принудительно.
Re[4]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 07.09.20 07:05
Оценка:
Здравствуйте, pilgrim_, Вы писали:
_>Если все еще актуально, дай знать, откопаю старый проект, где-то через неделю, сходу не вспомню, больше 10 лет прошло, но рич-едит насиловался по полной ,возможно и обновление скрола подавлялось принудительно.
Честно сказать, актуально. Если не сложно, буду очень благодарен.
Re[5]: ITextFont::SetForeColor дергает полосу прокрутки
От: pilgrim_ Россия  
Дата: 17.09.20 16:05
Оценка: 4 (1)
Здравствуйте, Went, Вы писали:

W>Здравствуйте, pilgrim_, Вы писали:

_>>Если все еще актуально, дай знать, откопаю старый проект, где-то через неделю, сходу не вспомню, больше 10 лет прошло, но рич-едит насиловался по полной ,возможно и обновление скрола подавлялось принудительно.
W>Честно сказать, актуально. Если не сложно, буду очень благодарен.

Извиняюсь за задержку, откопал таки проект, с трудом вспомнил что там да как, короче: при изменении атрибутов текста (а именно BackColor), в том числе массовые (один и более фрагментов текста, включая невидимые), в том числе с большой частотой (по таймеру, частое моргание цвета/плавная смена) помимо freez'a у TextDocument, также подавлялось событие EN_CHANGE (EM_GETEVENTMASK/EM_SETEVENTMASK + ENM_CHANGE), затем все это восстанавливалось обратно. т.е.:

..
textDOcument.Freeze();

//disable EN_CHANGE
int evtMask = (int)SendMessage(richHandle, EM_GETEVENTMASK, 0, 0);
SendMessage(richHandle, EM_SETEVENTMASK, 0,  evtMask & ~ENM_CHANGE)

//update text attributes
..

//restore events-enable EN_CHANGE
SendMessage(richHandle, EM_SETEVENTMASK, 0,  evtMask)

textDOcument.Unfreeze();
Re[6]: ITextFont::SetForeColor дергает полосу прокрутки
От: Went  
Дата: 18.09.20 07:42
Оценка:
Здравствуйте, pilgrim_, Вы писали:
_>Извиняюсь за задержку, откопал таки проект, с трудом вспомнил что там да как, короче: при изменении атрибутов текста (а именно BackColor), в том числе массовые (один и более фрагментов текста, включая невидимые), в том числе с большой частотой (по таймеру, частое моргание цвета/плавная смена) помимо freez'a у TextDocument, также подавлялось событие EN_CHANGE (EM_GETEVENTMASK/EM_SETEVENTMASK + ENM_CHANGE), затем все это восстанавливалось обратно. т.е.:
Увы, не помогло. В приципе, на момент парса у меня и так отключалась реакция на изменение текста (только на клиентской стороне), но можно было бы допустить какие-то особенности внутренней реализации РичЭдита. Пока что могу сказать только одно — "мерцание прокрутки" происходит тогда, когда я меняю текст (ну, вписываю букву с клавиатуры) очень скоро после того, как была расцветка какого-то фрагмента... Может, что-то не успело "валиднуться" или еще что-то. Может какая-то "внутренняя" каретка была сейчас где-то внизу, за видимой границей документа, где делала расцветку, и моя редактура текста приводит к какому-то непредвиденному "скачку", что отображается на полосе прокрутки...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.