Adding a checkbox to cxGridDBColumn (DateEdit) - delphi

I using Delphi BDS 2006 and have a DevExpress cxGridDBColumn with properties set to DateEdit and was wondering whether it is possible to add a checkbox to the displayed date time picker popup?

I am not sure that I understand what you wish to achieve. Anyway, it is impossible without creating a custom cxEditor which supports this look&feel and desired functionality.

Here is a quick hack which should help you implement this feature. However, you should handle the checkBox yourself. I have done this for the standalone editor, however, the same approach will work with the inplace editor:
procedure TForm1.cxDateEdit1PropertiesPopup(Sender: TObject);
var
AEdit: TcxDateEdit;
ACalendar: TcxPopupCalendar;
ACheckBox: TcxCheckBox;
begin
AEdit := TcxDateEdit(Sender);
if AEdit.Tag <> 1 then
begin
AEdit.Tag := 1;
ACalendar := TcxPopupCalendar(AEdit.Properties.PopupControl);
ACheckBox := TcxCheckBox.Create(Self);
ACheckBox.Parent := ACalendar.Parent;
ACheckBox.Align := alBottom;
ACheckBox.Transparent := True;
ACalendar.Parent.Height := ACalendar.Parent.Height + ACheckBox.Height;
end;
end;

Related

How to create a non visual component without any icon on the form?

