Rxdbcomb.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:17k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1997 Master-Bank                }
  6. {                                                       }
  7. {*******************************************************}
  8. unit RxDBComb;
  9. {$I RX.INC}
  10. interface
  11. uses Windows, DbCtrls, VDBConsts,
  12.   Messages, Menus, Graphics, Classes, Controls, DB, 
  13.   {$IFNDEF RX_D3} DBTables, {$ENDIF} StdCtrls, DBConsts;
  14. type
  15. { TCustomDBComboBox }
  16.   TCustomDBComboBox = class(TCustomComboBox)
  17.   private
  18.     FDataLink: TFieldDataLink;
  19. {$IFDEF WIN32}
  20.     FPaintControl: TPaintControl;
  21. {$ENDIF}
  22.     procedure DataChange(Sender: TObject);
  23.     procedure EditingChange(Sender: TObject);
  24.     function GetDataField: string;
  25.     function GetDataSource: TDataSource;
  26.     function GetField: TField;
  27.     function GetReadOnly: Boolean;
  28.     procedure SetDataField(const Value: string);
  29.     procedure SetDataSource(Value: TDataSource);
  30.     procedure SetEditReadOnly;
  31.     procedure SetItems(Value: TStrings);
  32.     procedure SetReadOnly(Value: Boolean);
  33.     procedure UpdateData(Sender: TObject);
  34.     function GetComboText: string; virtual;
  35.     procedure SetComboText(const Value: string); virtual;
  36.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  37. {$IFDEF WIN32}
  38.     procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
  39.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  40. {$ELSE}
  41.     function GetStyle: TComboBoxStyle;
  42. {$ENDIF}
  43.   protected
  44.     procedure Change; override;
  45.     procedure Click; override;
  46.     procedure ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
  47.       ComboProc: Pointer); override;
  48.     procedure CreateWnd; override;
  49.     procedure DropDown; override;
  50.     function GetPaintText: string; virtual;
  51.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  52.     procedure KeyPress(var Key: Char); override;
  53.     procedure Loaded; override;
  54.     procedure Notification(AComponent: TComponent;
  55.       Operation: TOperation); override;
  56.     procedure SetStyle(Value: TComboBoxStyle); {$IFDEF WIN32} override {$ELSE} virtual {$ENDIF};
  57.     procedure WndProc(var Message: TMessage); override;
  58.     property ComboText: string read GetComboText write SetComboText;
  59. {$IFNDEF WIN32}
  60.     property Style: TComboBoxStyle read GetStyle write SetStyle default csDropDown;
  61. {$ENDIF WIN32}
  62.     property DataField: string read GetDataField write SetDataField;
  63.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  64.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
  65.   public
  66.     constructor Create(AOwner: TComponent); override;
  67.     destructor Destroy; override;
  68. {$IFDEF RX_D4}
  69.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  70.     function UpdateAction(Action: TBasicAction): Boolean; override;
  71.     function UseRightToLeftAlignment: Boolean; override;
  72. {$ENDIF}
  73.     property Field: TField read GetField;
  74.     property Items write SetItems;
  75.     property Text;
  76.   end;
  77. { TRxDBComboBox }
  78.   TRxDBComboBox = class(TCustomDBComboBox)
  79.   private
  80.     FValues: TStrings;
  81.     FEnableValues: Boolean;
  82.     procedure SetEnableValues(Value: Boolean);
  83.     procedure SetValues(Value: TStrings);
  84.     procedure ValuesChanged(Sender: TObject);
  85.   protected
  86.     procedure SetStyle(Value: TComboBoxStyle); override;
  87.     function GetComboText: string; override;
  88.     function GetPaintText: string; override;
  89.     procedure SetComboText(const Value: string); override;
  90.   public
  91.     constructor Create(AOwner: TComponent); override;
  92.     destructor Destroy; override;
  93.   published
  94.     property Style; { must be published before Items }
  95.     property Color;
  96.     property Ctl3D;
  97.     property DataField;
  98.     property DataSource;
  99.     property DragMode;
  100.     property DragCursor;
  101.     property DropDownCount;
  102.     property Enabled;
  103.     property EnableValues: Boolean read FEnableValues write SetEnableValues;
  104.     property Font;
  105. {$IFDEF RX_D4}
  106.     property Anchors;
  107.     property BiDiMode;
  108.     property Constraints;
  109.     property DragKind;
  110.     property ParentBiDiMode;
  111. {$ENDIF}
  112. {$IFDEF WIN32}
  113.   {$IFNDEF VER90}
  114.     property ImeMode;
  115.     property ImeName;
  116.   {$ENDIF}
  117. {$ENDIF}
  118.     property ItemHeight;
  119.     property Items;
  120.     property ParentColor;
  121.     property ParentCtl3D;
  122.     property ParentFont;
  123.     property ParentShowHint;
  124.     property PopupMenu;
  125.     property ReadOnly;
  126.     property ShowHint;
  127.     property Sorted;
  128.     property TabOrder;
  129.     property TabStop;
  130.     property Values: TStrings read FValues write SetValues;
  131.     property Visible;
  132.     property OnChange;
  133.     property OnClick;
  134.     property OnDblClick;
  135.     property OnDragDrop;
  136.     property OnDragOver;
  137.     property OnDrawItem;
  138.     property OnDropDown;
  139.     property OnEndDrag;
  140.     property OnEnter;
  141.     property OnExit;
  142.     property OnKeyDown;
  143.     property OnKeyPress;
  144.     property OnKeyUp;
  145.     property OnMeasureItem;
  146. {$IFDEF WIN32}
  147.     property OnStartDrag;
  148. {$ENDIF}
  149. {$IFDEF RX_D5}
  150.     property OnContextPopup;
  151. {$ENDIF}
  152. {$IFDEF RX_D4}
  153.     property OnEndDock;
  154.     property OnStartDock;
  155. {$ENDIF}
  156.   end;
  157. implementation
  158. uses DBUtils;
  159. { TCustomDBComboBox }
  160. constructor TCustomDBComboBox.Create(AOwner: TComponent);
  161. begin
  162.   inherited Create(AOwner);
  163. {$IFDEF WIN32}
  164.   ControlStyle := ControlStyle + [csReplicatable];
  165. {$ENDIF}
  166.   FDataLink := TFieldDataLink.Create;
  167.   FDataLink.Control := Self;
  168.   FDataLink.OnDataChange := DataChange;
  169.   FDataLink.OnUpdateData := UpdateData;
  170.   FDataLink.OnEditingChange := EditingChange;
  171. {$IFDEF WIN32}
  172.   FPaintControl := TPaintControl.Create(Self, 'COMBOBOX');
  173. {$ENDIF}
  174. end;
  175. destructor TCustomDBComboBox.Destroy;
  176. begin
  177. {$IFDEF WIN32}
  178.   FPaintControl.Free;
  179. {$ENDIF}
  180.   FDataLink.OnDataChange := nil;
  181.   FDataLink.OnUpdateData := nil;
  182.   FDataLink.Free;
  183.   FDataLink := nil;
  184.   inherited Destroy;
  185. end;
  186. procedure TCustomDBComboBox.Loaded;
  187. begin
  188.   inherited Loaded;
  189.   if (csDesigning in ComponentState) then DataChange(Self);
  190. end;
  191. procedure TCustomDBComboBox.Notification(AComponent: TComponent;
  192.   Operation: TOperation);
  193. begin
  194.   inherited Notification(AComponent, Operation);
  195.   if (Operation = opRemove) and (FDataLink <> nil) and
  196.     (AComponent = DataSource) then DataSource := nil;
  197. end;
  198. procedure TCustomDBComboBox.CreateWnd;
  199. begin
  200.   inherited CreateWnd;
  201.   SetEditReadOnly;
  202. end;
  203. procedure TCustomDBComboBox.DataChange(Sender: TObject);
  204. begin
  205.   if DroppedDown then Exit;
  206.   if FDataLink.Field <> nil then ComboText := FDataLink.Field.Text
  207.   else if csDesigning in ComponentState then ComboText := Name
  208.   else ComboText := '';
  209. end;
  210. procedure TCustomDBComboBox.UpdateData(Sender: TObject);
  211. begin
  212.   FDataLink.Field.Text := ComboText;
  213. end;
  214. procedure TCustomDBComboBox.SetComboText(const Value: string);
  215. var
  216.   I: Integer;
  217.   Redraw: Boolean;
  218. begin
  219.   if Value <> ComboText then begin
  220.     if Style <> csDropDown then begin
  221.       Redraw := (Style <> csSimple) and HandleAllocated;
  222.       if Redraw then SendMessage(Handle, WM_SETREDRAW, 0, 0);
  223.       try
  224.         if Value = '' then I := -1 else I := Items.IndexOf(Value);
  225.         ItemIndex := I;
  226.       finally
  227.         if Redraw then begin
  228.           SendMessage(Handle, WM_SETREDRAW, 1, 0);
  229.           Invalidate;
  230.         end;
  231.       end;
  232.       if I >= 0 then Exit;
  233.     end;
  234.     if Style in [csDropDown, csSimple] then Text := Value;
  235.   end;
  236. end;
  237. function TCustomDBComboBox.GetComboText: string;
  238. var
  239.   I: Integer;
  240. begin
  241.   if Style in [csDropDown, csSimple] then Result := Text
  242.   else begin
  243.     I := ItemIndex;
  244.     if I < 0 then Result := '' else Result := Items[I];
  245.   end;
  246. end;
  247. procedure TCustomDBComboBox.Change;
  248. begin
  249.   FDataLink.Edit;
  250.   inherited Change;
  251.   FDataLink.Modified;
  252. end;
  253. procedure TCustomDBComboBox.Click;
  254. begin
  255.   FDataLink.Edit;
  256.   inherited Click;
  257.   FDataLink.Modified;
  258. end;
  259. procedure TCustomDBComboBox.DropDown;
  260. begin
  261. {$IFNDEF WIN32}
  262.   FDataLink.Edit;
  263. {$ENDIF}
  264.   inherited DropDown;
  265. end;
  266. function TCustomDBComboBox.GetDataSource: TDataSource;
  267. begin
  268.   Result := FDataLink.DataSource;
  269. end;
  270. procedure TCustomDBComboBox.SetDataSource(Value: TDataSource);
  271. begin
  272. {$IFDEF RX_D4}
  273.   if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
  274. {$ENDIF}
  275.     FDataLink.DataSource := Value;
  276. {$IFDEF WIN32}
  277.   if Value <> nil then Value.FreeNotification(Self);
  278. {$ENDIF}
  279. end;
  280. function TCustomDBComboBox.GetDataField: string;
  281. begin
  282.   Result := FDataLink.FieldName;
  283. end;
  284. procedure TCustomDBComboBox.SetDataField(const Value: string);
  285. begin
  286.   FDataLink.FieldName := Value;
  287. end;
  288. function TCustomDBComboBox.GetReadOnly: Boolean;
  289. begin
  290.   Result := FDataLink.ReadOnly;
  291. end;
  292. procedure TCustomDBComboBox.SetReadOnly(Value: Boolean);
  293. begin
  294.   FDataLink.ReadOnly := Value;
  295. end;
  296. function TCustomDBComboBox.GetField: TField;
  297. begin
  298.   Result := FDataLink.Field;
  299. end;
  300. procedure TCustomDBComboBox.KeyDown(var Key: Word; Shift: TShiftState);
  301. begin
  302.   inherited KeyDown(Key, Shift);
  303.   if Key in [VK_BACK, VK_DELETE, VK_UP, VK_DOWN, 32..255] then begin
  304.     if not FDataLink.Edit and (Key in [VK_UP, VK_DOWN]) then
  305.       Key := 0;
  306.   end;
  307. end;
  308. procedure TCustomDBComboBox.KeyPress(var Key: Char);
  309. begin
  310.   inherited KeyPress(Key);
  311.   if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
  312.     not FDataLink.Field.IsValidChar(Key) then
  313.   begin
  314.     MessageBeep(0);
  315.     Key := #0;
  316.   end;
  317.   case Key of
  318.     ^H, ^V, ^X, #32..#255:
  319.       FDataLink.Edit;
  320.     #27:
  321.       begin
  322.         FDataLink.Reset;
  323.         SelectAll;
  324. {$IFNDEF WIN32}
  325.         Key := #0;
  326. {$ENDIF}
  327.       end;
  328.   end;
  329. end;
  330. procedure TCustomDBComboBox.EditingChange(Sender: TObject);
  331. begin
  332.   SetEditReadOnly;
  333. end;
  334. procedure TCustomDBComboBox.SetEditReadOnly;
  335. begin
  336.   if (Style in [csDropDown, csSimple]) and HandleAllocated then
  337.     SendMessage({$IFDEF WIN32} EditHandle {$ELSE} FEditHandle {$ENDIF},
  338.       EM_SETREADONLY, Ord(not FDataLink.Editing), 0);
  339. end;
  340. procedure TCustomDBComboBox.WndProc(var Message: TMessage);
  341. begin
  342.   if not (csDesigning in ComponentState) then
  343.     case Message.Msg of
  344.       WM_COMMAND:
  345.         if TWMCommand(Message).NotifyCode = CBN_SELCHANGE then
  346.           if not FDataLink.Edit then begin
  347.             if Style <> csSimple then
  348.               PostMessage(Handle, CB_SHOWDROPDOWN, 0, 0);
  349.             Exit;
  350.           end;
  351.       CB_SHOWDROPDOWN:
  352.         if Message.WParam <> 0 then FDataLink.Edit
  353.         else if not FDataLink.Editing then DataChange(Self); {Restore text}
  354. {$IFDEF WIN32}
  355.       WM_CREATE,
  356.       WM_WINDOWPOSCHANGED,
  357.       CM_FONTCHANGED:
  358.         FPaintControl.DestroyHandle;
  359. {$ENDIF}
  360.     end;
  361.   inherited WndProc(Message);
  362. end;
  363. procedure TCustomDBComboBox.ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
  364.   ComboProc: Pointer);
  365. begin
  366.   if not (csDesigning in ComponentState) then
  367.     case Message.Msg of
  368.       WM_LBUTTONDOWN:
  369. {$IFDEF WIN32}
  370.         if (Style = csSimple) and (ComboWnd <> EditHandle) then
  371. {$ELSE}
  372.         if (Style = csSimple) and (ComboWnd <> FEditHandle) then
  373. {$ENDIF}
  374.           if not FDataLink.Edit then Exit;
  375.     end;
  376.   inherited ComboWndProc(Message, ComboWnd, ComboProc);
  377. end;
  378. procedure TCustomDBComboBox.CMExit(var Message: TCMExit);
  379. begin
  380.   try
  381.     FDataLink.UpdateRecord;
  382.   except
  383.     SelectAll;
  384.     if CanFocus then SetFocus;
  385.     raise;
  386.   end;
  387.   inherited;
  388. end;
  389. {$IFDEF WIN32}
  390. procedure TCustomDBComboBox.CMGetDatalink(var Message: TMessage);
  391. begin
  392.   Message.Result := Longint(FDataLink);
  393. end;
  394. procedure TCustomDBComboBox.WMPaint(var Message: TWMPaint);
  395. var
  396.   S: string;
  397.   R: TRect;
  398.   P: TPoint;
  399.   Child: HWND;
  400. begin
  401.   if csPaintCopy in ControlState then begin
  402.     S := GetPaintText;
  403.     if Style = csDropDown then begin
  404.       SendMessage(FPaintControl.Handle, WM_SETTEXT, 0, Longint(PChar(S)));
  405.       SendMessage(FPaintControl.Handle, WM_PAINT, Message.DC, 0);
  406.       Child := GetWindow(FPaintControl.Handle, GW_CHILD);
  407.       if Child <> 0 then begin
  408.         Windows.GetClientRect(Child, R);
  409.         Windows.MapWindowPoints(Child, FPaintControl.Handle, R.TopLeft, 2);
  410.         GetWindowOrgEx(Message.DC, P);
  411.         SetWindowOrgEx(Message.DC, P.X - R.Left, P.Y - R.Top, nil);
  412.         IntersectClipRect(Message.DC, 0, 0, R.Right - R.Left, R.Bottom - R.Top);
  413.         SendMessage(Child, WM_PAINT, Message.DC, 0);
  414.       end;
  415.     end
  416.     else begin
  417.       SendMessage(FPaintControl.Handle, CB_RESETCONTENT, 0, 0);
  418.       if Items.IndexOf(S) <> -1 then begin
  419.         SendMessage(FPaintControl.Handle, CB_ADDSTRING, 0, Longint(PChar(S)));
  420.         SendMessage(FPaintControl.Handle, CB_SETCURSEL, 0, 0);
  421.       end;
  422.       SendMessage(FPaintControl.Handle, WM_PAINT, Message.DC, 0);
  423.     end;
  424.   end
  425.   else inherited;
  426. end;
  427. {$ENDIF}
  428. function TCustomDBComboBox.GetPaintText: string;
  429. begin
  430.   if FDataLink.Field <> nil then Result := FDataLink.Field.Text
  431.   else Result := '';
  432. end;
  433. procedure TCustomDBComboBox.SetItems(Value: TStrings);
  434. begin
  435.   Items.Assign(Value);
  436.   DataChange(Self);
  437. end;
  438. {$IFNDEF WIN32}
  439. function TCustomDBComboBox.GetStyle: TComboBoxStyle;
  440. begin
  441.   Result := inherited Style;
  442. end;
  443. {$ENDIF}
  444. procedure TCustomDBComboBox.SetStyle(Value: TComboBoxStyle);
  445. begin
  446. {$IFDEF WIN32}
  447.   if (Value = csSimple) and Assigned(FDatalink) and FDatalink.DatasourceFixed then
  448.     _DBError(SNotReplicatable);
  449.   inherited SetStyle(Value);
  450. {$ELSE}
  451.   if Value = csSimple then ControlStyle := ControlStyle - [csFixedHeight]
  452.   else ControlStyle := ControlStyle + [csFixedHeight];
  453.   inherited Style := Value;
  454.   RecreateWnd;
  455. {$ENDIF}
  456. end;
  457. {$IFDEF RX_D4}
  458. function TCustomDBComboBox.UseRightToLeftAlignment: Boolean;
  459. begin
  460.   Result := DBUseRightToLeftAlignment(Self, Field);
  461. end;
  462. function TCustomDBComboBox.ExecuteAction(Action: TBasicAction): Boolean;
  463. begin
  464.   Result := inherited ExecuteAction(Action) or (FDataLink <> nil) and
  465.     FDataLink.ExecuteAction(Action);
  466. end;
  467. function TCustomDBComboBox.UpdateAction(Action: TBasicAction): Boolean;
  468. begin
  469.   Result := inherited UpdateAction(Action) or (FDataLink <> nil) and
  470.     FDataLink.UpdateAction(Action);
  471. end;
  472. {$ENDIF}
  473. { TRxDBComboBox }
  474. constructor TRxDBComboBox.Create(AOwner: TComponent);
  475. begin
  476.   inherited Create(AOwner);
  477.   FValues := TStringList.Create;
  478.   TStringList(FValues).OnChange := ValuesChanged;
  479.   EnableValues := False;
  480. end;
  481. destructor TRxDBComboBox.Destroy;
  482. begin
  483.   TStringList(FValues).OnChange := nil;
  484.   FValues.Free;
  485.   inherited Destroy;
  486. end;
  487. procedure TRxDBComboBox.ValuesChanged(Sender: TObject);
  488. begin
  489.   if FEnableValues then DataChange(Self);
  490. end;
  491. function TRxDBComboBox.GetPaintText: string;
  492. var
  493.   I: Integer;
  494. begin
  495.   Result := '';
  496.   if FDataLink.Field <> nil then begin
  497.     if FEnableValues then begin
  498.       I := Values.IndexOf(FDataLink.Field.Text);
  499.       if I >= 0 then Result := Items.Strings[I]
  500.     end
  501.     else Result := FDataLink.Field.Text;
  502.   end;
  503. end;
  504. function TRxDBComboBox.GetComboText: string;
  505. var
  506.   I: Integer;
  507. begin
  508.   if (Style in [csDropDown, csSimple]) and (not FEnableValues) then
  509.     Result := Text
  510.   else begin
  511.     I := ItemIndex;
  512.     if (I < 0) or (FEnableValues and (FValues.Count < I + 1)) then
  513.       Result := ''
  514.     else
  515.       if FEnableValues then Result := FValues[I]
  516.       else Result := Items[I];
  517.   end;
  518. end;
  519. procedure TRxDBComboBox.SetComboText(const Value: string);
  520. var
  521.   I: Integer;
  522.   Redraw: Boolean;
  523. begin
  524.   if Value <> ComboText then begin
  525.     if Style <> csDropDown then begin
  526.       Redraw := (Style <> csSimple) and HandleAllocated;
  527.       if Redraw then SendMessage(Handle, WM_SETREDRAW, 0, 0);
  528.       try
  529.         if Value = '' then I := -1 else
  530.           if FEnableValues then I := Values.IndexOf(Value)
  531.           else I := Items.IndexOf(Value);
  532.         if I >= Items.Count then I := -1;
  533.         ItemIndex := I;
  534.       finally
  535.         if Redraw then begin
  536.           SendMessage(Handle, WM_SETREDRAW, 1, 0);
  537.           Invalidate;
  538.         end;
  539.       end;
  540.       if I >= 0 then Exit;
  541.     end;
  542.     if Style in [csDropDown, csSimple] then Text := Value;
  543.   end;
  544. end;
  545. procedure TRxDBComboBox.SetEnableValues(Value: Boolean);
  546. begin
  547.   if FEnableValues <> Value then begin
  548.     if Value and (Style in [csDropDown, csSimple]) then
  549.       Style := csDropDownList;
  550.     FEnableValues := Value;
  551.     DataChange(Self);
  552.   end;
  553. end;
  554. procedure TRxDBComboBox.SetValues(Value: TStrings);
  555. begin
  556.   FValues.Assign(Value);
  557. end;
  558. procedure TRxDBComboBox.SetStyle(Value: TComboboxStyle);
  559. begin
  560.   if (Value in [csSimple, csDropDown]) and FEnableValues then
  561.     Value := csDropDownList;
  562.   inherited SetStyle(Value);
  563. end;
  564. end.