qt: use application FocusChanged slot to catch focus change events instead of listening for focus events of individual widgets. This new way should give better feedback from qt about focus changes.

git-svn-id: trunk@14361 -
This commit is contained in:
paul 2008-03-02 06:10:36 +00:00
parent fea0292e3d
commit f7c7ce2ff8
5 changed files with 59 additions and 68 deletions

View File

@ -24,7 +24,7 @@
Sets the owner of this canvas
------------------------------------------------------------------------------}
Procedure TControlCanvas.SetControl(AControl: TControl);
procedure TControlCanvas.SetControl(AControl: TControl);
begin
if FControl <> AControl then
begin

View File

@ -55,6 +55,10 @@ type
private
App: QApplicationH;
SavedDCList: TList;
// global hooks
FAppEvenFilterHook: QObject_hookH;
FAppFocusChangedHook: QApplication_hookH;
FOldFocusWidget: QWidgetH;
FDockImage: QRubberBandH;
FDragImageList: QWidgetH;
@ -75,6 +79,7 @@ type
function CreateThemeServices: TThemeServices; override;
function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
procedure FocusChanged(old: QWidgetH; now: QWidgetH); cdecl;
procedure OnWakeMainThread(Sender: TObject);
public
function LCLPlatform: TLCLPlatform; override;
@ -242,6 +247,22 @@ begin
end;
end;
function GetFirstQtObjectFromWidgetH(WidgetH: QWidgetH): TQtWidget;
begin
Result := nil;
if WidgetH = nil then
Exit;
repeat
Result := QtObjectFromWidgetH(WidgetH);
if Result = nil then
begin
WidgetH := QWidget_parentWidget(WidgetH);
if WidgetH = nil then
break;
end;
until Result <> nil;
end;
{$I qtobject.inc}
{$I qtwinapi.inc}
{$I qtlclintf.inc}

View File

@ -97,24 +97,26 @@ end;
procedure TQtWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
var
Method: TMethod;
FHook: QObject_hookH;
ScreenDC: HDC;
begin
App := QApplication_Create(@argc, argv);
WakeMainThread := @OnWakeMainThread;
FOldFocusWidget := nil;
{
check whether this hook crashes on linux & darwin and why it is so
we need this hook to catch release messages
}
// install global event filter
FHook := QObject_hook_create(App);
FAppEvenFilterHook := QObject_hook_create(App);
TEventFilterMethod(Method) := @EventFilter;
QObject_hook_hook_events(FHook, Method);
QObject_hook_hook_events(FAppEvenFilterHook, Method);
// install focus change slot
FAppFocusChangedHook := QApplication_hook_create(App);
QApplication_focusChanged_Event(Method) := @FocusChanged;
QApplication_hook_hook_focusChanged(FAppFocusChangedHook, Method);
ScreenDC := GetDC(0);
try
@ -187,6 +189,10 @@ end;
------------------------------------------------------------------------------}
procedure TQtWidgetSet.AppTerminate;
begin
// free hooks
QObject_hook_destroy(FAppEvenFilterHook);
QApplication_hook_destroy(FAppFocusChangedHook);
AppProcessMessages; // process pending messages since there can be release messages
QCoreApplication_quit;
end;
@ -299,6 +305,32 @@ begin
end;
end;
procedure TQtWidgetSet.FocusChanged(old: QWidgetH; now: QWidgetH); cdecl;
var
OldWidget, NewWidget: TQtWidget;
Msg: TLMessage;
begin
OldWidget := GetFirstQtObjectFromWidgetH(old);
NewWidget := GetFirstQtObjectFromWidgetH(now);
if OldWidget = NewWidget then
Exit;
FillChar(Msg, SizeOf(Msg), 0);
if OldWidget <> nil then
begin
Msg.msg := LM_KILLFOCUS;
Msg.wParam := PtrUInt(NewWidget);
OldWidget.DeliverMessage(Msg);
end;
if NewWidget <> nil then
begin
Msg.msg := LM_SETFOCUS;
Msg.wParam := PtrUInt(OldWidget);
NewWidget.DeliverMessage(Msg);
end;
end;
procedure TQtWidgetSet.OnWakeMainThread(Sender: TObject);
var
Event: QEventH;

