I want to remove the caret from a TEdit control in Delphi. I have made the component Enabled := False but the caret still appears.
My question is how to remove the caret from a disabled TEdit control?
I assume that you mean TEdit control.
The solution is HideCaret function, the only problem is where to call it. The 2 event handlers below worked fine for me:
procedure TForm18.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
HideCaret(Edit1.Handle);
end;
procedure TForm18.Edit1MouseEnter(Sender: TObject);
begin
HideCaret(Edit1.Handle);
end;
Place a TApplicationEventscontrol on the form and in the OnIdle event, hide the caret, as follows. Set the event to nil so it only fires once.
procedure TFormMain.AppEventsIdle(Sender: TObject; var Done: Boolean);
begin
AppEvents.OnIdle := nil;
HideCaret(Memo1.Handle);
end;
Related
How can I disable the mouse wheel scroll on a FMX TComboBox when hovering over it?
I've tried overriding the MouseWheel method without any luck. I'm most likely doing it wrong as I'm not experienced with overriding. REF: MouseWheel
I've gone ahead and removed Inherited:
type
TComboBoxOverride = class(TComboBox)
procedure MouseWheel(Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean); override;
end;
// I've tried changing the control on the class overriding the method. No luck
cbbServerMap: TComboBoxOverride;
{ TComboBoxOverride }
procedure TComboBoxOverride.MouseWheel(Shift: TShiftState; WheelDelta: Integer;
var Handled: Boolean);
begin
Handled := True;
end;
I've found the following SO post for VCL and DevEx but I'm struggling to convert it to FMX, Ref: How to suppress mouse wheel in TcxComboBox
When setting a breakpoint on the TCustomComboBox.MouseWheel method I can see that it ignores my override.
In the OnMouseWheel event, simply put Abort;.
For example:
procedure TfrmMinorInjury.cboDischargetypeMouseWheel(Sender: TObject;
Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean);
begin
Abort;
end;
I solved the same task but for memos in scrollbox.
My solution is
handle mouse wheel in scrollbox.OnMouseWheel. Set Handle := true there.
call directly scrollbox.OnMouseWheel in memo's OnMouseWheel
I use Delphi Berlin on Windows 10. I need to use tOpenDialog on a tStringGrid based tForm.
When I double click a file which overlaps a fixed column or row on an open dialog onFixedCellClick event fires automatically right after the disapperance of the open dialog. In the following image the file is on the same position of fixed row which is the first line.
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
OpenDialog1: TOpenDialog;
procedure FormClick(Sender: TObject);
procedure StringGrid1FixedCellClick(Sender: TObject; ACol, ARow: Integer);
procedure FormCreate(Sender: TObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.Options := StringGrid1.Options + [goFixedColClick, goFixedRowClick];
end;
procedure TForm1.FormClick(Sender: TObject);
begin
OpenDialog1.Execute;
end;
procedure TForm1.StringGrid1FixedCellClick(Sender: TObject; ACol, ARow: Integer);
begin
Caption := '';
end;
In most cases I can handle this by moving the dialog window or clicking the file once and clicking open button but I can't guarantee that other people who will use this would do that.
What is the reason and how can I solve this problem?
I believe this is a problem in how TCustomGrid triggers its OnFixedCellClick event on a mouse-up message (in its overriden MouseUp method) without checking if there was a corresponding mouse-down message (FHotTrackCell.Pressed). A quick fix (if you can copy and modify Vcl.Grids): on line 4564 in Berlin (in TCustomGrid.MouseUp method add another condition to check, leading to the call to FixedCellClick):
if ... and FHotTrackCell.Pressed then
FixedCellClick(Cell.X, Cell.Y);
In other words, don't call FixedCellClick if a mouse-up comes without a prior corresponding mouse-down.
My question is how to set a column in dbgrid in Delphi 7 which will be with a checkbox items.
Thanks in advance.
The easiest and most complete method as tested by me is as follows:
In the private section of your unit, declare a global for retaining grid options. It will be used for restoring after temporary disabling text editing while entering the checkbox column - as this is maybe one of the little errors mentioned by Jordan Borisovin regarding the delphi.about.com article
private
GridOriginalOptions : TDBGridOptions;
In the OnCellClick event, if field is boolean, toggle and post change to database
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
if (Column.Field.DataType=ftBoolean) then
begin
Column.Grid.DataSource.DataSet.Edit;
Column.Field.Value:= not Column.Field.AsBoolean;
Column.Grid.DataSource.DataSet.Post;
end;
end;
Drawing the checkbox for boolean fields of the grid
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
CtrlState: array[Boolean] of integer = (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED) ;
begin
if (Column.Field.DataType=ftBoolean) then
begin
DBGrid1.Canvas.FillRect(Rect) ;
if (VarIsNull(Column.Field.Value)) then
DrawFrameControl(DBGrid1.Canvas.Handle,Rect, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_INACTIVE)
else
DrawFrameControl(DBGrid1.Canvas.Handle,Rect, DFC_BUTTON, CtrlState[Column.Field.AsBoolean]);
end;
end;
Now the new part, disable cell editing while in the boolean column. On the OnColEnter and OnColExit events:
procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
if Self.DBGrid1.SelectedField.DataType = ftBoolean then
begin
Self.GridOriginalOptions := Self.DBGrid1.Options;
Self.DBGrid1.Options := Self.DBGrid1.Options - [dgEditing];
end;
end;
procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
if Self.DBGrid1.SelectedField.DataType = ftBoolean then
Self.DBGrid1.Options := Self.GridOriginalOptions;
end;
Even more, handle space key for toggling the checkbox
procedure TForm1.DBGrid1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if ((Self.DBGrid1.SelectedField.DataType = ftBoolean) and (key = VK_SPACE)) then
begin
Self.DBGrid1.DataSource.DataSet.Edit;
Self.DBGrid1.SelectedField.Value:= not Self.DBGrid1.SelectedField.AsBoolean;
Self.DBGrid1.DataSource.DataSet.Post;
end;
end;
That's it!
If you're using the TClientDataset+TDatasetProvider+TDataset, you can manipulate the data array variant before it gets to the clientdataset and include an not updatable boolean field.
Once is done, all you need is to draw on the grid using the OnDrawColumnCell event. Here I doesn't used a CheckBox but just a bitmap (when user click it changes to selected/unselected).
Please excuse me for posting this as answer, I don't have the 50 reputation to add comments yet.
Mihai MATEI's answer is very close to the rare (as in really working) solution except for an use case where it bugs.
Whenever the users' first action on the grid is to click on the checkbox, the first click will work but the second will reveal the underlying DBGrid editor.
This happens because the "GridOriginalOptionsmechan" mechanism needs to be initialized.
To do so, just add the following code in the grid's OnEnter event:
procedure TForm1.DBGrid1Enter(Sender: TObject);
begin
DBGrid1ColEnter(Sender);
end;
That's it!
OK
I used this article for my problem. OK But the problem is that it wasn't working how it should. So I change my logic in the code. And implementing it by saving the selected rows from the dbgrid in a list.
I have added hints to components on my form. When the components receive the focus, I'd like to set the caption of a label component to display the hint.
I have added a TApplicationEvents object and set the OnShowHint event to
procedure TImportFrm.ApplicationEvents1ShowHint(var HintStr: string;
var CanShow: Boolean; var HintInfo: THintInfo);
begin
HelpLbl.Caption := HintStr;
end;
However it seems that the ShowHint event only fires with mouse movements. Is there a way to fire the hint code when components receive focus, without having to implement the OnEnter event for every single component on the form?
Add a handler for TScreen.OnActiveControlChange in your main form's creation, and handle the hints in that event:
type
TForm2=class(TForm)
...
private
procedure ScreenFocusControlChange(Sender: TObject);
end;
implementation
procedure TForm2.FormCreate(Sender: TObject);
begin
Screen.OnActiveControlChange := ScreenFocusControlChange;
end;
procedure TForm2.ScreenFocusControlChange(Sender: TObject);
begin
Label1.Caption := ActiveControl.Hint;
Label1.Update;
end;
Note that Sender won't do you much good; it's always Screen. You can filter (for instance, to only change the Label.Caption for edit controls) by testing the ActiveControl:
if (ActiveControl is TEdit) then
// Update caption of label with ActiveControl.Hint
Note that if you'll need to reassign the event when you show child forms (to an event on that child form), or you'll always be updating the original form's label with the hints. The easiest way to do the reassignment is to give every form an OnActiveControlChange handler, and assign it in the form's OnActivate event and unassign it in the OnDeactivate event:
procedure TForm1.FormActivate(Sender: TObject);
begin
Screen.OnActiveControlChange := Self.ScreenActiveControlChange;
end;
procedure TForm1.FormDeactivate(Sender: TObject);
begin
Screen.OnActiveControlChange := nil;
end;
This will allow you to update controls other than Label1 on each form, and only use the hint changes on forms you want to do so.
A simple solution is to use OnIdle event:
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
if Assigned(ActiveControl) then
Label1.Caption:= ActiveControl.Hint;
end;
A more advanced solution is to override protected ActiveChanged method of TForm:
type
TForm1 = class(TForm)
...
protected
procedure ActiveChanged; override;
end;
...
procedure TForm1.ActiveChanged;
begin
inherited;
if Assigned(ActiveControl) then
Label1.Caption:= ActiveControl.Hint;
end;
Receiving focus and OnShowHint are quite different events; OnShowHint can be triggered for non-focused control as well.
Why would you need to implement the OnEnter event for every single component? You can create one generic method / event handler like:
procedure TForm1.AnyControlEnter(Sender: TObject);
begin
lbl1.Caption := TControl(Sender).Hint;
end;
and assign it to every component you placed on the form.
You said:
it seems that the ShowHint event only fires with mouse movements
This is a normal behaviour. The problem you have ( it's a guess) is that hints are not fired directly. Don't try to make a workaround, what you try to do with MouseEnter is exactly what is already happening...the only difference is that you'be forget something...
Keep the event ApplicationEvents1ShowHint() as you've initially done but add this in the form constructor event:
Application.HintPause := 1;
And then hints will be displayed (almost) without delay.
This code is not working for me on Delphi XE:
http://delphi.about.com/cs/adptips2000/a/bltip0800_5.htm
procedure TForm1.FormDeactivate(Sender: TObject) ;
begin
ReleaseCapture;
end;
procedure TForm1.FormMouseMove
(Sender: TObject; Shift: TShiftState; X,Y: Integer) ;
begin
If GetCapture = 0 then
SetCapture(Form1.Handle) ;
if PtInRect(Rect(Form1.Left,
Form1.Top,
Form1.Left + Form1.Width,
Form1.Top + Form1.Height),
ClientToScreen(Point(x, y))) then
Form1.Caption := 'Mouse is over form' else
Form1.Caption := 'Mouse is outside of form';
end;
No errors - it just has no effect.
Please help.
EDIT 1
It turned out the problem is not with the code, even mouse FormMouseEnter and FormMouseLeave are not working because I'm passing the form to a Unit I created with a function like this:
procedure Slide(Form: TForm; Show: Boolean);
I'm calling the Show method from inside this procedure. How can I overcome this problem?
Thanks.
EDIT 2
I don't want to use the function I posted now. I want to use what the people suggested below (FormMouseEnter and FormMouseLeave) but it's not working in my case as well.
You could use OnMouseEnter and OnMouseLeave events to keep track of whether the mouse is over the form or not without capturing the mouse cursor.
This is just a matter of entering the necessary code in the OnMouseEnter and OnMouseLeave events of the corresponding form. In my case, all I did was :
Create a new project in Delphi
Select the form you are working with
Go to the Object Inspector
Switch to the Events tab in the object inspector if necessary
Scroll down to the OnMouseEnter event, double click in the white space next to it which will generate an EventHandler. Make sure you end up with the following code in the event handler :
procedure TForm1.FormMouseEnter(Sender: TObject);
begin
Self.Caption := 'Mouse in form';
end;
Go to the Object Inspector again
Find the OnMouseLeave event and double click in the white area to the right of it to generate a new event handler, and add the following code to it
procedure TForm1.FormMouseLeave(Sender: TObject);
begin
Self.Caption := 'Mouse outside form';
end;
Run the app ... move your mouse over the form and the caption will change to 'Mouse inside form', move it outside the form and the caption will say 'Mouse outside form'
Works as a charm (Tested in Delphi 2010)
As far as I understand, using SetCapture for this is a bad idea. If it functioned like you wish, you would be robbing everyone else of the mouse messages just because you don't know a better way to track mouse.
But MSDN says (http://msdn.microsoft.com/en-us/library/ms646262(VS.85).aspx) that even with SetCapture, mouse messages from outside would not be redirected to your window unless mouse button is down (probably a measure to prevent exactly what are you trying to achieve: stealing mouse without a valid reason).
It doesn't matter where are you calling Show() from, so your problem is not in that.
I needed a form (frmTasks) with a heavily modified Caption. So I created a form with a hidden Caption. I simulate the Caption with a TImage (imgRedLogo) on which I draw the stuff I need.
This code lets the user to click the fake caption (the image) and move the form around. Works like a charm WITHOUT capturing the mouse. It works even with the right mouse button (you have to test the 'Button' parameter in imgRedLogoMouseDown if you want to disable this 'feature').
FULL WORKING CODE:
VAR
Dragged : Boolean= FALSE;
IsOverImg: Boolean= FALSE; { True if mouse if over the image }
OldPos : TPoint;
procedure TfrmTasks.imgRedLogoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Dragged:= True;
GetCursorPos(OldPos);
end;
procedure TfrmTasks.imgRedLogoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
VAR NewPos: TPoint;
begin
if Dragged AND IsOverImg then
begin
GetCursorPos(NewPos);
frmTasks.Left:= frmTasks.Left- OldPos.X + NewPos.X;
frmTasks.Top := frmTasks.Top - OldPos.Y + NewPos.Y;
OldPos:= NewPos;
end;
end;
procedure TfrmTasks.imgRedLogoMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Dragged
then Dragged:= False;
end;
procedure TfrmTasks.imgRedLogoMouseEnter(Sender: TObject);
begin
IsOverImg:= TRUE;
end;
procedure TfrmTasks.imgRedLogoMouseLeave(Sender: TObject);
begin
IsOverImg:= FALSE;
end;
Enjoy.