Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 340
  • Last Modified:

Question

I have one form, a tabset, a panel, group box and group box contains few fields. I have attached the sample file to give idea on form structure.

Now when i click current tab of the tabset, i need the combo boxes to be visible and edit boxes invisible, and vice versa on click of previous tab.

Now the problem is there are lots of combo boxes and edit  boxes, that could even increase in future.

Hence i need to write some smart code which shall handle the component visibility dynamically.

Kindly respond with code snippets.
Unit1.dfm
Unit1.pas
0
AbhiJeet
Asked:
AbhiJeet
  • 8
  • 6
  • 5
  • +2
1 Solution
 
Ephraim WangoyaCommented:
Loop through the control list of the page and hide the controls
Here is an example of hiding TEdit

procedure TForm1. HideEditControls(AControl: TControl);
var
  I: Integer;
begin
  for I := 0 to AControl.ControlCount -1 do
     if AControl.Controls[I] is TGroupBox then
       HideEditControls(AControl.Controls[I]
     else if AControl.Controls[I] is TGroupBox then
       HideEditControls(AControl.Controls[I]
     else if AControl.Controls[I] is TEdit then
       ATabsheet.Controls[I].Visible := False;

Open in new window


To call the code, you can use the PageChangeEvent
procedure TForm1.PageControl1Change(Sender: TObject);
begin
  if PageControl1.ActivePage = tsPage1 then
    HideEditControls(PageControl1.ActivePage)
  else
  ...........
end;

Open in new window

0
 
Ephraim WangoyaCommented:
Sorry, here is the first code snippet

procedure TForm1. HideEditControls(AControl: TControl);
var
  I: Integer;
begin
  for I := 0 to AControl.ControlCount -1 do
     if AControl.Controls[I] is TGroupBox then
       HideEditControls(AControl.Controls[I])
     else if AControl.Controls[I] is TGroupBox then
       HideEditControls(AControl.Controls[I])
     else if AControl.Controls[I] is TEdit then
       AControl.Controls[I].Visible := False;
end;

Open in new window

0
 
AbhiJeetAuthor Commented:
lots of flaw in this code,

kindly can someone post tested code.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Sinisa VukCommented:
Why you don't use pagecontrol component? This will work as you wish - each page may have own components.
0
 
AbhiJeetAuthor Commented:
i dont want to change the design.
can someone post a cooment, how to do this.
0
 
developmentguruPresidentCommented:
OK, there are a number of things wrong with what you have going on here.  The first thing that became apparent is that not all of your controls are parented to the group box.  Several of the labels appeared to be parented to the form itself, and this will make any such automated code not function correctly.  If you make sure to cut all of your labels ([CTRL][X]), target the group box, and paste them back in (re-position as needed) then the following code will work as long as all of the labels and edits and combo boxes have the TAG property set to the index of the page you want them to appear on.  

procedure TForm1.TabSet1Change(Sender: TObject; NewTab: Integer;
  var AllowChange: Boolean);
var
  I : integer;
  Control : TControl;

begin
  for I := 0 to GroupBox2.ControlCount - 1 do
    begin
      Control := GroupBox2.Controls[I];
      Control.Visible := Control.Tag = tabset1.TabIndex;
    end;
end;

Open in new window


You should also call this once from the OnFormCreate since that will make it look right the first time it is displayed.

This becomes an increasing headache to maintain, not to mention having to deal with controls that are literally on top of each other.  The more correct way to handle this would be to use something like a page control (as mentioned by sinisav) or to make each one a separate TFrame.  Using frames you can make each set of visual controls independent, making them far easier to work with.  When the user changes the tabs you take the current frame and parent it to nil and take the one the user is switching to and parent it to the group box.  This gives the same effect of the page control, but lets you have independent code for each.

Let me know if you would like to see an example.
0
 
Geert GruwezOracle dbaCommented:
>>i dont want to change the design.
as indicated by developmentguru:
your design is flawed, so you will have to change it in some way anyway
regardless of any answers you get here

if this isn't a test scenario:
then someone forgot to rename the components
Form1, Label1, Edit1, GroupBox1 are difficult to link to frmCustomer, lblName, edName, gbAddress

using a pagecontrol automatically gives the behaviour you want

why would you want us to reinvent the wheel again ?
0
 
AbhiJeetAuthor Commented:
@developmentguru - appreciate the suggestion, but no luck as  tag is already being used throughout the code for other functionalities.
Any other way around please?
0
 
developmentguruPresidentCommented:
You have a mix of controls so judging them by type will not work.  You could make a string list with the names of the controls that are on each page. It would work like this:

Declare SL as a TStringList.

add these line to OnFormCreate

SL := TStringList.Create;
SL.Add('Label1,Label2,Label3,Label4,Edit1,Edit2,Edit3,Edit4');
SL.Add('Label5,Label6,Label7,Label8,ComboBox1,ComboBox2,ComboBox3,ComboBox4');

This in OnFormClose
SL.Free

When you switch between tabs you:
1) get the line from SL that matches your tab index
2) create a temp string list and set it's CommaText property to the line you just got
3) As you loop through the controls you compare IndexOf each controls name to see if it is in your string list.  If it is set visible to true, otherwise visible is false.

