Custom dbgrid and Picklist issue - delphi

I'm creating my own DBGRid, and it works fine , except of the pick list. whatever button style is set for the grid, it always shows the inplace editor , neither the pick list nor the ellipse button !
i can not figure the mistake I'm doing :( . here is the relevant code :
function TMyDBGrid.CreateEditor: TInplaceEdit;
begin
result:=TInplaceEdit.Create(self);
end;
function TMyDBGrid.GetEditStyle(ACol, ARow: integer): TEditStyle;
begin
case Columns[ACol].ButtonStyle of
cbsAuto : Result:=esPickList;
cbsNone : result:=esSimple;
cbsEllipsis : result:=esEllipsis;
end;
end;
And the constructor and destructor just call inherited , with the constructor just setting some colors for the grid.

The reason there's no pick list or button is that you are using an TInplaceEdit as the cell editor which does not support the functionality you need.
The TDBGrid uses an TDBGridInplaceEdit that inherits from TInplaceEditList as its in place editor which integrates a TCustomListbox for its drop down list and paints and manages the edit button.

Related

Delphi dbgrid with wildcard character

I have DBGrid. Sometimes, if i change some cell value, it give a wildcard. You can see that in the image.
My question : when this wildcard, it can be appear? How can disable that?
The * is an indicator that your dbgrid is in insert mode.
If you don't want this indicator to appear you can change (the drawing of) it in the OnDrawColumnCell event.
If you use this event you may need to set dbGrid.DefaultDrawing to false.
See also: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Controlling_Grid_Drawing
Another option is to implement your own custom style.
type
TMyStyleWithNoIndicator = class(TCustomStyleServices)
function GetElementDetails(Detail: TThemedGrid): TThemedElementDetails; override;
end;
function TMyStyleWithNoIndicator.GetElementDetails(Detail: TThemedGrid): TThemedElementDetails;
begin
inherited;
//prevent drawing of the insert indicator.
if Detail in [tgIndicatorInsert] then Result.State = Ord(tgCellNormal);
end;
procedure TForm1.Form1Create(Sender: TObject);
begin
TStyleManager.SetStyle(TMyStyleWithNoIndicator.Create);
end;

How can I get a TDBLookupComboBox to show what you are typing?

