I'm doing a toggle switch, that when I click it changes its On/off state, I created it by overriding the Paint method in TCanvas, everything fine but the borders looked pixelated.
So I modified the component to load an image for each state depending on the checked of the image, in short I'm putting a TImage component inside a Checkbox inherited from TwwCheckbox
But when the image is pressed/clicked/checked, the Checked changes its state to true but it doesn't show the state that was saved in the database the next time I reopen the form, I mean, if I activate the toggle it is saved with an S and when opening the form where the Toggle is, it should be On and not off
{here I create the toggle in runtime and assign it a datasource
to connect it to the database}
procedure TForm1.FormCreate(Sender: TObject);
begin
ToggleButton:= TinToggleButton2.Create(Self);
ToggleButton.Name := 'ToggleButton';
ToggleButton.Parent:= Self;
ToggleButton.Left:= 200;
ToggleButton.Top:=100;
ToggleButton.Visible:= true;
ToggleButton.ValueChecked:= 'S';
ToggleButton.ValueUnchecked:= 'N';
ToggleButton.DisplayValueChecked:= 'S';
ToggleButton.DisplayValueUnchecked:= 'N';
ToggleButton.DataField:= 'TAutoSave';
ToggleButton.DataSource:= dsToggleButton;
ToggleButton.DataSource.DataSet:= qryToggleButton;
end;
//here the query
procedure TForm1.Button1Click(Sender: TObject);
begin
qryToggleButton.Active:= true;
end;
//i send the data to database
procedure TForm1.Button2Click(Sender: TObject);
begin
qryToggleButton.Post;
end;
{here I create the component in another unit where the click event is
to switch between image}
constructor TinToggleButton2.Create(AOwner: TComponent);
begin
inherited;
Width:= 34;
Height:= 15;
Image:= TImage.Create(Self);
Image.Visible:= true;
Image.Picture.LoadFromFile('toggle_Toggle1.ico');
Image.Parent:= Self;
Image.OnClick:=Self.Image1Click;
Self.Checked:= false;
Checked:= false;
end;
procedure TinToggleButton2.Image1Click(Sender: TObject);
begin
if DataSource <> nil then
begin
DataSource.Edit;
if Self.Checked then
begin
Self.Checked:= false;
DataSource.DataSet.FieldByName(DataField).Value:= ValueUnchecked;
Image.Picture.LoadFromFile('toggle_Toggle1.ico');
end
else
begin
Self.Checked:= true;
DataSource.DataSet.FieldByName(DataField).Value:= ValueChecked;
Image.Picture.LoadFromFile('toggle_Toggle2.ico');
end;
end;
end;
I create the toggle in runtime but I put the other components such as the TwwDataSource and the TADOQuery in the form and I assign the DataField and the DataSource to the checkbox
Related
Is there a Windows API for setting up a custom cursor for the form's title bar, system menu icon and minimize, maximize and close buttons?
I'm having a function for loading and setting cursors for a given control:
type
TFrm_Main = class(TForm)
....
private
procedure SetCursor_For(AControl: TControl; ACursor_FileName: string;
Const ACurIndex: Integer);
...
end;
const
crOpenCursor = 1;
crRotateCursor = 2;
crCursor_Water = 3;
var
Frm_Main: TFrm_Main;
...
procedure TFrm_Main.SetCursor_For(AControl: TControl; ACursor_FileName:
string; const ACurIndex: Integer);
begin
Screen.Cursors[ACurIndex] := Loadcursorfromfile(PWideChar(ACursor_FileName));
AControl.Cursor := ACurIndex;
end;
And I'm using it this way for the form:
SetCursor_For(Frm_Main, 'Cursors\Cursor_Rotate.ani', crRotateCursor);
But I'm missing a way to setup cursor for particular form parts like form title bar, system menu icon and minimize, maximize and close buttons. Is there a way to set cursor for these form parts?
Handle the WM_SETCURSOR message and test the message parameter's HitTest field for one of the following hit test code values, and set the cursor by using SetCursor function returning True to the message Result (Windows API macros TRUE and FALSE coincidentally match to the Delphi's Boolean type values, so you can only typecast there):
HTCAPTION - Title bar
HTSYSMENU - System menu icon
HTMINBUTTON - Minimize button
HTMAXBUTTON - Maximize button
HTCLOSE - Close button
For example:
type
TForm1 = class(TForm)
private
procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
end;
implementation
procedure TForm1.WMSetCursor(var Msg: TWMSetCursor);
begin
case Msg.HitTest of
HTCAPTION:
begin
Msg.Result := LRESULT(True);
Winapi.Windows.SetCursor(Screen.Cursors[crHandPoint]);
end;
HTSYSMENU:
begin
Msg.Result := LRESULT(True);
Winapi.Windows.SetCursor(Screen.Cursors[crHelp]);
end;
HTMINBUTTON:
begin
Msg.Result := LRESULT(True);
Winapi.Windows.SetCursor(Screen.Cursors[crUpArrow]);
end;
HTMAXBUTTON:
begin
Msg.Result := LRESULT(True);
Winapi.Windows.SetCursor(Screen.Cursors[crSizeAll]);
end;
HTCLOSE:
begin
Msg.Result := LRESULT(True);
Winapi.Windows.SetCursor(Screen.Cursors[crNo]);
end;
else
inherited;
end;
end;
I have numerous procedures which dynamically create a TButton when the user clicks a button. The following code is an example of this:
procedure TForm1.Button2Click(Sender: TObject);
begin
if not Assigned(FSeatButton) then begin
FSeatButton := TButton.Create(self);
FSeatButton.Parent := self;
FSeatButton.Left := 100;
FSeatButton.Top := 100;
FSeatButton.Width := 62;
FSeatButton.Height := 25;
FSeatButton.Caption := ('Seat');
FSeatButton.OnMouseDown := ButtonMouseDown;
FSeatButton.OnMouseMove := ButtonMouseMove;
FSeatButton.OnMouseUp := ButtonMouseUp;
end;
end;
This creates a Tbutton which the user can then drag around through the bottom 3 procedures. I need this procedure to repeat every time a user clicks button2 but if I use a for/repeat loop id have to specify when to end it, but i don't know how many Buttons the user will need to generate.
Also (This could be an idea for another question), how would i save each button created with its own ID as such E.G Button1, Button2... ButtonN. I'm guessing I'd need some sort of variable that increases every time the user clicks the button and it is somehow included in the name E.G ButtonI
It sounds like you just need to keep track of all the buttons that have been added. Use a container to do so:
In the type declaration add a container:
uses
System.Generics.Collections;
....
FButtons: TList<TButton>;
Instantiate it in the form's constructor, and destroy it in the destructor. Or use the OnCreate and OnDestroy events if you prefer.
Then when you create the button, add it to the list:
procedure TForm1.Button2Click(Sender: TObject);
var
Button: TButton;
begin
Button := TButton.Create(self);
Button.Parent := Self;
Button.Left := 100;
// etc.
FButtons.Add(Button);
end;
If you don't need to refer to the buttons after creating them then you don't need the list and you can just do this:
procedure TForm1.Button2Click(Sender: TObject);
var
Button: TButton;
begin
Button := TButton.Create(self);
Button.Parent := Self;
Button.Left := 100;
end;
Declare FSeatButton : array of TButton;
That way you have an unique instance of the added buttons and can name them in consecutive order.
Every time Button2 is clicked add a new button to the array:
procedure TForm1.Button2Click(Sender: TObject);
var
len: Integer;
begin
len := Length(FSeatButton);
SetLength(FSeatButton,len+1);
FSeatButton[len] := TButton.Create(self);
FSeatButton[len].Name := 'SeatButton'+IntToStr(len);
etc...
end;
I have a Firemonkey multi device project in Delphi 10 Seattle where the user can get a screen at the start of the app. Here the user needs to fill in 2 fields. But when I click on the edit fields the Virtual Keyboard isn't shown. If I skip this screen at start and call it later then the Virtual Keyboard is shown. This is done in the same way too.
I found sort of a solution:
When i click on the edit fields i call show VirtualKeyboard myself. The only problem is that the cursor isn't shown in the edit field.
Is there a way to place the cursor myself? Or does anyone know how to solve the Virtual Keyboard not showing problem in an other way?
Problem is on both Android and iOS
In the code below you can see the initial form create. The problem is when in ConnectFromProfile method the actCreateNewProfileExecute is called. There it will call a new form. In that form(TfrmProfile) the virtual keyboard isn't shown. I also call this form with another action and then it works fine.
procedure TfrmNocoreDKS.FormCreate(Sender: TObject);
begin
Inherited;
System.SysUtils.FormatSettings.ShortDateFormat := 'dd/mm/yyyy';
CheckPhone;
ConnectfromProfile;
if not Assigned(fProfileAction) then
ConnectDatabase
Else
lstDocuments.Enabled := False;
{$IFDEF ANDROID}
ChangeComboBoxStyle;
{$ENDIF}
end;
procedure TfrmNocoreDKS.ConnectfromProfile;
begin
fdmProfileConnection := TdmConnection.Create(nil);
fdmProfileConnection.OpenProfileDb;
fdmProfileConnection.LoadProfiles;
if fdmProfileConnection.Profiles.Count = 0 then
begin // Createdefault Profile
fProfileAction := actCreateNewProfileExecute;
end
else if fdmProfileConnection.Profiles.Count = 1 then
begin // one profile load connection;
fProfileAction := nil;
fCurrentProfile := fdmProfileConnection.Profiles.Items[0];
end
else
begin // multiple profiles choose connection;
fProfileAction := SelectProfileOnStartUp;
end;
end;
procedure TfrmNocoreDKS.FormShow(Sender: TObject);
begin
if Assigned(fProfileAction) then
fProfileAction(Self);
end;
procedure TfrmNocoreDKS.actCreateNewProfileExecute(Sender: TObject);
var
profilename, databasename, pathname: string;
prf: TfrmProfile;
begin
prf := TfrmProfile.Create(nil);
prf.Data := fdmProfileConnection.Profiles;
prf.ShowModal(
procedure(ModalResult: TModalResult)
begin
if ModalResult = mrOk then
begin
profilename := prf.edtProfilename.Text;
databasename := prf.edtDatabaseName.Text;
{$IFDEF IOS}
pathname := System.IOUtils.TPath.GetDocumentsPath;
{$ENDIF}
{$IFDEF ANDROID}
pathname := System.IOUtils.TPath.GetDocumentsPath;
{$ENDIF}
{$IFDEF WIN32}
pathname := ExtractFilePath(ParamStr(0)) + '\Data';
{$ENDIF}
FDSQLiteBackup1.Database := System.IOUtils.TPath.Combine(pathname,
'default.sqlite3'); // Default Database
FDSQLiteBackup1.DestDatabase := System.IOUtils.TPath.Combine(pathname,
databasename + '.sqlite3');
FDSQLiteBackup1.Backup;
fdmProfileConnection.AddProfile(databasename + '.sqlite3', profilename);
fdmProfileConnection.LoadProfiles;
fCurrentProfile := fdmProfileConnection.Profiles.Items[0];
connectDatabase;
end else
Application.Terminate;
end);
end;
Do not show any additional forms in MainForm.OnCreate/OnShow. Trying this on iOS 9.2 freeze app at "launch screen".
Instead of this, show new form asynchronously, like this:
procedure TForm4.FormShow(Sender: TObject);
begin
TTask.Run(procedure
begin
TThread.Synchronize(nil, procedure // work with visual controls - only throught Synchronize or Queue
begin
Form5:=TForm5.Create(Application);
Form5.ShowModal;
end)
end);
end;
of cource, you can separate this code to external procedures:
procedure ShowMyForm;
begin
Form5:=TForm5.Create(Application);
Form5.ShowModal;
end;
procedure TaskProc;
begin
TThread.Synchronize(nil, ShowMyForm);
end;
procedure TForm4.FormShow(Sender: TObject);
begin
TTask.Run(TaskProc);
end;
========
Another way - do not use any additional forms. Create frame and put it (at runtime) on MainForm with Align = Contents. After all needed actions - hide or release (due to ARC dont forget to set nil to frame variable) this frame.
In my Delphi XE2 Project, I am having Form1, Label1 and CheckBox1.
My requirement is to set the CheckBox1.Font.Color := clGreen;.
Thought I have written
procedure TForm1.FormCreate(Sender: TObject);
begin
CheckBox1.Font.Color := clGreen;
end;
yet the Font Color is default Black. So I have defined it in other way as follows:
I have removed the Caption from the CheckBox1 and changed the Width to 17.
Then I have placed Label1 next to CheckBox1 like CleckBox1 Caption.
After that I have written:
procedure TForm1.Label1Click(Sender: TObject);
begin
CheckBox1.Click;
end;
to Toggle the state of CheckBox1.
But I am getting [DCC Error] Unit1.pas(37): E2362 Cannot access protected symbol TCustomCheckBox.Click.
And another question is that whether the OnMouseDown Event of CheckBox1 can be triggered as the following image:
The Click() method merely triggers the contro's OnClick event, nothing else. It does not actually cause the control to perform click-related logic, like updating its internal state.
You can toggle the CheckBox's state like this:
CheckBox1.Checked := not CheckBox1.Checked;
Alternatively, use an accessor class to reach protected members:
type
TCheckBoxAccess = class(TCheckBox)
end;
TCheckBoxAccess(CheckBox1).Toggle;
You can use it like :
procedure TForm1.Label1Click(Sender: TObject);
begin
//either
CheckBox1.Checked := not CheckBox1.Checked; // this trigger onClick event!!
// or
// if you absolutely need it..
CheckBox1Click(Sender); // NOTE this will not check or uncheck CheckBox1
end;
But note you use here a TLabel Object (Sender). If you do not use Sender you can do it Without further attention.
But it's better to put the code for enable and disable other control out of the event. only one line for example doenable() .
procedure TForm1.doEnable(enable: Boolean);
begin
Edit1.Enabled := enable;
Edit2.Enabled := enable;
Edit3.Enabled := NOT enable;
if enable then Label1.Font.Color := clGreen else Label1.Font.Color := clWindowText;
...
end;
procedure TForm1.Label1Click(Sender: TObject);
begin
// NOTE This trigger also CheckBox1 Click event.
CheckBox1.Checked := not CheckBox1.Checked;
// NOT needed.
//if CheckBox1.Checked then doEnable(true) else doEnable(false);
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
if CheckBox1.Checked then doEnable(true) else doEnable(false);
end;
mybox.Checked := true;
Setting TRadioButton to checked (by code) causes OnClick event handler to be called.
How can I recognize if user is making the state change by GUI interaction
You can nil the OnClick event handler while changing a radiobutton state programmatically:
procedure TForm1.Button6Click(Sender: TObject);
var
Save: TNotifyEvent;
begin
Save:= RadioButton2.OnClick;
RadioButton2.OnClick:= nil;
RadioButton2.Checked:= not RadioButton2.Checked;
RadioButton2.OnClick:= Save;
end;
mybox.Tag := 666;
mybox.Checked :=true;
mybox.Tag := 0;
procedure myboxOnclick(Sender : TObject);
begin
if Tag = 0 then
//Do your thing
end;
If you have an action connected to the radiobutton, you can set the checked property of the action instead. This will also prevent the OnClick event to be fired.
TRadioButton (like TCheckBox) provides a protected property ClicksDisabled that can help you.
I use class helpers to add the needed functionality:
RadioButton1.SetCheckedWithoutClick(False);
with the following class helper for a VCL TRadioButton:
TRadioButtonHelper = class helper for TRadioButton
procedure SetCheckedWithoutClick(AChecked: Boolean);
end;
procedure TRadioButtonHelper.SetCheckedWithoutClick(AChecked: Boolean);
begin
ClicksDisabled := True;
try
Checked := AChecked;
finally
ClicksDisabled := False;
end;
end;