Текущий архив: 2006.12.17;
Скачать: CL | DM;
ВнизScrollbar & Enabled - bug? Найти похожие ветки
← →
HCode (2006-02-19 18:04) [0]procedure TForm1.MainFormFormCreate(Sender: PObj);
begin
ScrollBar1.Enabled:= false; // Не работает!
// Button1.Visible:= false; // Работает.
end;
Поверхностная отладка показала, что при вызове SetEnabled - ScrollBar1.fHandle = 0.
P.S. Версия KOL - 2.33
← →
Vladimir Kladov (2006-02-19 21:56) [1]ну так в чем проблема? Трудно вызвать GetWndowHandle, что ли.
← →
HCode (2006-02-19 22:50) [2]В смысле? В KOL.SetEnabled?
← →
ECM © (2006-02-20 11:41) [3]Посмотрел ситуацию...
> Трудно вызвать GetWndowHandle, что ли.
Это, конечно, первое что приходит в голову - но, к сожалению, дела не меняет..:(procedure TForm1.KOLForm1FormCreate(Sender: PObj);
begin
ScrollBar1.CreateWindow;
ScrollBar1.Enabled := FALSE;
end;
Хендл окна создается - запрет его тоже проходит нормально...
Но, ScrollBar1 всё равно в конце-концов получается Enabled = TRUE.
Происходит это из-за отложенной инициализации ScrollBar-a при создании:
//[function WndProcScrollBar]function WndProcScrollBar( Sender: PControl; var Msg: TMsg; var Rslt: Integer ): Boolean;
begin
Result := False;
case Msg.message of
WM_CREATE:
PostMessage(Sender.Handle, KSB_INITIALIZE, KSB_KEY, KSB_KEY);
KSB_INITIALIZE:
if (Msg.wParam = Msg.lParam) and (Msg.wParam = KSB_KEY) then
begin
Sender.SBPageSize := Sender.fSBPageSize;
Sender.SBMinMax := Sender.fSBMinMax;
Sender.SBPosition := Sender.fSBPosition; end;
end;
end;
Жирные строки (даже каждая в отдельности) приводит к тому, что окно
скроллбара снова оказывается незапрещенным.
Тайный смысл почему тут используется PostMessage (а не прямая инициализация в NewScrollbar или уж в крайнем случае SendMessage) мне неясен...
У меня получилось исправить сей момент двумя способами:
1) Заменить PostMessage на SendMessagefunction WndProcScrollBar( Sender: PControl; var Msg: TMsg; var Rslt: Integer ): Boolean;
begin
Result := False;
case Msg.message of
WM_CREATE:
SendMessage(Sender.Handle, KSB_INITIALIZE, KSB_KEY, KSB_KEY);
KSB_INITIALIZE:
if (Msg.wParam = Msg.lParam) and (Msg.wParam = KSB_KEY) then
begin
Sender.SBPageSize := Sender.fSBPageSize;
Sender.SBMinMax := Sender.fSBMinMax;
Sender.SBPosition := Sender.fSBPosition;
end;
end;
end;
2) Заставить выполниться инициализацию до запрета ScrollBar-a (пока не годится для MCK):procedure TForm1.KOLForm1FormCreate(Sender: PObj);
begin
ScrollBar1.CreateWindow;
Applet.ProcessMessages;
ScrollBar1.Enabled := FALSE;
end;
← →
homm © (2006-02-20 12:36) [4]
> Тайный смысл почему тут используется PostMessage (а не прямая
> инициализация в NewScrollbar или уж в крайнем случае SendMessage)
> мне неясен...
Только не в NewScrollbar, а в WndProcScrollBar реакцией на WM_CREATE. В NewScrollbar нет еще хендела, и
Sender.SBPageSize := Sender.fSBPageSize;
идентично
Sender.fSBPageSize := Sender.fSBPageSize;
2 Vladimir Kladov
> ну так в чем проблема? Трудно вызвать GetWndowHandle, что ли.
По-моему это откровенная грубость. Зачем так на новичков нападать?
← →
ECM © (2006-02-20 14:50) [5]
> Только не в NewScrollbar, а в WndProcScrollBar реакцией
> на WM_CREATE. В NewScrollbar нет еще хендела
Это как раз понятно...это касаемо первого варианта решения [3]
Я имел ввиду второй вариант решения (может я слишком сумбурно описал)
т.е. всмыле что особой разницы между вызовом CreateWindow в OnFormCreare и в функции NewScrollBar нет... :))
← →
Vladimir Kladov (2006-02-20 16:15) [6]Ну хорошо, в OnFormCreate не прокатывает, последняя инстанция, что ли. Есть еще OnShow (только флажок добавить, что показ идет в первый раз), там и сделать.
А вообще из мухи слона делаете. Что за надобность такая скроллбар запрещать (вдруг). Не проще ли сделать, чтобы его не было видно, пока он не нужен.
а жирных строк в коде я не вижу. Dolphin"ом смотрю, а он не показывает. (Иначе было бы очень весело грузить некоторые ветки на полторы сотни сообщений в браузере)
← →
ECM © (2006-02-20 17:08) [7]Да нет, никаких мух и слонов...:)
Я думаю - вариант с заменой Post на Send - ставит всё на свои места
кода не увеличивает - глюки вроде не добавляет...
я в письме забросил исправление...
← →
HCode (2006-02-20 17:47) [8]
> Ну хорошо, в OnFormCreate не прокатывает, последняя инстанция,
> что ли. Есть еще OnShow (только флажок добавить, что показ
> идет в первый раз), там и сделать.
Уважаемый Владимир, разумеется, прежде чем сообщить сюда об этой ошибке я попробывал вызывать ScrollBar1.Enabled:= false; в OnFormCreate, но к сожалению это не помогло.
← →
Vladimir Kladov (2006-02-20 18:55) [9]А зачем тогда вообще посылать сообщение? Я бы мог прямо в WM_CREATE и сделать все что нужно. Но увы...
Я же говорю: есть еще OnShow.
← →
HCode (2006-02-20 20:02) [10]
> Уважаемый Владимир, разумеется, прежде чем сообщить сюда
> об этой ошибке я попробывал вызывать ScrollBar1.Enabled:
> = false; в OnFormCreate, но к сожалению это не помогло.
Извините, описался :(
Как раз имелось ввиду не OnCreate, а OnShow!
← →
ECM © (2006-02-20 21:12) [11]
> Но увы...
А можно узнать подробнее почему?
Что-то я никак не могу понять причину... в каких случаях еще может приходить "ненужный" WM_CREATE?
Заранее благодарен...
← →
Vladimir Kladov (2006-02-20 21:22) [12]если даже в OnShow не работает, делается так: в OnShow себе же (форме) отправляется сообщение например WM_USER_1, в OnMessage оно ловится, и делает что надо. Есть еще метод "ленивый": таймер на 100 ms "завести", но тут гарантий чуть меньше.
А кстати, может и не работать в OnShow, действительно: ведь сообщение которое там в обработчике WM_CREATE отправлялось, может (и даже наверняка) оказалось в очереди после которое вызывает срабатывание OnShow.
← →
HCode (2006-02-20 22:55) [13]
> если даже в OnShow не работает, делается так: в OnShow себе
> же (форме) отправляется сообщение например WM_USER_1, в
> OnMessage оно ловится, и делает что надо. Есть еще метод
> "ленивый": таймер на 100 ms "завести", но тут гарантий чуть
> меньше.
МудрЕно :)
> А кстати, может и не работать в OnShow, действительно: ведь
> сообщение которое там в обработчике WM_CREATE отправлялось,
> может (и даже наверняка) оказалось в очереди после которое
> вызывает срабатывание OnShow.
Странно... На кнопке, рамке и возможно других элементах - работает, даже в OnCreate, не говоря уже о OnShow. Почему это присуще только ScrollBar"у?
← →
Vladimir Kladov (2006-02-21 19:53) [14]Точно сказать не могу. Создал тестовый проект, походил по шагам. (Кстати, отложенная отправка сообщения форме работает). WS_DISABLED в стиле есть, но при создании окна скроллбара ни на что не влияет. Видимо, так устроен скролбар в АПИ. Для него срабатывает EnableWindow / WM_ENABLE, но только когда он уже виден на экране.
← →
ECM © (2006-02-21 21:00) [15]
> WS_DISABLED в стиле есть, но при создании окна скроллбара
> ни на что не влияет. Видимо, так устроен скролбар в АПИ.
> Для него срабатывает EnableWindow / WM_ENABLE, но только
> когда он уже виден на экране.
Мне кажется Вы не правы - WS_DISABLED при создании - влияет как надо
просто потом при обработке KSB_INITIALIZE в WndProcScrollBar он заново
разрешается см. [3]. В этом можно убедится если временно изметить в KOL.PAS:
function NewScrollBar( AParent: PControl; BarSide: TScrollerBar ): PControl;
const SBS_Directions: array[ TScrollerBar ] of DWORD = ( SBS_HORZ or SBS_BOTTOMALIGN,
SBS_VERT or SBS_RIGHTALIGN );
begin
Result := _NewCommonControl(
AParent,
"SCROLLBAR",
WS_VISIBLE or WS_CHILD or WS_DISABLED or SBS_Directions[ BarSide ],
False,
nil
);
Result.DetachProc(WndProcCtrl);
Result.fLookTabKeys := [tkTab];
// Result.AttachProc(WndProcScrollBar);
AParent.AttachProc(WndProcScrollBarParent);
end;
Подчеркнутый текст у Вас тоже не виден?
(добавлен WS_DISABLED и выброшена WndProcScrollBar)
Можно убедится что в тестовом проекте - ScrollBar будет задизабленным
← →
ECM © (2006-02-21 21:10) [16]З.Ы. т.е все дело в применении SetScrollInfo (и SetScrollRange - имхо надо бы пользоваться только SetScrollInfo как рекомендовано в MSDN) - без флага
SIF_DISABLENOSCROLL сбрасывает состояние DISABLED.
← →
HCode (2006-02-28 15:27) [17]2 Vladimir Kladov
Если установить свойство в ScrollBar даже в среде разработки, то ScrollBar все равно доступен пользователю :(
2 ECM
Можно ли боротся с этой ошибкой без модификации KOL.pas?
← →
ECM © (2006-02-28 16:31) [18]
> Можно ли боротся с этой ошибкой без модификации KOL.pas?
Можно - см. пост [3] вариант 2)
← →
Vladimir Kladov (2006-02-28 20:39) [19]я вообще плохо реагирую на слово "баг". Для меня баг, это когда все падает, и надо систему перезагружать.
Так все-таки, чего исправлять? А то что-то запутался. (Нет, ECM, в самом деле, все выкинуть что ли. А что останется?).
Вообще, припоминаю, что скроллбар я начал делать, а доделал кто-то другой. Можно историю поднять. А уже потом я как-то для него зеркало добавил. Так что не могу точно сказать, почему там внутри так, а не иначе.
← →
Thaddy (2006-02-28 21:29) [20]Simply calling Createwindow is dangeous and can cause leaks.
This code can also cause problems, but works in most cases (even for scrollbar)
// Code to simulate recreatewindow for KOL controls
// Surfaces protected fields and methods outside kol.pas
type
PHack = ^THack;
THack = object(TControl)end;
procedure ReCreateWindow(aControl:PControl);
begin
DestroyWindow(aControl.Getwindowhandle);// nil window is ignored
PHack(aControl).fHandle:=0; // rest of object stays intact
aControl.CreateWindow; // Now call create window
end;
← →
ecm © (2006-02-28 21:30) [21]Тут главный критерий - отсутствие багов в работе... может такая суперотложенная инициализация(Post из WM_CREATE) и нужна (хотя я не могу себе представить зачем). Я не применяю ScrollBar - мне судить тяжело - тут надо потестировать ...
На мой взгляд - надо инициализацию перенести прямо в обработчик WM_CREATE
← →
Thaddy (2006-02-28 21:41) [22]My code causes any extra information that is necessary to create the WindowClass to be reinitialised.: The KOL object remains existing, the Windwos API class is reinstantiated. The code is a free interpretation of how the VCL works!
← →
ecm © (2006-02-28 22:26) [23]Тут дело не в пересоздании (ReCreate) , а в отложеном создании окна... И в ошибке инициализации параметров окна (что естественно) до его создания.
Что касается VCL то в том что по каждому пустяку окно пересоздается - не есть хорошо...:) Т.е - это отнюдь не достоинство VCL - сколько раз приходилось наступать на грабли, что после изменения параметров окна - его Handle становился другим.
← →
Thaddy (2006-02-28 23:05) [24]Yes, I somewhat misunderstood :) But fact remains that people want "features" or even expect "feature" from the VCL to propagate to KOL :)
And my code sometimes helps a liitle ;) (But isn"t failproof!) An example is the CS_NOCLOSE style, that is not possible from default KOL code.
But I agree, better to do things right in the first place... :)
← →
HCode (2006-03-01 13:56) [25]
> Вообще, припоминаю, что скроллбар я начал делать, а доделал кто-то другой.
И к сожалению это заметно. Отсутствует возможность назначить обработчик для некоторых событий, например - SB_ENDSCROLL. Отследить это событие проверяя значение Cmd в процедуре ScrollBarSBScroll(Sender: PControl; Cmd: Word) невозможно. Приходится ловить это событие в фукции FormMessage(var Msg: tagMSG; var Rslt: Integer), что несколько неудобно.
2 ECM
Похоже, вы больше всех понимаете в этой проблеме. Пожалуйста, если вас не затруднит, покажите изменения в KOL.pas устраняющие ошибку - "Enabled" и если можно, описанную :) в начале этого сообщения.
← →
ECM © (2006-03-02 18:47) [26]Исследовав ситуацию выяснил, что для текущей версии ScrollBar-a (2.33) действительно имеет место следующее:
- невозможность "нормально" обработать SB_ENDSCROLL и SB_THUMBPOSITION;
- не работает установка ширины (для sbVertical) или высоты (для sbHorizontal);
- собственно Subj ветки :))
Исправления предложенные мной в [3] вобщем тоже негодятся (выяснил при тщательном тестировании). В результате могу предолжить вариант исправлений, который по моим тестам исправляет ситуацию полностью, (вот только не знаю правильно ли это идеологически? - без создания окна для ScrollBar-а прямо в NewScrollBar - пока не получается все поставить на место). Вобщем вот исправления для KOL.PAS (исправленные места - {!ecm}{/!ecm})://[function NewScrollBar]
function NewScrollBar( AParent: PControl; BarSide: TScrollerBar ): PControl;
const SBS_Directions: array[ TScrollerBar ] of DWORD = ( SBS_HORZ or SBS_BOTTOMALIGN,
SBS_VERT or SBS_RIGHTALIGN );
begin
Result := _NewCommonControl(
AParent,
"SCROLLBAR",
WS_VISIBLE or WS_CHILD or SBS_Directions[ BarSide ],
False,
nil
);
{!ecm}
Result.GetWindowHandle;
{/!ecm}
Result.DetachProc(WndProcCtrl);
Result.fLookTabKeys := [tkTab];
//#ecm Result.AttachProc(WndProcScrollBar);
AParent.AttachProc(WndProcScrollBarParent);
end;
//[END NewScrollBar]//[function WndProcScrollBarParent]
function WndProcScrollBarParent( Sender: PControl; var Msg: TMsg; var Rslt: Integer ): Boolean;
var
Bar: PControl;
SI: TScrollInfo;
NewPos: Integer;
AllowChange: Boolean;
Cmd: Word;
begin
Result := False;
...
Cmd := Msg.wParam and $0000FFFF;
case Cmd of
SB_BOTTOM: NewPos := SI.nMax;
SB_TOP: NewPos := SI.nMin;
SB_LINEDOWN: NewPos := SI.nPos + 1;
SB_LINEUP: NewPos := SI.nPos - 1;
SB_PAGEDOWN: NewPos := SI.nPos + Integer(SI.nPage);
SB_PAGEUP: NewPos := SI.nPos - Integer(SI.nPage);
{!ecm}
SB_THUMBPOSITION,SB_THUMBTRACK: NewPos := SI.nTrackPos;
SB_ENDSCROLL: NewPos := SI.nPos;
{/!ecm}
else
Exit;
end;
...
В результате - все три приведенных выше глюка исчезают, плюс код облегчается - теперь WndProcScrollBar не используется ...
Попробуйте протестировать у себя этот вариант...!
← →
Владимир Кладов (2006-03-03 06:35) [27]А и протестируем. Вот в выходеной буду обновление делать, заодно может уже и попадет туда. У меня есть пара проектов со скроллбаром. На них и гляну.
← →
HCode (2006-03-03 15:24) [28]Все работает, спасибо!
Но возник еще один вопрос. Почему отсутствует поддержка управления ScrollBar"а клавиатурой?
← →
ECM © (2006-03-03 15:49) [29]Во-первых присутствует, только надо включить TabStop и установить на него фокус (я думаю можно это свойство засветить в MCK - плохого в этом нет ничего - а кому то может пригодится):
ScrollBar1.Style := ScrollBar1.Style or WS_TABSTOP;
Теперь при получении фокуса (программно или после щелчка мыши) scrollbar реагирует (сам, без доп. кода в KOL)
А во вторых - это не всегда удобно - допустим у Вас два скроллбара вертикальный и горизонтальный и хочется чтобы клавиатурный скроллинг выполнялся одновременно (без переключения фокуса). Вобщем мысль такая:
Вести обработку нажатия кнопок надо в предке т.е. общем в контроле (это не всем нужно да и для этих целей уже ScrollBox есть) - и лучше это сделать в программе руками. Слишком много вариантов - все не учтешь..
Так как оно сейчас - не ограничивает Ваши возможности...
...ИМХО
Страницы: 1 вся ветка
Текущий архив: 2006.12.17;
Скачать: CL | DM;
Память: 0.54 MB
Время: 0.041 c