I have a TDBLookupComboBox on my form.
When I put my cursor in it and type, the selection jumps a head to what I've typed (or as close as it can).
However I don't get any indication of what I've typed in the field.
TDBComboBox performs similarly to TDBLookupComboBox however, when I type in the field, the characters I type appear in regular text, and the 'completion' of the selection appears in inverse/selected following the regular text.
Is there a way I can make TDBLookupComboBox perform like TDBComboBox in this respect?
No, you can't make TDBLookupComboBox act like a TDBComboBox (without a bit of hacking).
The problem is that TDBLookupComboBox is used to lookup an index-field (normally a number) from another table. The chosen index is set in the destination-field. When you make TDBLookupComboBox "editable" (like TDBComboBox), you could type in anything, even values not in the source-table. And that shouldn't happen (by design). What index-value would you set in that case in the destination field?
You have several options.
You could "hack" TDBLookupComboBox to override the paint procedure to overwrite the selected text with the not selected (already typed) text. It's not easy. Especially if you want to maintain the functionality correctly. But here is some code where I think I've come close to what you want. Although when typing something that's not in the lookup-dataset it doesn't go any further. (It also doesn't account for right aligned text etc.):
type
TDBLookupComboBox = class(DBCtrls.TDBLookupComboBox)
protected
procedure Paint; override;
procedure KeyPress(var Key: Char); override;
end;
type
TForm1 = class(TForm)
DBLookupComboBox1: TDBLookupComboBox;
//.....
procedure TDBLookupComboBox.Paint;
var
TextPart: String;
begin
inherited;
Canvas.Font := Font;
Canvas.Brush.Color := Color;
// keeps case like the field is drawn
TextPart := Copy(Text, 1, Length(SearchText));
Canvas.TextOut(2, 2, TextPart);
end;
procedure TDBLookupComboBox.KeyPress(var Key: Char);
begin
inherited;
// we need this because paint is already called
// we need to call it again to overwrite the text
invalidate;
end;
It overrides the DBLookupComboBox at the top of your form. You don't have to compile this into a new component. You can just paste it into your form with the DBLookupComboBox. We need to call Paint again after keypress (with invalidate) because paint is already called before coming to that routine.
Another option is to use the TDBComboBox. You can fill the pulldown-items in OnEnter.
procedure TForm1.DBComboBox1Enter(Sender: TObject);
begin
DBComboBox1.Items.Clear;
IBQuery1.First;
while not IBQuery1.EOF do
begin
DBComboBox1.Items.Add(IBQuery1.FieldByName('TESTFIELD').DisplayText);
IBQuery1.Next;
end;
end;
If that's too slow (when entering the combobox) you could also fill the items at opening of the dataset.
Another few options from Jedi-library:
JvDBLookupCombo1
Has a pulldown directly when typing. The original typed text stays in the box.
TJvDBSearchComboBox
Also does what you want but is not connected to a destination datasource. You'll need to set the desired field yourself on OnExit.

How can I remove the or change the "horizontal separator" in a Category Panel control?

I've been playing around with the Category Panel Control inside Delphi 2010. I've been able to modify the colors and get them working they way I'd like. However, there's a silver colored "horizontal separator" (I don't know what else to call it) between each panel heading.
How can I change the appearance of this "horizontal separator" or remove it all together?
A look at the source of T(Custom)CategoryPanel reveals a method DrawCollapsedPanel. It unconditionally draws the separator. DrawCollapsedPanel is called from DrawHeader and the only condition checked is whether the panel is collapsed.
More importantly though, DrawCollapsedPanel is virtual, so you can either create your own descendant or use an interceptor class:
TCategoryPanel = class(ExtCtrls.TCategoryPanel)
protected
procedure DrawCollapsedPanel(ACanvas: TCanvas); override;
function GetCollapsedHeight: Integer; override;
end;
If you put this in a separate unit, all you need to do then is include it AFTER the ExtCtrls unit wherever you want a category panel with your own behaviour.
To please David :-)
procedure TCategoryPanel.DrawCollapsedPanel(ACanvas: TCanvas);
begin
// Don't call inherited, we do not want the default separator.
// And don't draw anything you don't want.
end;
and we need to override GetCollapsedHeight as well, as that determines the room available for whatever you want to draw under the Header in a collapsed state:
function TCategoryPanel.GetCollapsedHeight: Integer;
begin
// As we don't want anything under here,
// don't call inherited and just return the HeaderHeight.
// (Instead of HeaderHeight + 6;
Result := HeaderHeight;
end;
Screenshot:

How to add a drop down menu to an Action Item at Runtime

I'm using the following method to create a an ActionClient with an Action at run time.
procedure TMainForm.AddToProjectHistory(Path: string);
var
NewOption: TAction;
ActionClient: TActionClientItem;
begin
NewOption := TAction.Create(self);
NewOption.ActionList := ActionManager1;
NewOption.Caption := Path;
NewOption.OnExecute := ProjectHistoryExecute;
ActionClient := TActionClientItem(aToolBarFile.ActionClient.Items[0].Items.Add);
ActionClient.Action := NewOption;
ActionClient.Caption := Path;
end;
This works fine if there is already an item in the list, but doesn't work at all if there isn't
e.g. if I add an Item at design time then I can add more items at runtime
But if I don't add anything at design time, theres no Drop Down to display the list of items, no drop down appears after adding items.
This doesn't have to be done with Actions but the rest of the menu system uses actions and I don't think I can add standard MenuItems to the action drop down.
Delphi 2005
The VCL automatically creates button controls of a type that depends on whether the item has child elements. By default (and depending on the ActionManager's style setting), for an ActionClientItem which has child items, a TXPStyleDropDownBtn button is created, and for a childless ActionClientItem, a TXPStyleButton is created.
So when the first child item is added during run time, the button is of the wrong type. Changing the type of that button would require destruction of the current button and a complete and manual instantiation of the new button. This should be possible, but have not tried, because:
The really most easy solution is to fool the VCL by adding a child item at design time, and to delete that item on form creation:
procedure TForm1.FormCreate(Sender: TObject);
begin
aToolBarFile.ActionClient.Items[0].Items[0].Free;
end;
if you create an actionclient of type "context", it won't have to change button type. The menu will drop down when you right click on the button instead.

Making a TPageControl flat in Delphi 7

I don't know whether this question can be answered here, but I hope it will.
I wrote a simple text editor in Delphi 7 that serves as my primary IDE for writing C code under Windows. I run Windows in a VM and I needed something light.
In any case, it uses a TpageControl that gets a new tab whenever you open or create a new file. Pretty standard.
Now, the TPageControl under Delphi has no flat property.
NO I don't mean setting the tab style to tsButtons or tsFlatButtons
the borders cannot be set to "none" and it looks pretty bad when you add a text editor into the tab control.
Is there any way to make a TpageControl flat?
EDIT:
On an open source PageControl that supports flat here's what I found:
procedure TCustomTabExtControl.WndProc(var Message: TMessage);
begin
if(Message.Msg=TCM_ADJUSTRECT) and (FFlat) then
begin
Inherited WndProc(Message);
Case TAbPosition of
tpTop : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Top:=PRect(Message.LParam)^.Top-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpLeft : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Left:=PRect(Message.LParam)^.Left-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpBottom : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Bottom:=PRect(Message.LParam)^.Bottom-4;
PRect(Message.LParam)^.Top:=0;
end;
tpRight : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=PRect(Message.LParam)^.Right-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
end;
end else Inherited WndProc(Message);
end;
The thing is when I tried something similar on the main application it won't work. It won't even compile.
When the tabs are drawn as buttons, no border is drawn around the display area, so set the Style property to tsButtons or tsFlatButtons. (For non-VCL programmers, this is equivalent to including the tcs_Buttons window style on the tab control.)
An alternative is to use a TNotebook. It holds pages, but it doesn't do any painting at all. You'd have to provide the tabs yourself, such as by setting the tab control's height equal to the height of the tabs, or by using a TTabSet. (TTabSet is available in Delphi 2005; I'm not sure about Delphi 7.)
Regarding the code you found, it would be helpful if you indicated why it doesn't compile, or if you gave a link to where you found it, since I suppose the compilation error was because it refers to fields or properties of the custom class rather than the stock one. Here's what you can try to put it in your own code, without having to write a custom control.
Make two new declarations in your form like this:
FOldTabProc: TWndMethod;
procedure TabWndProc(var Msg: TMessage);
In the form's OnCreate event handler, assign that method to the page control's WindowProc property:
FOldTabProc := PageControl1.WindowProc;
PageControl1.WindowProc := TabWndProc;
Now implement that method and handle the tcm_AdjustRect messsage:
procedure TForm1.TabWndProc(var Msg: TMessage);
begin
FOldTabProc(Msg);
if Msg.Msg = tcm_AdjustRect then begin
case PageControl1.TabPosition of
tpTop: begin
PRect(Msg.LParam)^.Left := 0;
PRect(Msg.LParam)^.Right := PageControl1.ClientWidth;
Dec(PRect(Msg.LParam)^.Top, 4);
PRect(Msg.LParam)^.Bottom := PageControl1.ClientHeight;
end;
end;
end;
end;
You can fill in the other three cases if you need them. Tcm_AdjustRect is a message identifier declared in the CommCtrl unit. If you don't have that message in that unit, declare it yourself; its value is 4904.
I suspect this doesn't stop the control from drawing its borders. Rather, it causes the contained TTabSheet to grow a little bigger and cover up the borders.
I'm using Delphi XE8 and the following seems to do the trick:
ATabControl.Tabs.Clear;
ATabControl.Style := TTabStyle.tsFlatButtons;
ATabControl.Brush.Color := clWhite;
You could always use a commercial solution. I would strongly recommend Raize components, which support flat TPageControls with tabs. The component set is very easy to work with, and supports numerous visual enhancements which in my opinion give a better feel to any application.
(source: raize.com)
Drop two TPageControls, one with tabs as Tabs, with a global height equal to the tabs, and one with flatbuttons and Tabvisible properties set to false, which would be aligned under the first one. Then make sure the tab change on the first TPagecontrol makes the tabs also change in the second one.

Resources