View File

@ -126,7 +126,6 @@ type
procedure SlotShow(vShow: Boolean); cdecl;
function SlotClose: Boolean; cdecl; virtual;
procedure SlotDestroy; cdecl;
procedure SlotFocus(Event: QEventH; FocusIn: Boolean); cdecl;
procedure SlotHover(Sender: QObjectH; Event: QEventH); cdecl;
function SlotKey(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
procedure SlotMouse(Sender: QObjectH; Event: QEventH); cdecl;
@ -1518,14 +1517,6 @@ begin
QEventDestroy: SlotDestroy;
QEventEnter,
QEventLeave: SlotMouseEnter(Sender, Event);
QEventFocusIn: SlotFocus(Event, True);
QEventFocusOut:
begin
SlotFocus(Event, False);
if QFocusEvent_reason(QFocusEventH(Event)) <> QtMouseFocusReason then
releaseMouse;
end;
QEventHoverEnter,
QEventHoverLeave,
QEventHoverMove:
@ -1647,51 +1638,6 @@ begin
DeliverMessage(Msg);
end;
{------------------------------------------------------------------------------
Function: TQtWidget.SlotFocus
Params: None
Returns: Nothing
------------------------------------------------------------------------------}
procedure TQtWidget.SlotFocus(Event: QEventH; FocusIn: Boolean); cdecl;
{$ifdef VerboseFocus}
const
QtFocusReasonToStr: array[QtFocusReason] of String =
(
{QtMouseFocusReason } 'QtMouseFocusReason',
{QtTabFocusReason } 'QtTabFocusReason',
{QtBacktabFocusReason } 'QtBacktabFocusReason',
{QtActiveWindowFocusReason} 'QtActiveWindowFocusReason',
{QtPopupFocusReason } 'QtPopupFocusReason',
{QtShortcutFocusReason } 'QtShortcutFocusReason',
{QtMenuBarFocusReason } 'QtMenuBarFocusReason',
{QtOtherFocusReason } 'QtOtherFocusReason',
{QtNoFocusReason } 'QtNoFocusReason'
);
{$endif}
var
Msg: TLMessage;
begin
{$ifdef VerboseFocus}
WriteLn('TQtWidget.SlotFocus In=',FocusIn,' For ', dbgsname(LCLObject),
' Reason = ', QtFocusReasonToStr[QFocusEvent_reason(QFocusEventH(Event))]);
if QFocusEvent_reason(QFocusEventH(Event)) = QtTabFocusReason then
DebugLn('Warning Qt handled Tab and set focus iself. Event for object ', dbgsname(LCLObject));
{$endif}
FillChar(Msg, SizeOf(Msg), #0);
if FocusIn then
Msg.Msg := LM_SETFOCUS
else
Msg.Msg := LM_KILLFOCUS;
DeliverMessage(Msg);
{$ifdef VerboseFocus}
WriteLn('TQtWidget.SlotFocus END');
{$endif}
end;
procedure TQtWidget.SlotHover(Sender: QObjectH; Event: QEventH); cdecl;
var
Msg: TLMessage;

View File

@ -1754,15 +1754,7 @@ begin
begin
// Capture widget can be child of complex control. In any case we should return TQtWidget as result.
// So we will look for parent while not found apropriate LCL handle.
repeat
Widget := QtObjectFromWidgetH(w);
if Widget = nil then
begin
w := QWidget_parentWidget(w);
if w = nil then
break;
end;
until Widget <> nil;
Widget := GetFirstQtObjectFromWidgetH(w);
Result := HWND(Widget);
end
else