TDBGrid right align columns and set caret pos when editing value - delphi

I want to set the caret position in my derived TInplaceEdit in a derived DBGrid, similiar to a TDBGrid for right aligned columns.
procedure TMyGridEditor.CreateParams(var Params: TCreateParams);
const
Alignments : array[TAlignment] of LongWord= (ES_Left, ES_Right, ES_Center);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or Alignments[FAlignment];
end;
procedure TMyGridEditor.UpdateContents;
begin
inherited;
// if Assigned(Grid) and Assigned(Grid.SelectedColumn) then begin
// Alignment := Grid.SelectedColumn.Alignment;
if (TDBGrid(Grid).SelectedIndex <> -1) then
Alignment := TDBGrid(Grid).Columns[TDBGrid(Grid).SelectedIndex].Alignment;
end;
Additional description:
Grid.SelectedColumn = Currently selected column of the grid
Sample picure: Column too small for value
Problem1: The caret position is always on the right and positioned after the last character, this looks strange for ie. string and memo contents. How can I set the caret to the left, just after the inplaceeditor will be displayed.
Problem2: The contents for number values are displayed on multiple lines, when there is not sufficient space avaiable (column is too small). This looks very strange.
How can I accomplish these tasks? Any help appreciated... Thanks

Related

TCustomEdit right align makes caret position weird

I made a number edit (inherited from TCustomEdit) with fixed right alignment:
procedure TNumberEdit.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or ES_RIGHT;
end;
Works, but the caret posotion looks weird, hiding part of the rightmost character:
Tried to set the the right margin with the following code:
Perform(EM_SETMARGINS, EC_RIGHTMARGIN, MakeLong(0, xWidth));
The margin appears, but doesnt make any difference bot the characters and the caret will get the offset.
How can I prevent this?
(Im using Delphi 7)

Dynamically assigning form size before maximize loses assigned values

I have an application which always starts initially maximized. This consists of putting Self.WindowState := wsMaximized; in the OnCreate of the main form.
Just before that, I'm assigning what should be the default dimensions of the main form, if the user were to change the window state to wsNormal.
So, in short, the main form's OnCreate handler looks something like:
procedure TfrmMain.FormCreate(Sender: TObject);
begin
Width:= 1300;
Height:= 800;
WindowState:= wsMaximized;
end;
Theoretically, I could assign these dimensions in design-time, and that does what I need. However, due to the size of my screen, and thus the IDE, the whole form is not visible at one glance without scrolling. In design, I keep the form size small, so I can see everything. But in runtime, I need to assign these default dimensions, and then maximize it by default. When the user changes the window state out of maximized, I expect it to go to those dimensions I dynamically assigned.
The issue is that it seems to lose those dimensions after maximizing the form, and it reverts back to whatever values were in design-time. If I comment out the line WindowState:= wsMaximized; then it shows the form in the desired default dimensions. However, maximizing it seems to overwrite and ignore these values I had just assigned before it.
How can I create and show my main form maximized by default, while at the same time dynamically assigning the default size, without my assigned values getting lost?
(Confirmed with 10.3.3.)
The exact origin of this problem I cannot pinpoint, but a reasonable cause would be that during the constructor the form component is being read and that previous sizes seem to be explicitly backed up:
procedure TControl.SetWidth(Value: Integer);
begin
SetBounds(FLeft, FTop, Value, FHeight);
Include(FScalingFlags, sfWidth);
if csReading in ComponentState then
FExplicitWidth := FWidth;
end;
A possible solution is to set the desired sizes in the OnCreate event, like you are doing now, but postpone setting the desired WindowsState until the OnShow event.
procedure TForm1.FormCreate(Sender: TObject);
begin
Width := 1300;
Height := 800;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
WindowState := wsMaximized;
end;
Of course, you probably should prevent consecutive calls by using a one-off mechanism.
Please take a look at wsMaximized forms do not appear maximized too.
Apparently, the VCL does not store the explicit intermediate size (in some Delphi versions anyway) but seems to merge the change with that of the maximization when the form is actually shown.
Like Sertac Akyuz quite correctly suggested, you can use SetWindowPlacement to bypass this VCL interference:
procedure TForm1.FormCreate(Sender: TObject);
var
WindowPlacement: TWindowPlacement;
begin
GetWindowPlacement(Handle, WindowPlacement);
WindowPlacement.rcNormalPosition := Bounds(Left, Top, 1300, 800);
WindowPlacement.showCmd := SW_SHOWMAXIMIZED;
SetWindowPlacement(Handle, WindowPlacement);
end;
You must set form size on FormActivate:
procedure TfrmMain.FormActivate(Sender: TObject);
begin
if Tag = 0 then
begin
// Top := 100;
// Left := 100;
Width:= 1300;
Height:= 800;
WindowState:= wsMaximized;
Tag := 1;
end;
end;

Delphi properly position balloon hint associated with a listview item