I hope that was enough to get you started as I may not have time to work up a full example until the weekend.
0
 
Ephraim WangoyaCommented:
Lots of flaws in the code!!
I would like to know where. This is very basic code for finding controls within a control.
I suggest you study it.

I did overlook one thing, simply use TPageControl as suggested by Geert_Gruwez.
You are just creating a maintenance headache with this approach.
Keep your code clean and simple
0
 
AbhiJeetAuthor Commented:
@developmentguru- complete example   please
0
 
Geert GruwezOracle dbaCommented:
from developmentguru:
add these line to OnFormCreate
SL := TStringList.Create;
// I added comma before and after the line ... see later
SL.Add(',Label1,Label2,Label3,Label4,Edit1,Edit2,Edit3,Edit4,');
SL.Add(',Label5,Label6,Label7,Label8,ComboBox1,ComboBox2,ComboBox3,ComboBox4,');
fVisibleTabIndex := 0;

Open in new window

This in OnFormClose
SL.Free

>> next you really want only 2 pieces of code and a parameter:
in the OnTabClick:
fVisibleTabIndex := Tab.Index;

type 
  TForm1 = class(TForm)
    // Etc ...   
  protected
    procedure UpdateActions; override;

procedure TForm1.UpdateActions;
var I: Integer;
  names: string;
begin
  inherited UpdateActions;
  names := SL[fVisibleTabIndex];
  for I := 0 to ComponentCount-1 do 
    SetVisible(Componets[I], Pos(','+Components[I].Name + ',', names) > 0);
end;

// Uses TypInfo;
procedure TForm1.SetVisible(aComponent: TComponent; aVisible: Boolean);
var
  PRecProp: PPropInfo;
  Vis: Boolean;
begin
  PRecProp := GetPropInfo(aComponent.ClassInfo, 'Visible');
  if Assigned(PRecProp) then
  begin
    Vis := GetOrdProp(aComponent, PrecProp);
    if Vis <> aVisible then 
      SetOrdProp(aComponent, PRecProp, aVisible);
  end;
end;

Open in new window

0
 
AbhiJeetAuthor Commented:
where is this class PPropInfo is defined?
0
 
developmentguruPresidentCommented:
PPropInfo is defined in the TypInfo unit.
0
 
Geert GruwezOracle dbaCommented:
line 17 was very important
// Uses TypInfo;

every line in code usually is ... unless it's useless
0
 
Geert GruwezOracle dbaCommented:
one more thing, be very carefull with UpdateActions

slow code in this procedure can simply kill your application

if you want to see the impact:
just add a sleep in the UpdateActions

procedure TForm1.UpdateActions;
begin
  inherited UpdateActions;
  Sleep(1000);
end;
0
 
AbhiJeetAuthor Commented:
this line is not working
Vis := GetOrdProp(aComponent, PrecProp);

vis is boolean and getordprop is  returning integer,
0
 
Geert GruwezOracle dbaCommented:
use boolean algebra to solve that

Vis := GetOrdProp(aComponent, PrecProp) <> 0;
0
 
AbhiJeetAuthor Commented:
SetOrdProp(aComponent, PRecProp, aVisible);

stuck with this line now.
0
 
AbhiJeetAuthor Commented:
@developmentguru - could you please post your full code example?
0
 
Geert GruwezOracle dbaCommented:
stuck with this line now.
you'll get stuck with a lot of lines

>> that's what we were trying to indicate when we said the design was flawed

The solution: a good design with a pagecontrol

but ... you don't have to take our word for it
0
 
developmentguruPresidentCommented:
I should be able to tomorrow.
0
 
developmentguruPresidentCommented:
I have changed your design a little bit.  I made sure both group boxes were parented to Panel1.  I also found out that one of the panels had edits under the combo boxes which made the results... hard to see.  I removed those edits but, if you want them back, then it would be easy to do.  In this design you can have any number of group boxes representing your tabs.  The group boxes MUST be named GroupBox1 for tab 0, GroupBox2 for tab1, etc.

Let me know what you think.

