Add DBLookupCombobox to Delphi DBGrid - delphi

I'd like to add DBLookupComboboxes to certain columns in a DBGrid. There is a nice article on About.com on how to do this here. The problem is that with a table having many columns, if you select from the DBLookupCombobox in one column and then try to scroll left, the combobox will move left too as shown in the included images. How can the About.com code can be changed to prevent this behavior? A web search showed two others complaining of the exact same problem with no solution. Note that I want to use a DBLookupCombobox to show a name but enter the id, so using a simple picklist will not do.
procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
if DBGrid1.SelectedField.FieldName = DBLookupComboBox1.DataField then
DBLookupComboBox1.Visible := False
end;
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
if (gdFocused in State) then
begin
if (Column.Field.FieldName = DBLookupComboBox1.DataField) then
with DBLookupComboBox1 do
begin
Left := Rect.Left + DBGrid1.Left + 2;
Top := Rect.Top + DBGrid1.Top + 2;
Width := Rect.Right - Rect.Left;
Width := Rect.Right - Rect.Left;
Height := Rect.Bottom - Rect.Top;
Visible := True;
end;
end
end;
procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
if (key = Chr(9)) then Exit;
if (DBGrid1.SelectedField.FieldName = DBLookupComboBox1.DataField) then
begin
DBLookupComboBox1.SetFocus;
SendMessage(DBLookupComboBox1.Handle, WM_Char, word(Key), 0);
end
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
with DBLookupComboBox1 do
begin
DataSource := DataSource1; // -> AdoTable1 -> DBGrid1
ListSource := DataSource2;
DataField := 'resource_id'; // from AdoTable1 - displayed in the DBGrid
KeyField := 'id';
ListField := 'resource_name; id';
Visible := False;
end;
DataSource2.DataSet := AdoQuery1;
AdoQuery1.Connection := AdoConnection1;
AdoQuery1.SQL.Text := 'SELECT id,resource_name FROM resources';
AdoQuery1.Open;
end;

Here is one solution using a neat hack from François.
type
// Hack to redeclare your TDBGrid here without the the form designer going mad
TDBGrid = class(DBGrids.TDBGrid)
procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL;
end;
TForm1 = class(TForm)
[...]
procedure TDBGrid.WMHScroll(var Msg: TWMHScroll);
begin
if Form1.DBGrid1.SelectedField.FieldName = Form1.DBLookupComboBox1.DataField then begin
case Msg.ScrollCode of
SB_LEFT,SB_LINELEFT,SB_PAGELEFT: begin
Form1.DBGrid1.SelectedIndex := Form1.DBGrid1.SelectedIndex-1;
Form1.DBLookupComboBox1.Visible := False;
end;
SB_RIGHT,SB_LINERIGHT,SB_PAGERIGHT: begin
Form1.DBGrid1.SelectedIndex := Form1.DBGrid1.SelectedIndex+1;
Form1.DBLookupComboBox1.Visible := False;
end;
end;
end;
inherited; // to keep the expected behavior
end;

Related

How to emphasize some specific items from cxDBchecklistbox

