Добрый день. Простите, если сообщение не по адресу, не нашел более подходящий раздел.
Есть RichEdit, делаю расцветку достаточно большого текста. Пробегаю по словам и меняю цвет через ITextFont::SetForeColor. Иногда, когда текст достаточно большой, наблюдаю, как на мгновение вертикальная полоса прокрутки дергается то вверх, то вниз. Комментирование только этой строки проблему скрывает. Само собой, я не меняю выделение текста во время этой операции, и не перемещаю текст, поэтому причину проблемы, честно сказать, понять не могу никак.
Здравствуйте, Went, Вы писали:
W>Добрый день. Простите, если сообщение не по адресу, не нашел более подходящий раздел. W>Есть RichEdit, делаю расцветку достаточно большого текста. Пробегаю по словам и меняю цвет через ITextFont::SetForeColor. Иногда, когда текст достаточно большой, наблюдаю, как на мгновение вертикальная полоса прокрутки дергается то вверх, то вниз. Комментирование только этой строки проблему скрывает. Само собой, я не меняю выделение текста во время этой операции, и не перемещаю текст, поэтому причину проблемы, честно сказать, понять не могу никак.
Попробуйте на время изменения атрибутов шрифта заморозить отрисовку (насколько помню ITextDocument Freeze/Unfreeze).
Здравствуйте, 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();
}
От фриза толку никакого, что с ним, что без него. Может, нельзя сразу интерфейсы освобождать?
Здравствуйте, Went, Вы писали:
W>Добрый день. Простите, если сообщение не по адресу, не нашел более подходящий раздел. W>Есть RichEdit, делаю расцветку достаточно большого текста. Пробегаю по словам и меняю цвет через ITextFont::SetForeColor. Иногда, когда текст достаточно большой, наблюдаю, как на мгновение вертикальная полоса прокрутки дергается то вверх, то вниз. Комментирование только этой строки проблему скрывает. Само собой, я не меняю выделение текста во время этой операции, и не перемещаю текст, поэтому причину проблемы, честно сказать, понять не могу никак.
А как ITextFont получаете?
Здравствуйте, Went, Вы писали:
W>Здравствуйте, Carc, Вы писали: C>> А как ITextFont получаете? W>Вот так. Этот код вызывается на каждое слово текста. W>
[skipped] W>Но что с ним, что без него иногда мигает текст и полоса прокрутки.
Посмотрел внимательно. Та вродь все верно… У меня точно такой же код, разве что малость "поприлизанее". А по смыслу тютелька в тютельку.
Но вообще говоря, вертикальная полоса прокрутки дергается только, если меняется позиция выделения\курсора… И только. Такое явление наблюдалось, когда начинаются танцы с бубнами с собственными гиперссылками. В старом ITextFont (1-ой версии) нельзя было поставить аттрибут ссылки — нет в нем SetLink (есть в ITextFont2)…
Не может быть что где-то (допустим в вызывающем коде) меняется выделение или позиция каретки (EM_(EX)SETSEL)?
Я бы сюда покопал… Во всех других случаях и версиях RichEdit, SetForeColor никак не влияет на вертикальную прокрутку. Ну по крайней мере, пока не начинаем шалить уже с самими шрифтами…
Поставить какой-нить хук-субкласс, да проверить!?!
Здравствуйте, Carc, Вы писали: C>Не может быть что где-то (допустим в вызывающем коде) меняется выделение или позиция каретки (EM_(EX)SETSEL)? C>Я бы сюда покопал… Во всех других случаях и версиях RichEdit, SetForeColor никак не влияет на вертикальную прокрутку. Ну по крайней мере, пока не начинаем шалить уже с самими шрифтами…
Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает.
Здравствуйте, Went, Вы писали:
W>Здравствуйте, Carc, Вы писали: C>>Не может быть что где-то (допустим в вызывающем коде) меняется выделение или позиция каретки (EM_(EX)SETSEL)? C>>Я бы сюда покопал… Во всех других случаях и версиях RichEdit, SetForeColor никак не влияет на вертикальную прокрутку. Ну по крайней мере, пока не начинаем шалить уже с самими шрифтами… W>Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает.
А если отключить нотификации от RichEdit на изменение на время вызовы SetForeColor? Через EM_SETEVENTMASK + ENM_CHANGE
Ничего не поменяется!:!
+ опять же, попробовать поймать EN_VSCOLL, оно вообще приходит в момент SetForeColor?
Просто странное какое-то дело… У меня аккурат ITextFont::SetForeColor и используется в фоне налево и направо, по любому чиху: ввод, изменение, скроллинг и ни разу ничего подобного года не видел на SetForeColor…
Здравствуйте, Went, Вы писали:
W>Здравствуйте, Carc, Вы писали:
C>>PS: RichEdit какой версии (имя класса окна)? W>RichEdit20A
А почему не юникодный RichEdit20W?
Здравствуйте, Carc, Вы писали:
C>Здравствуйте, Went, Вы писали:
W>>Здравствуйте, Carc, Вы писали:
C>>>PS: RichEdit какой версии (имя класса окна)? W>>RichEdit20A C>А почему не юникодный RichEdit20W?
Да у меня все приложение как-то исторически в мультибайте пашет. А где надо работать с юникодом, работаю через Widechar-сообщения. Понятно, что костылики, но нет времени переводить всё приложение на Widechar.
Здравствуйте, Carc, Вы писали:
W>>Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает. C>А если отключить нотификации от RichEdit на изменение на время вызовы SetForeColor? Через EM_SETEVENTMASK + ENM_CHANGE C>Ничего не поменяется!:!
Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет.
C>+ опять же, попробовать поймать EN_VSCOLL, оно вообще приходит в момент SetForeColor? C>Просто странное какое-то дело… У меня аккурат ITextFont::SetForeColor и используется в фоне налево и направо, по любому чиху: ввод, изменение, скроллинг и ни разу ничего подобного года не видел на SetForeColor…
Нет, нотификация EN_VSCROLL не вызывается (даже если явно разрешить ее через SetEventMask).
Вот здесь записал видео, видно как дергается при вводе (и даже при прокрутке, пока происходит парсинг)
То есть получается, пока я парсю текст (сейчас я это делаю в основном потоке, но небольшими порциями по айдлу), полоса прокрутки дергается (заметь, она не только дергается, но и меняет размер), возможно, в то место, где парсила, а возможно, и куда-то непонятно куда. Если я ввожу строго по одному символу (ввел-подождал-ввел-подождал), то ничего не дергается. Если я меняю текст в процессе парсинга (быстро ввожу символы) — дергается.
Здравствуйте, Went, Вы писали:
W>Да у меня все приложение как-то исторически в мультибайте пашет. А где надо работать с юникодом, работаю через Widechar-сообщения. Понятно, что костылики, но нет времени переводить всё приложение на Widechar.
Знакомо…
Здравствуйте, Went, Вы писали:
W>Здравствуйте, Carc, Вы писали:
W>>>Понимаешь, если я комментирую сам вызов SetForeColor, то прокрутка дергаться прекращает. C>>А если отключить нотификации от RichEdit на изменение на время вызовы SetForeColor? Через EM_SETEVENTMASK + ENM_CHANGE C>>Ничего не поменяется!:! W>Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет.
Дык по ходу получается что дергает не сама SetForeColor, а парсер!?! Вроде как так?
У меня похожая реализация, парсится в основном потоке, но маленькими порциями (только видимая часть текста).
Но есть "но". Парсится не сразу на всяких там EN_SELCHANGE, EN_VSCROLL (проскролили текст) или EN_CHANGE, а парсится отложено.
Ну, если "на пальцах", в двух словах, то грубо говоря запоминается время нотификации, когда надо парсить. Взводится таймер. Когда таймер срабатывает, то проверяется время последнего события (нотификации, когда пора начинать парсить) и если таймаут прошел, тогда начинаем парсить (предполагается, что закончился активный скролл или изменение текста пользователем).
Если пока таймер "собирается" придет еще нотификация, то время прихода нотификации опять же новое и таймаут на срабатывании таймера будет меньше заданного. Тогда еще ждем, пока таймаут между последней нотификацией и срабатыванием таймера не превысит захордкоденный какой-то лимит.
Ну, это так… Принципиальная схема, так сказать. В принципе и без таймера можно. Через соседний поток, который спит-спит, нотификацией пробуждается (дергаем какой-нить примитив), ну а потом уже этот фоновый поток выполняет по сути "работу" таймера. Ну это уже детали реализации. Тут кому что нравится, кому поп, а кому попова дочка…
Здравствуйте, Carc, Вы писали:
W>>Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет. C>Дык по ходу получается что дергает не сама SetForeColor, а парсер!?! Вроде как так?
Но если я комментирую только одну строчку с SetForeColor, то ничего уже не дергается. То есть все манипуляции парсера ничего не меняют, а вот вызов метода — порождает дёргалку.
C>Но есть "но". Парсится не сразу на всяких там EN_SELCHANGE, EN_VSCROLL (проскролили текст) или EN_CHANGE, а парсится отложено.
Да и у меня так ) Я просто ивалидю фрагмент, а потом, по айдлу, запускаю парс. Но я парсю не только видимое, а до конца (ну, чтобы при перемотке вперед не было задержек).
C>Ну, если "на пальцах", в двух словах...
Да, это я понимаю, спасибо. В будущем переделаю на поток. Но пока что хочется просто косметику поправить, чтобы не мельтешил скролл.
C>>Но есть "но". Парсится не сразу на всяких там EN_SELCHANGE, EN_VSCROLL (проскролили текст) или EN_CHANGE, а парсится отложено. W>Да и у меня так ) Я просто ивалидю фрагмент, а потом, по айдлу, запускаю парс. Но я парсю не только видимое, а до конца (ну, чтобы при перемотке вперед не было задержек).
А зачем до конца-то? Может там еще 50 страниц текста, которые и смотреть-то никто не будет?
Просто ловим EN_VSCROLL (или EN_SELCHANGE, если движемся по тексту кареткой с клавы), и парсим видимое + пару-тройку строк выше, и пару-тройку ниже. Аккурат, чтобы, если скользить по тексту построчно с клавиатуры стрелкой вниз(вверх), то появляющаяся строка уже была подсвечена…
Ну, да у меня несколько проще. При таком скролле стрелкой (EN_SELCHANGE), я сразу подкручиваю текст на пару строк или вниз или вверх. Чтобы была видна не только конкретная строка, но и некоторый фрагмент до-после, в зависимости от того, куда скроллились по тексту. Вроть как предполагая, что как правило, интересует некоторый плюс-минус фрагмент вокруг искомой строки, а не только она сама.
Здравствуйте, Went, Вы писали:
W>Здравствуйте, Carc, Вы писали:
W>>>Если я отключу нотификацию, то, понятное дело, ничего не будет дергаться, потому что я не буду реагировать на изменение текста и не буду запускать парсер Но если запускать его принудительно, то дергаться начнет, то есть EN_CHANGE никак не влияет. C>>Дык по ходу получается что дергает не сама SetForeColor, а парсер!?! Вроде как так? W>Но если я комментирую только одну строчку с SetForeColor, то ничего уже не дергается. То есть все манипуляции парсера ничего не меняют, а вот вызов метода — порождает дёргалку.
Я бы тогда копал бы в сторону метода парсинга… Видимо он что-то проделывает. Плюс можно попробовать засабклассить скроллер-контрол, и половить изменение его позиции уже в своей WindowProc. Может выведет по стеку вызовов, с какого вдруг дергается текст…
Здравствуйте, Went, Вы писали:
W>От фриза толку никакого, что с ним, что без него. Может, нельзя сразу интерфейсы освобождать?
Если все еще актуально, дай знать, откопаю старый проект, где-то через неделю, сходу не вспомню, больше 10 лет прошло, но рич-едит насиловался по полной ,возможно и обновление скрола подавлялось принудительно.
Здравствуйте, pilgrim_, Вы писали: _>Если все еще актуально, дай знать, откопаю старый проект, где-то через неделю, сходу не вспомню, больше 10 лет прошло, но рич-едит насиловался по полной ,возможно и обновление скрола подавлялось принудительно.
Честно сказать, актуально. Если не сложно, буду очень благодарен.