---DFM---
object Form1: TForm1
  Left = 192
  Top = 114
  Caption = 'Form1'
  ClientHeight = 464
  ClientWidth = 854
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Panel1: TPanel
    Left = 64
    Top = 56
    Width = 505
    Height = 265
    Caption = 'Panel1'
    TabOrder = 0
    object GroupBox1: TGroupBox
      Left = 8
      Top = 8
      Width = 489
      Height = 241
      Caption = 'GroupBox1'
      TabOrder = 0
      object Label1: TLabel
        Left = 24
        Top = 24
        Width = 32
        Height = 13
        Caption = 'Label1'
      end
      object Label2: TLabel
        Left = 286
        Top = 24
        Width = 32
        Height = 13
        Caption = 'Label1'
      end
      object Label3: TLabel
        Left = 25
        Top = 54
        Width = 32
        Height = 13
        Caption = 'Label1'
      end
      object Label4: TLabel
        Left = 287
        Top = 54
        Width = 32
        Height = 13
        Caption = 'Label1'
      end
      object Edit1: TEdit
        Left = 136
        Top = 24
        Width = 121
        Height = 21
        TabOrder = 0
        Text = 'Edit1'
      end
      object Edit2: TEdit
        Left = 366
        Top = 24
        Width = 121
        Height = 21
        TabOrder = 1
        Text = 'Edit1'
      end
      object Edit3: TEdit
        Left = 137
        Top = 54
        Width = 121
        Height = 21
        TabOrder = 2
        Text = 'Edit1'
      end
      object Edit4: TEdit
        Left = 361
        Top = 54
        Width = 121
        Height = 21
        TabOrder = 3
        Text = 'Edit1'
      end
    end
    object GroupBox2: TGroupBox
      Left = 0
      Top = 0
      Width = 489
      Height = 241
      Caption = 'GroupBox1'
      TabOrder = 1
      object Label5: TLabel
        Left = 24
        Top = 24
        Width = 41
        Height = 13
        Caption = 'reading1'
      end
      object Label6: TLabel
        Left = 286
        Top = 24
        Width = 41
        Height = 13
        Caption = 'reading2'
      end
      object Label7: TLabel
        Left = 25
        Top = 54
        Width = 41
        Height = 13
        Caption = 'reading3'
      end
      object Label8: TLabel
        Left = 287
        Top = 54
        Width = 41
        Height = 13
        Caption = 'reading4'
      end
      object cmbread1: TComboBox
        Left = 184
        Top = 24
        Width = 73
        Height = 21
        TabOrder = 0
      end
      object cmbread2: TComboBox
        Left = 392
        Top = 24
        Width = 89
        Height = 21
        TabOrder = 1
      end
      object cmbread3: TComboBox
        Left = 176
        Top = 56
        Width = 73
        Height = 21
        TabOrder = 2
      end
      object cmbread4: TComboBox
        Left = 392
        Top = 56
        Width = 89
        Height = 21
        TabOrder = 3
      end
    end
  end
  object TabSet1: TTabSet
    Left = 64
    Top = 320
    Width = 505
    Height = 21
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    Tabs.Strings = (
      'Current'
      'Previous')
    TabIndex = 0
    OnChange = TabSet1Change
  end
end

Open in new window


---PAS---
unit frmMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Tabs, Generics.Collections;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    GroupBox2: TGroupBox;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    cmbread1: TComboBox;
    cmbread2: TComboBox;
    cmbread3: TComboBox;
    cmbread4: TComboBox;
    TabSet1: TTabSet;
    procedure TabSet1Change(Sender: TObject; NewTab: Integer;
      var AllowChange: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    fPageControls : TObjectList<TStringList>;

    procedure ShowControlsByGroupBox(NewTab : integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  NewPageControls : TStringList;
  I : Integer;
  GroupBox : TGroupBox;

begin
  {This is important to the success of the ShowControlsByGroupBox.  This will
   allow the developer to move the various group boxes around to organize
   controls, knowing that this code will put the group boxes back in alignment.

   Each group box must be directly parented to Panel1 in order for this to work}
  for I := 0 to Panel1.ControlCount - 1 do
    if Panel1.Controls[I] is TGroupBox then
      begin
        GroupBox := Panel1.Controls[I] as TGroupBox;
        GroupBox.Align := alClient;
      end;
  ShowControlsByGroupBox(0); //initialize the screen
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  fPageControls.Free;
end;

procedure TForm1.ShowControlsByGroupBox(NewTab : integer);
var
  SearchName : string;
  GroupBox : TGroupBox;
  NameMatches : boolean;
  I : integer;

begin
  SearchName := 'GroupBox' + IntToStr(Succ(NewTab));

  for I := 0 to Panel1.ControlCount - 1 do
    if Panel1.Controls[I] is TGroupBox then
      begin
        GroupBox := Panel1.Controls[I] as TGroupBox;
        NameMatches := GroupBox.Name = SearchName;
        if NameMatches then
          GroupBox.BringToFront;
      end;
end;

procedure TForm1.TabSet1Change(Sender: TObject; NewTab: Integer;
  var AllowChange: Boolean);
begin
  ShowControlsByGroupBox(NewTab);
end;

end.

Open in new window

0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 8
  • 6
  • 5
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now