implement float spinedit for win32 (issue #1386)

git-svn-id: trunk@8139 -
This commit is contained in:
micha 2005-11-12 23:02:05 +00:00
parent 394baa43ef
commit 9793627ce5
6 changed files with 168 additions and 95 deletions

View File

@ -24,11 +24,12 @@ begin
if Value>fMaxValue then Value:=fMaxValue;
if (not HandleAllocated) then exit;
if ([csLoading,csDestroying]*ComponentState<>[]) then begin
fValueNeedsUpdate:=true;
FUpdatePending := true;
exit;
end;
TWSCustomFloatSpinEditClass(WidgetSetClass).UpdateControl(Self);
fValueNeedsUpdate:=false;
FValueChanged := true;
FUpdatePending := false;
end;
function TCustomFloatSpinEdit.ValueIsStored: boolean;
@ -37,11 +38,14 @@ begin
end;
procedure TCustomFloatSpinEdit.TextChanged;
var
lPrevValue: single;
begin
if Value=fLastValueOnChange then exit;
fLastValueOnChange:=Value;
Modified := True;
FValueEmpty:=false;
lPrevValue := FValue;
FValueChanged := true;
if Value = lPrevValue then exit;
Modified := true;
FValueEmpty := false;
if HandleAllocated and (not (csLoading in ComponentState)) then Change;
end;
@ -52,11 +56,6 @@ begin
UpdateControl;
end;
function TCustomFloatSpinEdit.ClimbRateIsStored: boolean;
begin
Result := FClimbRate <> 1;
end;
function TCustomFloatSpinEdit.GetModified: Boolean;
begin
Result := FModified;
@ -137,10 +136,10 @@ begin
UpdateControl;
end;
procedure TCustomFloatSpinEdit.SetClimbRate(const Num : Single);
procedure TCustomFloatSpinEdit.SetIncrement(const NewIncrement: single);
begin
if fClimbRate = Num then exit;
fClimbRate := Num;
if NewIncrement = FIncrement then exit;
FIncrement := NewIncrement;
UpdateControl;
end;
@ -161,7 +160,7 @@ end;
procedure TCustomFloatSpinEdit.Loaded;
begin
inherited Loaded;
if fValueNeedsUpdate then UpdateControl;
if FUpdatePending then UpdateControl;
end;
procedure TCustomFloatSpinEdit.Change;
@ -176,16 +175,17 @@ Procedure TCustomFloatSpinEdit.SetValue(const num : Single);
begin
if FValue = Num then exit;
FValue := Num;
fLastValueOnChange := FValue;
fValueNeedsUpdate:=true;
FUpdatePending := true;
UpdateControl;
end;
{-----------------------------------------------------------------------------}
Function TCustomFloatSpinEdit.GetValue: Single;
begin
if HandleAllocated and (not fValueNeedsUpdate) then begin
if HandleAllocated and FValueChanged then
begin
FValue := TWSCustomFloatSpinEditClass(WidgetSetClass).GetValue(Self);
FValueChanged := false;
end;
Result := fValue;
end;
@ -204,12 +204,13 @@ begin
inherited Create(TheOwner);
fCompStyle := csSpinEdit;
fClimbRate := 1;
FIncrement := 1;
fDecimals := 2;
fValue := 0;
fValueNeedsUpdate := true;
fMinValue := 0;
fMaxValue := 100;
FUpdatePending := true;
FValueChanged := true;
SetInitialBounds(0,0,50,20);
ParentColor := false;
@ -261,9 +262,9 @@ end;
{ TCustomSpinEdit }
function TCustomSpinEdit.GetClimbRate: integer;
function TCustomSpinEdit.GetIncrement: integer;
begin
Result:=round(FClimbRate);
Result:=round(FIncrement);
end;
function TCustomSpinEdit.GetMaxValue: integer;
@ -281,10 +282,10 @@ begin
Result:=round(inherited GetValue);
end;
procedure TCustomSpinEdit.SetClimbRate(const AValue: integer);
procedure TCustomSpinEdit.SetIncrement(const AValue: integer);
begin
if ClimbRate=AValue then exit;
inherited SetClimbRate(AValue);
if Increment = AValue then exit;
inherited SetIncrement(AValue);
end;
procedure TCustomSpinEdit.SetMaxValue(const AValue: integer);

View File

@ -440,10 +440,11 @@ Var
ScrollbarHandle := HWND(LParam);
if ScrollbarHandle<>0 then
lWinControl := GetWindowInfo(ScrollbarHandle)^.WinControl;
if lWinControl is TCustomTrackBar
then begin
LMessage.Msg := LM_CHANGED;
Exit;
if lWinControl <> nil then
begin
if lWinControl is TCustomTrackBar then
LMessage.Msg := LM_CHANGED;
exit;
end;
PLMsg:=@LMScroll;
@ -586,6 +587,42 @@ Var
begin
Result := WindowInfo^.isComboEdit and (ComboBoxHandleSizeWindow = Windows.GetParent(Window));
end;
procedure HandleSpinEditChange(ASpinEdit: TCustomFloatSpinEdit);
var
lWindowInfo: PWindowInfo;
lNewValue: single;
begin
lWindowInfo := GetWindowInfo(ASpinEdit.Handle);
if lWindowInfo = @DefaultWindowInfo then exit;
lNewValue := StrToFloatDef(ASpinEdit.Text, lWindowInfo^.spinValue);
if lNewValue <> lWindowInfo^.spinValue then
begin
lWindowInfo^.spinValue := lNewValue;
LMessage.Msg := CM_TEXTCHANGED;
end;
end;
procedure HandleSpinEditDeltaPos(AUpDownMsg: PNMUpDown);
var
lSpinEdit: TCustomFloatSpinEdit;
spinHandle: HWND;
newValue: single;
begin
lSpinEdit := TCustomFloatSpinEdit(WindowInfo^.WinControl);
newValue := WindowInfo^.spinValue + AUpDownMsg^.iDelta * lSpinEdit.Increment;
if (lSpinEdit.MinValue <> 0) or (lSpinEdit.MaxValue <> 0) then
begin
if newValue > lSpinEdit.MaxValue then
newValue := lSpinEdit.MaxValue;
if newValue < lSpinEdit.MinValue then
newValue := lSpinEdit.MinValue;
end;
spinHandle := AUpDownMsg^.hdr.hwndFrom;
UpdateFloatSpinEditText(spinHandle, NewValue, lSpinEdit.DecimalPlaces);
Windows.SendMessage(spinHandle, UDM_SETPOS32, 0, 500);
WindowInfo^.spinValue := newValue;
end;
Begin
Assert(False, 'Trace:WindowProc - Start');
@ -749,18 +786,22 @@ Begin
BN_CLICKED: LMessage.Msg := LM_CLICKED;
BN_KILLFOCUS: LMessage.Msg := LM_EXIT;
end
else if (lWinControl is TCustomEdit) or (lWinControl is TCustomFloatSpinEdit) then
else if (lWinControl is TCustomEdit) then
case Hi(WParam) of
EN_CHANGE: LMessage.Msg := CM_TEXTCHANGED;
EN_CHANGE: LMessage.Msg := CM_TEXTCHANGED;
end
else if (lWinControl is TCustomFloatSpinEdit) then
case Hi(WParam) of
EN_CHANGE: HandleSpinEditChange(TCustomFloatSpinEdit(lWinControl));
end
else if (lWinControl is TCustomMemo) then
case Hi(WParam) of
// multiline edit doesn't send EN_CHANGE, so use EN_UPDATE
EN_UPDATE: LMessage.Msg := CM_TEXTCHANGED;
EN_UPDATE: LMessage.Msg := CM_TEXTCHANGED;
end
else if (lWinControl is TCustomListBox) then
case Hi(WParam) of
LBN_SELCHANGE: LMessage.Msg := LM_SELCHANGE;
LBN_SELCHANGE: LMessage.Msg := LM_SELCHANGE;
end
else if lWinControl is TCustomCombobox then
case Hi(WParam) of
@ -1215,13 +1256,20 @@ Begin
End;
WM_NOTIFY:
Begin
if PNMHdr(LParam)^.code=MCN_SELCHANGE then begin
LMessage.Msg := LM_CHANGED;
WindowInfo := GetWindowInfo(PNMHdr(LParam)^.hwndFrom);
if WindowInfo^.WinControl<>nil then
lWinControl := WindowInfo^.WinControl;
end
else begin
WindowInfo := GetWindowInfo(PNMHdr(LParam)^.hwndFrom);
case PNMHdr(LParam)^.code of
MCN_SELCHANGE:
begin
LMessage.Msg := LM_CHANGED;
if (WindowInfo <> nil) and (WindowInfo^.WinControl <> nil) then
lWinControl := WindowInfo^.WinControl;
end;
UDN_DELTAPOS:
begin
if WindowInfo <> nil then
HandleSpinEditDeltaPos(PNMUpDown(LParam));
end;
else
PLMsg:=@LMNotify;
With LMNotify Do
Begin
@ -1238,9 +1286,9 @@ Begin
idFrom := Windows.SendMessage(HWndFrom, TCM_GETCURSEL, 0, 0);
end;
end;
End;
end;
end;
End;
end;
WM_PAINT:
Begin
SendPaintMessage;

View File

@ -54,6 +54,8 @@ Type
DrawItemIndex: integer; // in case of listbox, when handling WM_DRAWITEM
DrawItemSelected: boolean;// whether this item is selected LB_GETSEL not uptodate yet
MouseX, MouseY: word; // noticing spurious WM_MOUSEMOVE messages
case integer of
0: (spinValue: single);
end;
function WM_To_String(WM_Message: Integer): string;
@ -96,6 +98,7 @@ procedure EnableApplicationWindows(Window: HWND);
procedure AddToChangedMenus(Window: HWnd);
procedure RedrawMenus;
function MeasureText(const AWinControl: TWinControl; Text: string; var Width, Height: integer): boolean;
function GetControlText(AHandle: HWND): string;
type
PDisableWindowsInfo = ^TDisableWindowsInfo;
@ -1081,6 +1084,15 @@ begin
ReleaseDC(winHandle, canvasHandle);
end;
function GetControlText(AHandle: HWND): string;
var
TextLen: dword;
begin
TextLen := GetWindowTextLength(AHandle);
SetLength(Result, TextLen);
GetWindowText(AHandle, PChar(Result), TextLen + 1);
end;
{$IFDEF ASSERT_IS_ON}
{$UNDEF ASSERT_IS_ON}

View File

@ -35,7 +35,7 @@ uses
////////////////////////////////////////////////////
Spin, Controls, LCLType,
////////////////////////////////////////////////////
WSSpin, WSLCLClasses, Windows, Win32Int, WinExt,
WSSpin, WSLCLClasses, Windows, Win32Int, WinExt, Win32Proc,
Win32WSStdCtrls, Win32WSControls;
type
@ -52,6 +52,7 @@ type
const AParams: TCreateParams): HWND; override;
class function GetSelStart(const ACustomFloatSpinEdit: TCustomFloatSpinEdit): integer; override;
class function GetSelLength(const ACustomFloatSpinEdit: TCustomFloatSpinEdit): integer; override;
class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override;
class function GetValue(const ACustomFloatSpinEdit: TCustomFloatSpinEdit): single; override;
class procedure SetSelStart(const ACustomFloatSpinEdit: TCustomFloatSpinEdit; NewStart: integer); override;
@ -70,25 +71,43 @@ type
end;
procedure UpdateFloatSpinEditText(const ASpinHandle: HWND; const ANewValue: single;
const ADecimalPlaces: integer);
implementation
uses
SysUtils;
{ TWin32WSCustomFloatSpinEdit }
function GetBuddyWindow(AHandle: HWND): HWND;
begin
Result := SendMessage(AHandle, UDM_GETBUDDY, 0, 0)
end;
procedure UpdateFloatSpinEditControl(const Handle: HWND;
const AFloatSpinEdit: TCustomFloatSpinEdit);
var
minval, maxval: integer;
lWindowInfo: PWindowInfo;
begin
// initialize extremes
minval := Trunc(AFloatSpinEdit.MinValue);
maxval := Trunc(AFloatSpinEdit.MaxValue);
if (minval = 0) and (maxval = 0) then
lWindowInfo := GetWindowInfo(Handle);
if lWindowInfo <> @DefaultWindowInfo then
begin
minval := low(integer);
maxval := high(integer);
lWindowInfo^.spinValue := AFloatSpinEdit.Value;
UpdateFloatSpinEditText(Handle, AFloatSpinEdit.Value, AFloatSpinEdit.DecimalPlaces);
end;
SendMessage(Handle, UDM_SETRANGE32, minval, maxval);
SendMessage(Handle, UDM_SETPOS32, 0, LParam(Trunc(AFloatSpinEdit.Value)));
end;
procedure UpdateFloatSpinEditText(const ASpinHandle: HWND; const ANewValue: single;
const ADecimalPlaces: integer);
var
editHandle: HWND;
newValueText: string;
begin
editHandle := GetBuddyWindow(ASpinHandle);
newValueText := FloatToStrF(ANewValue, ffFixed, 20, ADecimalPlaces);
Windows.SendMessage(editHandle, WM_SETTEXT, 0, Windows.LPARAM(PChar(newValueText)));
end;
function TWin32WSCustomFloatSpinEdit.CreateHandle(const AWinControl: TWinControl;
@ -102,15 +121,15 @@ begin
with Params do
begin
Buddy := CreateWindowEx(WS_EX_CLIENTEDGE, 'EDIT', StrCaption, Flags Or ES_AUTOHSCROLL, Left, Top, Width, Height, Parent, HMENU(Nil), HInstance, Nil);
Window := CreateUpDownControl(Flags or DWORD(WS_BORDER or UDS_ALIGNRIGHT or UDS_NOTHOUSANDS or UDS_ARROWKEYS or UDS_WRAP or UDS_SETBUDDYINT),
Window := CreateUpDownControl(Flags or DWORD(WS_BORDER or UDS_ALIGNRIGHT or UDS_ARROWKEYS),
0, 0, // pos - ignored for buddy
0, 0, // size - ignored for buddy
Parent, 0, HInstance, Buddy,
0, 0, 0);
UpdateFloatSpinEditControl(Window, TCustomFloatSpinEdit(AWinControl));
1000, 0, 500);
end;
// create window
FinishCreateWindow(AWinControl, Params, true);
UpdateFloatSpinEditControl(Params.Window, TCustomFloatSpinEdit(AWinControl));
// init buddy
Params.SubClassWndProc := @WindowProc;
WindowCreateInitBuddy(AWinControl, Params);
@ -135,35 +154,40 @@ end;
function TWin32WSCustomFloatSpinEdit.GetSelStart(
const ACustomFloatSpinEdit: TCustomFloatSpinEdit): integer;
begin
Result := EditGetSelStart(SendMessage(ACustomFloatSpinEdit.Handle,
UDM_GETBUDDY, 0, 0));
Result := EditGetSelStart(GetBuddyWindow(ACustomFloatSpinEdit.Handle));
end;
function TWin32WSCustomFloatSpinEdit.GetSelLength(
const ACustomFloatSpinEdit: TCustomFloatSpinEdit): integer;
begin
Result := EditGetSelLength(SendMessage(ACustomFloatSpinEdit.Handle,
UDM_GETBUDDY, 0, 0));
Result := EditGetSelLength(GetBuddyWindow(ACustomFloatSpinEdit.Handle));
end;
function TWin32WSCustomFloatSpinEdit.GetText(const AWinControl: TWinControl;
var AText: string): boolean;
begin
Result := AWinControl.HandleAllocated;
if not Result then
exit;
AText := GetControlText(GetBuddyWindow(AWinControl.Handle));
end;
function TWin32WSCustomFloatSpinEdit.GetValue(
const ACustomFloatSpinEdit: TCustomFloatSpinEdit): single;
begin
Result := SendMessage(ACustomFloatSpinEdit.Handle, UDM_GETPOS32, 0, 0);
Result := GetWindowInfo(ACustomFloatSpinEdit.Handle)^.spinValue;
end;
procedure TWin32WSCustomFloatSpinEdit.SetSelStart(
const ACustomFloatSpinEdit: TCustomFloatSpinEdit; NewStart: integer);
begin
EditSetSelStart(SendMessage(ACustomFloatSpinEdit.Handle, UDM_GETBUDDY, 0, 0),
NewStart);
EditSetSelStart(GetBuddyWindow(ACustomFloatSpinEdit.Handle), NewStart);
end;
procedure TWin32WSCustomFloatSpinEdit.SetSelLength(
const ACustomFloatSpinEdit: TCustomFloatSpinEdit; NewLength: integer);
begin
EditSetSelLength(SendMessage(ACustomFloatSpinEdit.Handle, UDM_GETBUDDY, 0, 0),
NewLength);
EditSetSelLength(GetBuddyWindow(ACustomFloatSpinEdit.Handle), NewLength);
end;
procedure TWin32WSCustomFloatSpinEdit.ShowHide(const AWinControl: TWinControl);
@ -172,12 +196,11 @@ var
begin
// call inherited
TWin32WSWinControl.ShowHide(AWinControl);
Buddy := SendMessage(AWinControl.Handle, UDM_GETBUDDY, 0, 0);
Buddy := GetBuddyWindow(AWinControl.Handle);
if AWinControl.HandleObjectShouldBeVisible then
ShowWindow(Buddy, SW_SHOW)
else
ShowWindow(Buddy, SW_HIDE);
end;
procedure TWin32WSCustomFloatSpinEdit.UpdateControl(

View File

@ -667,17 +667,11 @@ begin
end;
function TWin32WSCustomComboBox.GetText(const AWinControl: TWinControl; var AText: string): boolean;
var
Handle: HWND;
TextLen: dword;
begin
Result := AWinControl.HandleAllocated;
if not Result then
exit;
Handle := AWinControl.Handle;
TextLen := GetWindowTextLength(Handle);
SetLength(AText, TextLen);
GetWindowText(Handle, PChar(AText), TextLen + 1);
AText := GetControlText(AWinControl.Handle);
end;
procedure TWin32WSCustomComboBox.SetArrowKeysTraverseList(const ACustomComboBox: TCustomComboBox;
@ -815,17 +809,11 @@ begin
end;
function TWin32WSCustomEdit.GetText(const AWinControl: TWinControl; var AText: string): boolean;
var
TextLen: dword;
Handle: HWND;
begin
Result := AWinControl.HandleAllocated;
if not Result then
exit;
Handle := AWinControl.Handle;
TextLen := GetWindowTextLength(Handle);
SetLength(AText, TextLen);
GetWindowText(Handle, PChar(AText), TextLen + 1);
AText := GetControlText(AWinControl.Handle);
end;
procedure TWin32WSCustomEdit.SetCharCase(const ACustomEdit: TCustomEdit; NewCase: TEditCharCase);

View File

@ -37,19 +37,18 @@ type
TCustomFloatSpinEdit = class(TWinControl)
private
fClimbRate: Single;
fDecimals: Integer;
fLastValueOnChange: single;
FIncrement: single;
FDecimals: integer;
FMaxValue: single;
FMinValue: single;
FModified: boolean;
FOnChange: TNotifyEvent;
FSelLength: integer;
FSelStart: integer;
fValue: Single;
FValue: Single;
FValueEmpty: boolean;
fValueNeedsUpdate: boolean;
function ClimbRateIsStored: boolean;
FUpdatePending: boolean;
FValueChanged: boolean;
function GetModified: Boolean;
function GetSelLength: integer;
function GetSelStart: integer;
@ -70,7 +69,7 @@ type
procedure SetDecimals(Num: Integer);
function GetValue: Single;
procedure SetValue(const Num: Single);
procedure SetClimbRate(const Num: Single);
procedure SetIncrement(const NewIncrement: single);
procedure InitializeWnd; override;
procedure FinalizeWnd; override;
procedure Loaded; override;
@ -91,7 +90,7 @@ type
property Text;
public
property DecimalPlaces: Integer read FDecimals write SetDecimals default 2;
property ClimbRate: Single read FClimbRate write SetClimbRate default 1;
property Increment: Single read FIncrement write SetIncrement default 1;
property MinValue: single read FMinValue write SetMinValue default 0;
property MaxValue: single read FMaxValue write SetMaxValue default 100;
property TabStop default true;
@ -109,6 +108,7 @@ type
property Constraints;
property DecimalPlaces;
property Enabled;
property Increment;
property MaxValue;
property MinValue;
property OnChange;
@ -137,21 +137,21 @@ type
TCustomSpinEdit = class(TCustomFloatSpinEdit)
private
function GetClimbRate: integer;
function GetIncrement: integer;
function GetMaxValue: integer;
function GetMinValue: integer;
function GetValue: integer;
procedure SetClimbRate(const AValue: integer);
procedure SetIncrement(const AValue: integer);
procedure SetMaxValue(const AValue: integer);
procedure SetMinValue(const AValue: integer);
procedure SetValue(const AValue: integer);
public
constructor Create(TheOwner: TComponent); override;
public
property Value: integer read GetValue write SetValue;
property MinValue: integer read GetMinValue write SetMinValue;
property MaxValue: integer read GetMaxValue write SetMaxValue;
property ClimbRate: integer read GetClimbRate write SetClimbRate;
property Value: integer read GetValue write SetValue default 0;
property MinValue: integer read GetMinValue write SetMinValue default 0;
property MaxValue: integer read GetMaxValue write SetMaxValue default 100;
property Increment: integer read GetIncrement write SetIncrement default 1;
end;
@ -162,9 +162,10 @@ type
property Align;
property Anchors;
property BorderSpacing;
property ClimbRate;
property ClimbRate: integer write SetIncrement stored false; // TODO: remove, deprecated
property Constraints;
property Enabled;
property Increment;
property MaxValue;
property MinValue;
property OnChange;