I would like to create a non visual component (like TTimer for example) that I can drop on the form and that I can set up directly from the Object Inspector, but I don't want to see its icon on the form (it'd just obstruct anything). For example TFloatAnimation works like this but I don't understand how.
The GExperts library (http://www.gexperts.org/) has a plug-in which can toggle the visibility
of non-visual components on a form, and it is apparently not Delphi-version-specific but it is
not exactly trivial.
The method which does this is
procedure THideNonVisualCompsExpert.ToggleNonVisualVisible(Form: TCustomForm);
const
NonVisualClassName = 'TContainer';
var
VisibleState: Boolean;
FormHandle: THandle;
CompHandle: THandle;
WindowClass: string;
FirstCompFound: Boolean;
WinControl: TWinControl;
ChildControl: TWinControl;
i: Integer;
begin
Assert(Assigned(Form));
Assert(Form.Handle > 0);
FirstCompFound := False;
WinControl := Form;
if InheritsFromClass(WinControl.ClassType, 'TWinControlForm') then
begin
for i := WinControl.ComponentCount - 1 downto 0 do
begin
if WinControl.Controls[i] is TWinControl then
begin
ChildControl := WinControl.Controls[i] as TWinControl;
if InheritsFromClass(ChildControl.ClassType, 'TCustomFrame') then
begin
WinControl := ChildControl;
Break;
end;
end;
end;
end;
FormHandle := GetWindow(WinControl.Handle, GW_CHILD);
CompHandle := GetWindow(FormHandle, GW_HWNDLAST);
VisibleState := False;
GxOtaClearSelectionOnCurrentForm;
while (CompHandle <> 0) do
begin
WindowClass := GetWindowClassName(CompHandle);
if AnsiSameText(WindowClass, NonVisualClassName) then
begin
if not FirstCompFound then
begin
VisibleState := not IsWindowVisible(CompHandle);
FirstCompFound := True;
end;
if VisibleState then
ShowWindow(CompHandle, SW_SHOW)
else
ShowWindow(CompHandle, SW_HIDE);
end;
CompHandle := GetWindow(CompHandle, GW_HWNDPREV);
end;
end;
in the unit GX_HideNonVisualComps.Pas.
As written, it toggles the visibility of all the non-visual components on the
target form, but looking at the code of the ToggleNonVisualVisible method it looks like it
ought to be possible (but I have not tried) to adapt it to operate on a selected component class and
force instances of the class to a non-visible state. Once you have done that, you would probably
need to experiment with how and when to invoke the method at design-time; if I was doing it, I would probably start
with somewhere like the target component's Loaded method.
(I would feel more comfortable posting this "answer" as a comment but obviously it would be too long)
I have thought about this. A Non Visual Component does not do any painting, in a Windows environment (like the IDE) it has no Window, and therefore cannot influence how the IDE chooses to render it.
One approach would be to derive from TWinControl, making your component a Visual Component, and then to ensure that it is not drawn. Try setting the positioning properties to be non-published, and when you are parented, always set your position outside the parent window. This means that your control is always clipped and never painted.
I haven't tried this, but I can see no reason why it wouldn't work.
You can also use this approach to have an apparently non visual component that renders information in the IDE at designtime, but not at runtime.

FindComponent Not Finding Components Created at Runtime

I use Delphi 7 with a number of third party components. My main stub application loads a number of DLLs, which are various modules like creditors, debtors, purchase orders, and so on.
I have an issue with FindComponent(). 99% of the time, it works how it should. But not for the code below.
I was trying to create a form reports, where I keep all the details of the reports selection criteria in a table, and then create the criteria on the fly. In theory, it should work perfectly, but for some reason after creating the components, FindComponent() cannot find them.
try
for i := gbSelectionCriteria.ComponentCount - 1 downto 0 do begin
ShowMessage(gbSelectionCriteria.Components[i].Name);
gbSelectionCriteria.Components[i].Free;
end;
// The above loop to remove the components from the groupbox works fine
// Creating the components works
fSysData.tbSelectionCriteria.First;
while not fSysData.tbSelectionCriteria.EOF do begin
case fSysData.tbSelectionCriteriaComponentType.AsInteger of
1 : begin // TMyAdvEdit
with TMyAdvEdit.Create(gbSelectionCriteria) do begin
Visible := False;
Parent := gbSelectionCriteria;
Name := fSysData.tbSelectionCriteriaName.AsString;
Left := fSysData.tbSelectionCriteriaLeft.AsInteger;
Top := fSysData.tbSelectionCriteriaTop.AsInteger;
Width := fSysData.tbSelectionCriteriaWidth.AsInteger;
LabelCaption := fSysData.tbSelectionCriteriaCaption.AsString;
LabelPosition := AdvEdit.lpLeftCenter;
LabelAlwaysEnabled := True;
LabelTransparent := True;
EditType := MyEditType[fSysData.tbSelectionCriteriaDataType.AsInteger];
Text := '';
OnClick := GetClickEvent(fSysData.tbSelectionCriteriaOnClickEvent.AsString);
OnDblClick := GetClickEvent(fSysData.tbSelectionCriteriaOnDblClickEvent.AsString);
OnKeyPress := GetKeyPressEvent(fSysData.tbSelectionCriteriaOnKeyPressEvent.AsString);
Visible := True;
// at this point findComponent finds nothing
if FindComponent(Name) <> nil then
ShowMessage(Name+' Created');
end;
edEdit.OnClick := GetClickEvent(fSysData.tbSelectionCriteriaOnClickEvent.AsString);
edEdit.OnDblClick := GetClickEvent(fSysData.tbSelectionCriteriaOnDblClickEvent.AsString);
edEdit.OnKeyPress := GetKeyPressEvent(fSysData.tbSelectionCriteriaOnKeyPressEvent.AsString);
edEdit.Visible := True;
if FindComponent(edEdit.Name) <> nil then
ShowMessage(edEdit.Name+' Created');
end;
2 : begin
end;
3 : begin
end;
4 : begin
end;
5 : begin
end;
6 : begin
end;
7 : begin
end;
8 : begin
end;
end;
fSysData.tbSelectionCriteria.Next;
end;
if fSysData.tbSysReports.Locate('ReportID', TAdvOfficeRadioButton(Sender).Tag, []) then begin
ReportData.ReportID := TAdvOfficeRadioButton(Sender).Tag;
ReportData.RepName := fSysData.tbSysReportsReportName.AsString;
ReportData.RepTitle := fSysData.tbSysReportsReportTitle.AsString;
ReportData.RepModule := fSysData.tbSysReportsModule.AsString;
ReportData.RepOrientation := fSysData.tbSysReportsReportOrientaton.AsString;
ReportData.RepPageIndex := fSysData.tbSysReportsCriteriaPageIndex.AsInteger;
end;
finally
end;
The Process of the reports is:
User clicks a button
Radio buttons are created from the button click
User clicks a radio button
Report criteria is created from the radio button click
User enters data or DblClicks to select data from a list.
User Clicks Preview button to view Report - this is where FindComponent fails and returns nil..
All the code worked before when I had created all the criteria at design time, then added the code above.
The code below is part of what needs to be added to the query to retrieve the data for the report:
if Length(TMyAdvEdit(FindComponent('edQuoteReference')).Text) > 0 then
qryTempTable.SQL.Add(' and q.UserReference = "' + TMyAdvEdit(FindComponent('edQuoteReference')).Text + '"');
This is the first time FindComponent() fails and goes no further.
I have tried various ways to create the components, but each of them results in an Access Violation because the component is nil.
I have looked everywhere, and tried everything I can think of, for a solution to this problem.
FindComponent searches for components owned by the subject of the method call. You call FindComponent on the form, and so look for the component amongst those components owned by the form. But the control you search for is not owned by the form, it is owned by gbSelectionCriteria, which is what you passed to the control's constructor as the Owner argument.
If you wish to use FindComponent in the way you do you therefore need to make the form be the owner of the controls that you create. Then when you call FindComponent on the form, it can find the control because it is the owner. Pass Self to the control's constructor to make this come to pass:
TMyAdvEdit.Create(Self)
I'm having to make some reasonably large guesses here. Perhaps this code actually resides in a data module rather than a form. But the essential principle will be as I say.
Firstly I do apologize if this is in the wrong spot..
Thanks for the response and the answer, I have been doing this for a lot of years and I can't believe I missed something so small.
this,
if FindComponent(Name) <> nil then
should have been this,
if gbSelectionCriteria.FindComponent(Name) <> nil then
I don't normally use with, it was just one way to test create the component.
I set the components visibility to false before and then to true after it is created to stop flicker as it creates.
Thanks again..

How to align paragraph using Delphi MSWord automation?

I want to align a text to center and I have no idea on how to achieve it.
Here is my code:
try
MsWord := GetActiveOleObject('Word.Application');
except
try
MsWord := CreateOleObject('Word.Application');
MsWord.Visible := True;
except
Exception.Create('Error');
end;
end;
MSWord.Documents.Add;
MSWord.Selection.Font.Size := 22;
MSWord.Selection.Font.Bold := true;
MSWord.Selection.TypeText(#13#10);
MSWord.Selection.TypeText('I want this to be center-aligned');
...
MSWord.ActiveDocument.SaveAs('C:\doc2.doc');
Please help.
Thanks
This works for me:
procedure TForm1.Button1Click(Sender: TObject);
var
MSWord : OleVariant;
begin
try
MsWord := GetActiveOleObject('Word.Application');
except
try
MsWord := CreateOleObject('Word.Application');
MsWord.Visible := True;
except
Exception.Create('Error');
end;
end;
MSWord.Documents.Add;
MSWord.Selection.Font.Size := 22;
MSWord.Selection.Font.Bold := true;
MSWord.Selection.TypeText(#13#10);
MSWord.Selection.TypeText('I want this to be center-aligned');
MSWord.Selection.ParagraphFormat.Alignment := wdAlignParagraphCenter;
MSWord.ActiveDocument.SaveAs('C:\doc2.doc');
end;
Btw, the way to find the answer yourself is to go into Word, start recording a macro, perform the action, stop recording then edit the macro to see what code Word generates. Converting that to Delphi is usually fairly trivial if you're using late binding (accessing Word from Delphi via an OleVariant) but can be a bit long winded if you're using early binding, because early binding requires all parameters to be specified, whereas late binding lets you leave most of them out.

Programmatically adding columns to a TdxDBGrid (Expressquantumgrid by Devexpress)

With a customer I'm stuck developing for this very old version (2.1) of ExpressQuantumGrid by DevExpress. In Delphi 4. I can't find any documentation about it.
Basically I just need to create a bunch of TdxDBGridMaskColumn and "insert" them into the grid (TdxDBGrid) at runtime. From the code completion pop-up I can't figure out how.
Thanks!
We have an old app that uses Delphi 5 and DevExpress v3, the code might not be identical but should get you started.
A function that can create a column of any type (TdxDBDateColumn for example):
function CreateColumn(const aField: string; aColClass: TdxDBTreeListColumnClass): TdxDBTreeListColumn;
var
begin
Result := dxGrid.CreateColumn(aColClass);
Result.Name := dxGrid.Name + aField;
TdxDBGridColumn(Result).DisableFilter := True;
TdxDBGridColumn(Result).DisableGrouping := True;
TdxDBGridColumn(Result).Alignment := taRightJustify;
TdxDBGridColumn(Result).FieldName := aField;
TdxDBGridColumn(Result).Caption := aField;
TdxDBGridColumn(Result).Width := 70;
end;
Then you can call this function like so:
NewColumn := CreateColumn('Username', TdxDBGridColumn);

Dynamically access a property in a Delphi component

I'm using Delphi 5, and we have a method to dynamically create certain controls based on the contents of a database table (we create TButtons mostly) and take action when those are clicked. This allows us to add simple controls to a form without having to recompile the application.
I was wondering if it was possible to set a component's property based on a property name contained in a string so we could set further options.
Pseudo-code:
Comp := TButton.Create(Self);
// Something like this:
Comp.GetProperty('Left').AsInteger := 100;
// Or this:
Comp.SetProperty('Left', 100);
Is this possible at all?
You have to use the Run-Time Type Information features of Delphi to do this:
This blog describes exactly what you are trying to do: Run-Time Type Information In Delphi - Can It Do Anything For You?
Basically you have to get the property information, using GetPropInfo and then use SetOrdProp to set the value.
uses TypInfo;
var
PropInfo: PPropInfo;
begin
PropInfo := GetPropInfo(Comp.ClassInfo, 'Left');
if Assigned(PropInfo) then
SetOrdProp(Comp, PropInfo, 100);
end;
This is not as concise as your pseudo-code, but it still does the job. Also it gets more complicated with other stuff, like array properties.
From one of my working units (in Delphi 7 though)
var
c : TComponent;
for i := 0 to pgcProjectEdits.Pages[iPage].ControlCount - 1 do
begin
c := pgcProjectEdits.Pages[iPage].Controls[i];
if c is TWinControl
then begin
if IsPublishedProp(c,'color')
then
SetPropValue(c,'color',clr);
if IsPublishedProp(c,'readonly')
then
SetPropValue(c,'readonly', bReadOnly );
...
end;
...
You have to include TypInfo in the uses statement.
Don't know if this works under Delphi 5.
Just as an added example. Here is how to set sub-properties, I'm setting the Margins on this Button component:
uses TypInfo;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
var PropInfo := GetPropInfo(Button1.ClassInfo, 'Margins');
if Assigned(PropInfo) then
begin
var Margins := TMargins.Create(self);
try
Margins.Left := 100;
Margins.Top := 100;
Margins.Right := 100;
Margins.Bottom := 100;
SetObjectProp(Button1, PropInfo, Margins);
finally
Margins.Free;
end;
end;
end;
This works on Delphi 10.3 Rio and later due to the inline variables.

Resources