Forum > Designer

Custom Component and Radio Group

(1/2) > >>

Aruna:
Hi, I have a custom component that runs Linux 'lsblk' command and then displays the output in a Tmemo. This part works. I want to give the user the ability to select any option in lsblk. The source code is below:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit lsblk; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Controls, StdCtrls, Process; type  { TLSB }  TLSB = class(TCustomControl)  private    FMemo: TMemo;    procedure DoRunCommand;  protected    procedure CreateWnd; override;  public    constructor Create(AOwner: TComponent); override;  published    property Align;    property Anchors;    property Font;    property ParentFont;    property ParentShowHint;    property ShowHint;    property TabOrder;    property TabStop;    property Visible;  end; procedure Register; implementation constructor TLSB.Create(AOwner: TComponent);begin  inherited Create(AOwner);  with GetControlClassDefaultSize do        SetInitialBounds(0, 0, 688, 150);   // Initialize the memo  FMemo        := TMemo.Create(Self);  FMemo.Parent := Self;  FMemo.Align  := alClient;//FMemo.Width  :=600;//FMemo.Height :=180;  FMemo.Font.Name:= 'Monospace';  //FMemo.ScrollBars := ssVertical;  //Run the command  DoRunCommand;end; procedure TLSB.CreateWnd;begin  inherited CreateWnd;  // Additional initialization if necessaryend; procedure TLSB.DoRunCommand;var  outstr: string;begin  RunCommand('lsblk', ['-S'], outstr); // @TRon's  FMemo.Lines.Add(outstr);end; procedure Register;begin  RegisterComponents('Linux Sysinfo', [TLSB]);end; end.How would one do this, please?

Right now I am using
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---RunCommand('lsblk', ['-S'], outstr); How would I use a RadioGrop to run the other flags/options/switches?

bobby100:
Make one more published property of string type for arguments, and use it instead of '-S' in the DoRunCommand.
Do not forget to initialize it to an empty string in the Create method.

Now, the RadioGroup is a part of your main program. You need to a procedure that will inspect the state(s) of the RadioGroup and according to it create a suitable string to pass to your component.

Aruna:

--- Quote from: bobby100 on August 31, 2024, 06:28:57 pm ---Make one more published property of string type for arguments, and use it instead of '-S' in the DoRunCommand.
Do not forget to initialize it to an empty string in the Create method.

Now, the RadioGroup is a part of your main program. You need to a procedure that will inspect the state(s) of the RadioGroup and according to it create a suitable string to pass to your component.

--- End quote ---
Thank you bobby100  I’m very new to object-oriented programming, I would greatly appreciate it if you could provide some example code to help me better understand the concepts.
If it's not too much trouble, could you please share some examples? Thank you very much for your help!

bobby100:
No problem to help you, but you need to share some more info with me about what your app should do etc.
2nd question - why did you put the part of the code into a separate component? I am referring to the other thread here on the forum.
I would go for a separate component if I have a GUI widget, or if there is a lot of reusable code to make sense for a separate component, unit or class.
If you are doing it for a learning experience - I can understand that, and I will help you.

I would begin with redesigning your component TLSB:
- chose a better name, LSB normally stays for Less Significant Bit. It can lead to some confusion.
- make it more universal, with published properties like Command and Arguments. This way you expand the usability of your component - run any terminal command with arguments and catch the output.

This is how I would do it:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit TerminalRun; {$mode ObjFPC}{$H+} interface uses  Classes, SysUtils, Controls, StdCtrls, Process; type  TTerminalRun = class(TCustomControl)  private    FCommand: string;    FArguments: string;    FMemo: TMemo;    function DoRunCommand: boolean;  protected    procedure CreateWnd; override;  public    constructor Create(AOwner: TComponent); override;    function Run: boolean;  published    property Command: string read FCommand write FCommand;    property Arguments: string read FArguments write FArguments;    property Align;    property Anchors;    property Font;    property ParentFont;    property ParentShowHint;    property ShowHint;    property TabOrder;    property TabStop;    property Visible;  end; procedure Register; implementation constructor TTerminalRun.Create(AOwner: TComponent);begin  inherited Create(AOwner);  with GetControlClassDefaultSize do    SetInitialBounds(0, 0, 688, 150);   // Initialize the memo  FMemo := TMemo.Create(Self);  FMemo.Parent := Self;  FMemo.Align := alClient;  FMemo.Font.Name := 'Monospace';   // Initialize the variables  FCommand := '';  FArguments := '';end; procedure TTerminalRun.CreateWnd;begin  // Do we really need this?  inherited CreateWnd;  // Additional initialization if necessaryend; function TTerminalRun.Run: boolean;begin  Result := False;  if FCommand <> '' then    Result := DoRunCommand;end; function TTerminalRun.DoRunCommand: boolean;var  outstr: string;begin  Result := RunCommand(FCommand, [FArguments], outstr); // @TRon's  if Result then    FMemo.Lines.Add(outstr)  else    FMemo.Lines.Add('Error executing command ' + FCommand + ' ' + FArguments);end; procedure Register;begin  RegisterComponents('Linux Sysinfo', [TTerminalRun]);end; end.
So, I've added two properties - Command and Arguments. I've added a function Run with feedback as boolean. I've converted your DoRunCommand to a function to get feedback. See, the RunCommand is also a function, so you can get a feedback if successfully run or not. We add some checks in Run function and also include this in final feedback. There are better ways to get the error info if the function did not succeed, but let leave it at this simple method for now.
Don't put DoRunCommand in Create method - this is a bad idea because it is also executed in the IDE, at design time. If your DoRunCommand triggers an exception, you will lock your IDE. With my new organization of the code, where you need to set the Command and the Arguments before Run, it won't work anyway. You need to take care about the code that it is executed also in the IDE at the design time, to not lock your IDE.
To use the component, one must set the command and the arguments, and execute the Run function after that. You do this from your main unit/form.

bobby100:
I just saw a mistake in my code. The FArguments is not a single string but an array. The way I've written it, it will take just one argument.

Navigation

[0] Message Index

[#] Next page

Go to full version