I have dataset with 2 different sources - some are for goverment and others are for organization only. I need to distinct them somehow, like making some items bold or different color.
I tried to use DrawItem event, but couldn't figure it out.
For adding items I used:
while not (cdDataset1.Eof) do
begin
if ((cdDataset1.fieldbyName('displayName').value<> '') and (cdDataset1.fieldbyName('TyypId').value=1280781)) then
begin
cxDBCheckListBox1.Items.Add.Text:= cdDataset1.fieldbyName('displayName').value;
end;
cdDataset1.Next;
end;
cdDataset1.First;
while not (cdDataset1.Eof) do
begin
if ((cdDataset1.fieldbyName('displayName').value<> '') and (cdDataset1.fieldbyName('TyypId').value=1243501)) then
begin
cxDBCheckListBox1.Items.Add.Text:= cdDataset1.fieldbyName('displayName').value;
end;
cdDataset1.Next;
end;
This part works well. But can I use field TyypID for distinction on cxdbchecklistbox ?
It should look like this(checkboxs intead of bullets ofcourse):
Important option1
Impotant option2
extra info option1
I found the solution. First add tags . OnDrawItem creating canvas is needed:
//adding items to checklistbox where needed.
cxDBCheckListBox1.Items.Clear;
while not (cdDataset1.Eof) do
begin
if ((cdDataset1.fieldbyName('displayName').value<> '') and
(cdDataset1.fieldbyName('TyypId').value=28078)) then
begin
with cxDBCheckListBox1.Items.Add do
begin
Text:= cdDataset1.fieldbyName('displayName').value;
Tag := 1280781;
end;
end;
cdDataset1.Next;
end;
//Then on drawitem:
procedure TfmSample.cxDBCheckListBox1DrawItem(
Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
ACanvas: TcxCanvas;
AText: string;
ATextRect: TRect;
AGlyphWidth: Integer;
AListBox: TcxDBCheckListBox;
ACanvasFont: TFont;
AItemEnabled: Boolean;
AItemTag: Integer;
begin
AListBox := (Control as TcxDBCheckListBox);
ACanvas := AListBox.InnerCheckListBox.Canvas;
ACanvasFont := ACanvas.Font;
AItemTag := AListBox.Items[Index].Tag;
AItemEnabled := AListBox.Items[Index].Enabled;
case AItemTag of
1243501:
begin
ACanvasFont.Color := clBlue;
end;
1280781 :
begin
ACanvasFont.Style := [fsBold];
ACanvasFont.Color := clBlack;
end;
end;
ACanvas.Brush.Color := clWhite;
ACanvas.FillRect(Rect);
AText := AListBox.Items[Index].Text;
ATextRect := Rect;
ATextRect.Left := 20;
ACanvas.DrawTexT(AText, ATextRect, 0);
end;

DBGRID with Row Height variable

I would like to show in a DBGRID as follows:
Imagine "Grid" as follows:
ID - DESCRIPTION
1 - Line 1 of the grid
2 - Line 2 of the grid
3 - Line 3 of the grid
Now, suppose the size of the DESCRIPTION column is changed and no longer appear the words "GRID";
I would like to stay as well DBGRID
ID - DESCRIPTION
1 - Line 1 of the
grid
2 - Line 2 of the
grid
3 - Line 3 of the
grid
is there any possibility that ??
Not what you're asking, but might help... I once used this code to show complete Memo fields in the standard DBGrid:
TMyForm = class(TForm)
...
private
FormMemoRect: TRect;
MemoGrid: TDBGrid;
BMemo: TBitBtn;
...
Procedure TMyForm.FormMemoDeactivate(Sender: TObject);
Begin
(Sender As TForm).Close;
Sender.Free;
End;
Procedure TMyForm.BMemoClick(Sender: TObject);
Var FormMemo: TForm;
Begin
MemoGrid.SetFocus;
FormMemo := TForm.Create(Self);
With TMemo.Create(FormMemo) Do Begin
Parent := FormMemo;
Align := alClient;
ReadOnly := True;
WordWrap := True;
ScrollBars := ssVertical;
Lines.Text := MemoGrid.DataSource.DataSet.Fields[TComponent(Sender).Tag].AsString;
End;
With FormMemo Do Begin
OnDeactivate := FormMemoDeactivate;
Left := FormMemoRect.Left;
Top := FormMemoRect.Top;
Width := Max(FormMemoRect.Right - FormMemoRect.Left, 300);
Height := FormMemoRect.Bottom - FormMemoRect.Top;
BorderStyle := bsNone;
Show;
End;
End;
Procedure TMyForm.GrdMemoDrawColumnCell(Sender: TObject; Const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
Begin
If (gdFocused In State) Then Begin
If Column.Field.DataType In [ftBlob, ftMemo] Then Begin
{Desenha botão para visualização do Memo}
FormMemoRect.Left := TWinControl(Sender).ClientToScreen(Rect.TopLeft).X;
FormMemoRect.Right := TWinControl(Sender).ClientToScreen(Rect.BottomRight).X;
FormMemoRect.Top := TWinControl(Sender).ClientToScreen(Rect.BottomRight).Y;
FormMemoRect.Bottom := FormMemoRect.Top + 100;
If Not Assigned(BMemo) Then
BMemo := TBitBtn.Create(Self);
BMemo.Parent := TWinControl(Sender).Parent;
BMemo.Width := 16;
BMemo.Height := 16;
BMemo.Caption := '...';
BMemo.OnClick := BMemoClick;
BMemo.Tag := Column.Field.Index;
BMemo.Left := TWinControl(Sender).Left + Rect.Right - BMemo.Width + 1;
BMemo.Top := TWinControl(Sender).Top + Rect.Top + 2;
MemoGrid := TDBGrid(Sender);
End
Else
FreeAndNil(BMemo);
End;
End;
For Blob/Memo Fields, you may also find it useful to do some custom GetText to show something directly in the Grid:
Procedure TMyForm.DataSetMemoGetText(Sender: TField; var Text: String; DisplayText: Boolean);
Begin
Text := Copy(Sender.AsString, 1, 50);
If Text <> Sender.AsString Then
Text := Text + '...';
End;
This is how the result looks like.
PS: Sorry for non-standard code style.

Delphi XE6 firemonkey component alignment problems when added at runtime

i wanto dynamic add 5 TLable in my iOS app.
like this
Procedure Form1.FormCreate(Sender: TObject)
var
I: Integer;
begin
for I := 1 to 5 do
begin
with TLabel.Create(Self) do
begin
Parent := self;
Align := TAlignLayout.Top;
Height := 50;
Text := IntToStr(I);
end;
end;
end;
i think the order is 12345, but I get 15432.
What can I do to get the desired results?
You must give a chance to the aligning algorithm to do what you want.
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
for I := 1 to 5 do
begin
with TLabel.Create(Self) do
begin
Parent := self;
Align := TAlignLayout.alTop;
Height := 50;
Position.Y := I*Height; //add this line
Text := IntToStr(I);
end;
end;
end;

Display Password Char for editable TField in DBGrid

I have a DBGrid where I am using following query to get the data:
Select * from table1 where <condition>
One of the fields in Password coming from database, which I want to display as ***. But keep it editable for the Grid itself.
Can you please suggest what can be done for this. Sample code will be much appreciated
You can do this by dropping a TEdit on your form and set the password char property to be '*'. Then you need to add code into the OnDrawColumnCell event of the TDBGrid like this :-
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
grid : TDBGrid;
maskValue : String;
aRect : TRect;
begin
maskValue := '**';
aRect := Rect;
grid := sender as TDBGrid;
if column.FieldName = 'password' then
if gdfocused in State then
begin
Edit1.Left := Rect.Left + grid.Left + 1;
Edit1.Top := rect.Top + grid.Top + 1;
Edit1.Width := Rect.Right - Rect.Left + 2;
Edit1.Height := Rect.Bottom - Rect.Top + 2;
Edit1.Clear;
Edit1.Visible := True;
end
else
begin
grid.Canvas.FillRect(Rect);
DrawText(grid.Canvas.Handle, PChar(maskValue), Length(maskValue), aRect,
DT_SINGLELINE or DT_LEFT or DT_VCENTER);
end
else
grid.DefaultDrawColumnCell(Rect, DataCol, Column, state);
end;
procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
Edit1.Visible := False;
end;
procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = Chr(9) then Exit;
if (Sender as TDBGrid).SelectedField.FieldName = 'password' then
begin
Edit1.SetFocus;
SendMessage(Edit1.Handle, WM_CHAR, word(Key), 0);
end;
end;
procedure TForm1.Edit1Change(Sender: TObject);
begin
if DBGrid1.DataSource.State in [dsEdit, dsInsert] then
DBGrid1.DataSource.DataSet.FieldByName('password').AsString := Edit1.Text;
end;
procedure TForm1.Edit1Enter(Sender: TObject);
begin
DBGrid1.DataSource.Edit;
end;
This should get you going, but as has been mentioned it's not ideal to be editing passwords in this way.

Delphi - issue with drawing over a TDBGrid descendant

I've wrote a TDBGrid descendant component which is displaying the content of different blob fields for the current row selected, each one in a TJvDBRichEdit. The DrawColumnCell code for displaying the content of the blob fields:
procedure TMyDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var iPos,iNr,iTop:Integer;
begin
// RBA 01/04/2013 12:10
if not (csDesigning in ComponentState) then
if FDisplayBlobAsRTF then //property to show the blob fields or not
begin
if (gdSelected in State) then
begin
if Column.Field.isblob then
begin
ipos := 0;
iNr := 0;
while (iPos <= Column.Field.DataSet.FieldCount-1)and(Column.Field.DataSet.Fields[ipos].FieldName <> Column.Field.FieldName ) do
begin
if Column.Field.DataSet.Fields[ipos].IsBlob then
inc(iNr);
inc(iPos);
end;
with TJvDBRichEdit(FRichEditList[inr]) do//FRichEditList - TObjectList which contains all the TJvDBRichEdit components, and release them on destroy
begin
Left := Rect.Left + Self.Left + 1;
iTop := Rect.Top + Self.Top + 1;
if iTop + Height > Self.Height then
iTop := iTop - Height;
Top := iTop;
Width := Rect.BottomRight.X - Rect.left;
Visible := true;
end;
end;
end
end;
inherited;
end;
overrided LayoutChanged routine
procedure TMyDBGrid.LayoutChanged;
var iPos : Integer;
dtDataset : TDataSet;
jvDbRichEdit : TJvDBRichEdit;
begin
if not (csDesigning in ComponentState) then
if FDisplayBlobAsRTF then
begin
dtDataset := GetDataset;//get the dataset assigned to the grid
if dtDataset <> nil then
if dtDataset.State <> dsInactive then
begin
FRichEditList.Clear;
for iPos := 0 to dtDataset.FieldCount-1 do
if dtDataset.Fields[iPos].IsBlob then
begin
jvDbRichEdit := TJvDBRichEdit.Create(nil);
jvDbRichEdit.Parent := Self;
jvDbRichEdit.DataSource := Self.DataSource;
jvDbRichEdit.DataField := dtDataset.Fields[iPos].FieldName;
jvDbRichEdit.Visible := false;
FRichEditList.Add(jvDbRichEdit);
end;
end;
end;
end;
the problem appears when I make a scroll on the last displayed grid row :
How can I redraw the grid behind? I've tried with repainting the hole grid, but it is flickering.
LE: this is not intended to modify the content in the richedtis, only to display them.

Resources