Recent

Author Topic: Link Button-Counter with Start-Up Procedure  (Read 376 times)

AlphaInc.

  • New Member
  • *
  • Posts: 13
Link Button-Counter with Start-Up Procedure
« on: September 23, 2020, 09:31:47 am »
Hello Everybody,

I have a TButton which should have two different states for example On and Off. It’s default state should get set by a procedure which is executed when the program starts. To explain more what the Button does:

When I press the button it changes its caption to „Off“ and executes a CMD-Script. When I press it again it should set the Caption to „On“ and execute another script. When i press on the Button again it should set the Caption to „off“ again and so on.

The start-up procedure checks a config file which was created by me for a string and whether the string is present it sets the Caption to On (without executing the Script!). The only problem I still have is that in some cases, clicking the Button does not change the Caption because of the way it is implemented. I defined that the State „off“ is the first to come but when the procedure already sets the caption to „off“ (Because of the missing string) the caption won’t change until i click the button 2 times. I hope it get’s clear what I mean.

Therefore I’m looking for a better way to set the Caption of the button so that the Setup done by my start-up procedure will link with the two different states of my TButton.

This is my Code so far:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,
  9.   ShellAPI, StdCtrls, Buttons;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1:      TButton;
  17.     Memo1:        TMemo;
  18.  
  19.     procedure Button1Click(Sender: TObject);
  20.     procedure Memo1Change(Sender: TObject);
  21.     procedure versionCheck();
  22.  
  23.   private
  24.  
  25.   public
  26.     counter : byte;
  27.   end;
  28.  
  29.     Trec = record
  30.     cap, msg : string;
  31.     end;
  32.  
  33.     TInfo1 = array [0..1] of Trec;
  34.  
  35.  
  36. var
  37.     Form1: TForm1;
  38.  
  39. const
  40.     version : TInfo1        = ((cap:'On.'; msg:'On'),
  41.                                (cap:'Off.'; msg:'Off.'));
  42.  
  43. implementation
  44.  
  45. {$R *.lfm}
  46.  
  47. { TForm1 }
  48.  
  49. procedure TForm1.Button1Click(Sender: TObject);
  50. begin
  51.   ShellExecute(0,nil, PChar('cmd'),PChar('/c cd Binaries && start version.bat'),nil,1);
  52.   memo1.lines.add(version[counter].msg);
  53.  
  54.   inc(counter);
  55.   if counter = 2 then counter := 0;
  56.  
  57.   Button1.Caption := version[counter].cap;
  58. end;  
  59.  
  60.  
  61. procedure TForm1.versionCheck();
  62. var
  63.   MyFile: Text;
  64.   Line1: String;
  65. begin
  66.   AssignFile(MyFile, 'config.txt');
  67.   Reset(MyFile);
  68.   ReadLn(MyFile, Line1);
  69.   CloseFile(MyFile);
  70.   if Line1 = 'version   = remastered' then
  71.     Button1.Caption := 'On.'
  72.   else
  73.     Button1.Caption := 'Off.'
  74. end;      
                                               

Handoko

  • Hero Member
  • *****
  • Posts: 3866
  • My goal: build my own game engine using Lazarus
Re: Link Button-Counter with Start-Up Procedure
« Reply #1 on: September 23, 2020, 10:39:40 am »
You forgot to set a value for counter when program starts. If CheckVersion is always being called when program starts, it should set a value for counter there.

Because as you said the button only have 2 states: on and off. It is better to use var CurrentState: Boolean instead var counter: Byte.

You don't need to use batch script, Pascal should be able do what the batch script does. The disadvantage of using batch file is it can be easily modified or damaged by users.

Also as mentioned by howardpc, your code did not handle error properly. You should use exception block or IOResult.

AlphaInc.

  • New Member
  • *
  • Posts: 13
Re: Link Button-Counter with Start-Up Procedure
« Reply #2 on: September 23, 2020, 11:21:50 am »
Thank you for your reply. Can you Tell me how to set value for the counter and change it to Boolean? I‘m really sorry but I’m not really talented in programming.

Handoko

  • Hero Member
  • *****
  • Posts: 3866
  • My goal: build my own game engine using Lazarus
Re: Link Button-Counter with Start-Up Procedure
« Reply #3 on: September 23, 2020, 01:24:15 pm »
1. Don't make it public if it is not needed

Code: Pascal  [Select][+][-]
  1.   public
  2.     counter : byte;
  3.   end;

Above is your code. Do you have any reason why the counter is public? It is usually a good practice to set a property or variable to the lowest visibility. So instead of making it public, it is better to make it private:

Code: Pascal  [Select][+][-]
  1.   private
  2.     counter : byte;
  3.   end;

2. Replace counter with a boolean variable

Because there are only 2 states: on and off, it will be better to use a boolean-typed variable. Also I rename the counter to isRemastered, which is more meaningful. So the variable counter now becomes:

Code: Pascal  [Select][+][-]
  1.   private
  2.     isRemastered: Boolean;
  3.   end;

3. Change the declaration of TInfo1

Because we now use boolean instead of byte, we need to change the declaration of TInfo1:

Code: Pascal  [Select][+][-]
  1. type
  2.   TInfo1 = array[Boolean] of Trec;
  3.  
  4. const
  5.   Version: TInfo1 = ((cap:'Off.'; msg:'This is remastered version'),
  6.                      (cap:'On.';  msg:'This is original version'));

Also replace the texts for cap and msg to whatever you want.

4. Button1.OnClick should call VersionCheck

It should call VersionCheck, which will update the caption of the button:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   if isRemastered then
  4.   begin
  5.     // Do something if currenct version is remastered
  6.     //ShellExecute(...
  7.   end
  8.   else
  9.   begin
  10.     // Do something is currenct version is not remastered
  11.     //ShellExecute(...
  12.   end;
  13.   VersionCheck;
  14.   Memo1.Lines.Add(Version[isRemastered].msg);
  15. end;

5. VersionCheck need to be called when program starts

Your Form1.FormCreate should call VersionCheck, which will set the value for isRemastered and update the button's caption.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   VersionCheck;
  4. end;

6. The VersionCheck procedure

Your VersionCheck procedure should be something like this:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.VersionCheck;
  2. var
  3.   MyFile: Text;
  4.   Line1:  string;
  5. begin
  6.   // Read the config file
  7.   AssignFile(MyFile, 'config.txt');
  8.   Reset(MyFile);
  9.   ReadLn(MyFile, Line1);
  10.   CloseFile(MyFile);
  11.  
  12.   // Set the value for isRemastered
  13.   isRemastered := (Line1 = 'version = remastered');
  14.  
  15.   // Set the button's caption
  16.   Button1.Caption := Version[isRemastered].cap;
  17. end;

For your information, you set the Line1's value by checking the 'version = remastered' in the config file is not a good practice. The better solution is using TIniFile. Maybe you're not ready to try TIniFile, but remember to study it if you have time.

https://wiki.freepascal.org/Using_INI_Files

7. Bonus

Following the all 6 steps above, the code should work now. But your code for file reading can cause a serious issue if something bad happens when reading the file.

Below is try-except block added to VersionCheck procedure:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.VersionCheck;
  2. var
  3.   MyFile: Text;
  4.   Line1:  string;
  5. begin
  6.   // Load isRemastered's value from config file
  7.   AssignFile(MyFile, 'config.txt');
  8.   try
  9.     Reset(MyFile);
  10.     ReadLn(MyFile, Line1);
  11.     CloseFile(MyFile);
  12.     isRemastered := (Line1 = 'version = remastered');
  13.   except
  14.     ShowMessage('Error reading file');
  15.     isRemastered := False; // Set the default value if reading error
  16.   end;
  17.  
  18.   // Set the button's caption
  19.   Button1.Caption := Version[isRemastered].cap;
  20. end;

If you're not familiar with exception block you can use IOResult.

Read more:
https://wiki.freepascal.org/Exceptions
https://www.freepascal.org/docs-html/rtl/system/ioresult.html
« Last Edit: September 23, 2020, 06:22:10 pm by Handoko »

AlphaInc.

  • New Member
  • *
  • Posts: 13
Re: Link Button-Counter with Start-Up Procedure
« Reply #4 on: September 23, 2020, 04:43:58 pm »
Thank you very much for your detailed answer  :o
I will try it tomorrow since I’m not at home today.

AlphaInc.

  • New Member
  • *
  • Posts: 13
Re: Link Button-Counter with Start-Up Procedure
« Reply #5 on: September 25, 2020, 02:36:29 pm »
I tried your Code, Handoko but it does not work.
The Button Caption does not change wheter i press the button or not.

Handoko

  • Hero Member
  • *****
  • Posts: 3866
  • My goal: build my own game engine using Lazarus
Re: Link Button-Counter with Start-Up Procedure
« Reply #6 on: September 25, 2020, 02:41:45 pm »
I changed your line:
'version   = remastered'

Because it has extra spaces.

Also make sure your script is working correctly. Or show us the script.

 

TinyPortal © 2005-2018