How do I ensure a balloon hint that I want to associate with a listview item is properly positioned so that it is next to the item in question, and always shows the full ballon text on screen?
For example, if I enter an invalid character when editing a file name in Windows Explorer, a balloon pops up saying what the invalid characters are. The entire balloon is always on screen even if the list item is near a screen edge or partially off screen. The tail is always positioned at the middle bottom of the list item. The bubble is usually to the bottom right of the tail, but may be above it or to the left if the list item is near the bottom and/or right edges of the screen.
Primarily, I am unable to get the bubble and tail to stay close to the list item.
procedure TForm1.ListEdited(Sender: TObject; Item: TListItem;
var S: string);
var
AHint: string;
R: TRect;
B : TBalloonHint;
begin
if TRegEx.IsMatch(S, '[\\/:*?"<>|]') then
begin
AHint := 'A file name cannot contain any of the following' + sLineBreak +
'characters: \/:*?"<>|';
R := Item.DisplayRect(drBounds);
R.TopLeft := ClientToScreen(R.TopLeft);
R.BottomRight := ClientToScreen(R.BottomRight);
B := TBalloonHint.Create(Self);
B.Description := AHint;
B.HideAfter := 5000;
B.ShowHint(R);
S := TRegEx.Replace(S, '[\\/:*?"<>|]', '');
end;
end;
I've tried the various overloads of ShowHint, as well as the JEDI balloon hint component. I've also adjusted the Top property of the rectangle, which may position the balloon better when the item is in a certain area of the screen, but the ballon is then off position when the item is on some other part of the screen.
Delphi 10.3 Rio, Win 7 x64.
DisplayRect gives client coordinates relative to the listview containing the item, not the form. Hence when converting to screen coordinates, you have to use the listview as the base, not the form:
R := Item.DisplayRect(drBounds);
R.TopLeft := ListView1.ClientToScreen(R.TopLeft); // <--
R.BottomRight := ListView1.ClientToScreen(R.BottomRight); // <--

Is there a way to turn off the Caption on a TDBRadioGroup

I have a TDBRadioGroup that I've added to my form.
I'd really like to have the caption to the left of it instead of on top (the form's a little busy and tall, and I'm trying to squeeze it in).
I can add my own label to the left of the Radio Group. But the control insists on reserving space of a Caption that does not exists. Is there a way I can turn it off completely?
The best we've come up with so far is sticking it on a TPanel and then hiding the top couple lines off-panel.
A TGroupBox (and it's descendant TDBGroupBox) are basically wrappers around the Windows GroupBox. The control is designed to sport a user-defined label across the upper-left corner, and doesn't have any style setting to remove it.
So, short of creating your own control to host a series of TRadioButton controls yourself and display them, there's no built-in way to disable the space reserved for the caption. You can suppress the text, of course, by setting the Caption := '', but the padding for the text descenders is not removed simply because the caption isn't displayed.
You can override the paint procedure for TRadioGroup so that the frame is drawn closer to the top of your item list. You could create a new component of type TNoCaptionRadioGroup. You might still have to use the panel trick that you have tried, but by lowering the top of the frame you can grab the space consumed by the non-existent caption. Something like this:
tNoCaptionRadioBox = class(TRadioGroup)
protected
procedure paint; override;
end;
procedure tNoCaptionRadioBox.paint;
var
H: Integer;
R: TRect;
begin
with Canvas do
begin
Font := Self.Font;
H := TextHeight('0');
R := Rect(0, H, Width, Height);
if Ctl3D then
begin
Inc(R.Left);
Inc(R.Top);
Brush.Color := clBtnHighlight;
FrameRect(R);
OffsetRect(R, -1, -1);
Brush.Color := clBtnShadow;
end else
Brush.Color := clWindowFrame;
FrameRect(R);
end;
end;
This is taken from the code for painting a TCustomGroupBox. I have removed the code for drawing the caption and have changed the top of the frame to the full height of the Font. Your actual captioned radio buttons will still be drawn where Windows wants them to be and with the default spacing.
Remember to register the new component by running the package installation tool.
procedure Register;
begin
RegisterComponents('myComponents', [tNoCaptionRadioBox]);
end;

Problem with adding graphics to TLabel

I'm trying to create with Delphi a component inherited from TLabel, with some custom graphics added to it on TLabel.Paint. I want the graphics to be on left side of text, so I overrode GetClientRect:
function TMyComponent.GetClientRect: TRect;
begin
result := inherited GetClientRect;
result.Left := 20;
end;
This solution has major problem I'd like to solve: It's not possible to click on the "graphics area" of the control, only label area. If the caption is empty string, it's not possible to select the component in designer by clicking it at all. Any ideas?
First excuse-me for my bad English.
I think it is not a good idea change the ClientRect of the component. This property is used for many internal methods and procedures so you can accidentally change the functionality/operation of that component.
I think that you can change the point to write the text (20 pixels in the DoDrawText procedure -for example-) and the component can respond on events in the graphic area.
procedure TGrlabel.DoDrawText(var Rect: TRect; Flags: Integer);
begin
Rect.Left := 20;
inherited;
end;
procedure TGrlabel.Paint;
begin
inherited;
Canvas.Brush.Color := clRed;
Canvas.Pen.Color := clRed;
Canvas.pen.Width := 3;
Canvas.MoveTo(5,5);
Canvas.LineTo(15,8);
end;
What methods/functionality are you getting from TLabel that you need this component to do?
Would you perhaps be better making a descendent of (say, TImage) and draw your text as part of it's paint method?
If it's really got to be a TLabel descendant (with all that this entails) then I think you'll be stuck with this design-time issue, as doesn't TLabel have this problem anyway when the caption is empty?
I'll be interested in the other answers you get! :-)

Resources