Recent

Author Topic: [Solved] Global Variable Not Visible In Another Unit  (Read 617 times)

Wilko500

  • New Member
  • *
  • Posts: 34
[Solved] Global Variable Not Visible In Another Unit
« on: April 02, 2021, 12:06:56 am »
Having read up on variable declaration and making it global I though I had grasped it, but no, I have not. I have read a number of posts with similar issue but have not found solutions so I need a hint as to what I have missed.

I have declared my global variable gChartIndex in the interface section of my main unit FcMain.  That should make it global and visible in other units.
Code: Pascal  [Select][+][-]
  1. unit FcMain;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.     Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
  9.     ExtCtrls, GroupsAndCharts, GetFileVerInfo, Printers,
  10.     Drawing, ChartSupport, ClsChartClasses;
  11. Var
  12.     gChartIndex:  Integer;       //Index of selected chart in ChartListView
  13. type
  14.  
  15.   { TfrmMain }
  16.  
  17.   TfrmMain = class(TForm)
  18.     Button1: TButton;
  19.    //Lots of definitions deleted from here from brevity
  20.     procedure OptGrpAllClick(Sender: TObject);
  21.     procedure OptGrpSelClick(Sender: TObject);
  22.  
  23.   private
  24.  
  25.   public
  26.  
  27.   end;      
  28.  

However in my Results unit I reference gChartIndex in procedure TfrmResults.cmdExitClick.  I added FcMain in the Implementation section to avoid a circular reference.  On running the value of gChartIndex is zero.  I also tried to prefix with unit name ie. as FcMain.gChartIndex but still the value is zero.  In both code chunks I have omitted procedures that are not involved to keep  the code as short as possible.  Help please.
Code: Pascal  [Select][+][-]
  1. unit Results;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, CheckLst,
  9.   ComCtrls, ExtCtrls;
  10.  
  11. type
  12.  
  13.   { frmResults }
  14.  
  15.   { TfrmResults }
  16.  
  17.   TfrmResults = class(TForm)
  18.     cmdPrint: TButton;
  19.     cmdExit: TButton;
  20.     cmdResPrint: TButton;
  21.     cmdResExit: TButton;
  22.     Edit1: TEdit;
  23.     Edit2: TEdit;
  24.     FramePrint: TGroupBox;
  25.     GroupBox1: TGroupBox;
  26.     Label1: TLabel;
  27.     Label2: TLabel;
  28.     ListView1: TListView;
  29.     ListViewResults: TCheckListBox;
  30.     OptPrintAll: TRadioButton;
  31.     OptPrintRange: TRadioButton;
  32.     OptPrintSel: TRadioButton;
  33.     procedure cmdExitClick(Sender: TObject);
  34.     procedure FormCreate(Sender: TObject);
  35.     procedure ListView1Click(Sender: TObject);
  36.   private
  37.  
  38.   public
  39.  
  40.   end;
  41.  
  42. var
  43.   frmResults: TfrmResults ;
  44.   strVisiblePage:   String;     //The visible page in results list
  45.   gResCheck:        Boolean;    //Set when resultls listview checkbox set/unset
  46.   gResIndex:        Integer;    //The index of selected item in results ListView
  47.  
  48. implementation
  49.  
  50. {$R *.lfm}
  51. Uses Drawing, FcMain ;
  52. { TfrmResults }
  53.  
  54. procedure TfrmResults.FormCreate(Sender: TObject);
  55. begin
  56.  
  57. end;
  58.  
  59. procedure TfrmResults.cmdExitClick(Sender: TObject);
  60. begin
  61.     //Close open charts
  62.     frmMain.GroupBox3.Visible:=True;
  63.     frmMain.ListViewCharts.SetFocus;
  64.     showMessage(gChartIndex.tostring);
  65.     frmMain.ListViewCharts.ItemIndex:=gChartIndex;
  66.     frmResults.Close;
  67.  
  68. end;
  69.  
« Last Edit: April 02, 2021, 11:08:09 am by Wilko500 »

jamie

  • Hero Member
  • *****
  • Posts: 4472
Re: Global Variable Not Visible In Another Unit
« Reply #1 on: April 02, 2021, 12:18:49 am »
I would say you got your assignment backwards...

The only true wisdom is knowing you know nothing

Zath

  • Sr. Member
  • ****
  • Posts: 363
Re: Global Variable Not Visible In Another Unit
« Reply #2 on: April 02, 2021, 12:29:14 am »
unit Results can't see your variable because you don't have unit FcMain declared in the uses clause of unit Results.


Wilko500

  • New Member
  • *
  • Posts: 34
Re: Global Variable Not Visible In Another Unit
« Reply #3 on: April 02, 2021, 12:31:41 am »
Its included in the implementation section.  If it's in the interface section I get a circular reference.

Wilko500

  • New Member
  • *
  • Posts: 34
Re: Global Variable Not Visible In Another Unit
« Reply #4 on: April 02, 2021, 12:32:50 am »
Sorry, I forgot to include the procedure where gChartIndex is assigned.
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.ListViewChartsClick(Sender: TObject);
  2. //ListViewCharts - Select action
  3. Var
  4.     gChartIndex:      Integer;
  5. begin
  6. If Assigned(ListViewCharts.Selected) Then  //Prevents access violation if clicking on space
  7.     Begin
  8.     //Save index of selection
  9.     gChartIndex:=ListViewCharts.ItemIndex;
  10.     //ShowMessage(index.tostring);
  11.     //Get ChartId and GroupId
  12.     gChId:=ListViewCharts.Selected.Caption;       //Get selected Chart Id
  13.     gGrpId:=ListViewCharts.Selected.SubItems[0];  //Get Selected Group Id
  14.     //Now create chart classes
  15.     CS:=TChartSettings.Create(gChid);     //Class of Chart Settings
  16.     CD:=TChartDetails.Create(gChid);   //Class of Chart Parameters
  17.     CG:=TChartGroup.Create(gGrpId);       //Class of Chart Group Details
  18.     //Display the chart's settings
  19.     LoadChartSettings(gChId);
  20.     //And enable the "Select" button
  21.     DoButtons(frmMain,'CmdCh', '0001');
  22. {EndIf}End;
  23. end; /code]

Wilko500

  • New Member
  • *
  • Posts: 34
Re: Global Variable Not Visible In Another Unit
« Reply #5 on: April 02, 2021, 12:36:14 am »
Ahhh!  Because it's in implementation it's private to unit Results????? Therefore not defined.

If so how to reference without circular reference?

egsuh

  • Hero Member
  • *****
  • Posts: 726
Re: Global Variable Not Visible In Another Unit
« Reply #6 on: April 02, 2021, 03:17:47 am »
Including the unit within uses clause in the implementation setcion is fine, unless you are accessing the variable within interface section. You have re-declared gChartIndex within procedure TfrmMain.ListViewChartsClick(Sender: TObject). In this case, it is regarded as local variable and global variable is not accessed within the procedure.

MarkMLl

  • Hero Member
  • *****
  • Posts: 2565
Re: Global Variable Not Visible In Another Unit
« Reply #7 on: April 02, 2021, 10:16:56 am »
Including the unit within uses clause in the implementation setcion is fine, unless you are accessing the variable within interface section. You have re-declared gChartIndex within procedure TfrmMain.ListViewChartsClick(Sender: TObject). In this case, it is regarded as local variable and global variable is not accessed within the procedure.

Agreed, provided that the code quoted in two messages is consistent. This isn't FORTRAN where you say that two variables are equivalent, you import the unit (which exports the global variable) and don't redefine.

On the rare occasion it's necessary I find a class helper to be a useful way of avoiding a circular reference:

Code: Pascal  [Select][+][-]
  1. unit cms50dpluscode;
  2.  
  3. interface
  4.  
  5. type
  6.   TCMS50DPlusForm = class(TForm)
  7. ...
  8.   protected
  9.     fcommsThread: TThread;
  10. ...
  11.   end;
  12.  
  13. var
  14.   CMS50DPlusForm: TCMS50DPlusForm;
  15.  
  16.  
  17. implementation
  18. ...
  19.  
  20. type
  21.   TcommsThread= class(TThread)
  22. ...
  23.   end;
  24.  
  25.   TCMS50DPlusFormH=                     (* Avoid circular definition            *)
  26.     class helper for TCMS50DPlusForm
  27.     protected
  28.       function CommsThread(): TCommsThread; inline;
  29.     end;
  30.  
  31.  
  32. (* This helper avoids problems with circular references, in particular many
  33.   occurrences of things like TCommsThread(CMS50DPlusForm.CommsThread).Synchronize()
  34.   in favour of the somewhat more concise CMS50DPlusForm.CommsThread.Synchronize().
  35. *)
  36. function TCMS50DPlusFormH.CommsThread(): TCommsThread; inline;
  37.  
  38. begin
  39.   result := fCommsThread as TcommsThread
  40. end { TCMS50DPlusFormH.CommsThread } ;
  41.  
  42. ...
  43.     CMS50DPlusForm.CommsThread.Synchronize(@CMS50DPlusForm.CommsThread.writerPlaybackShim)
  44. ...
  45.  

However in at least most cases you can achieve the same effect by careful choice of class structure.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Wilko500

  • New Member
  • *
  • Posts: 34
Re: Global Variable Not Visible In Another Unit
« Reply #8 on: April 02, 2021, 11:07:55 am »
Including the unit within uses clause in the implementation setcion is fine, unless you are accessing the variable within interface section. You have re-declared gChartIndex within procedure TfrmMain.ListViewChartsClick(Sender: TObject). In this case, it is regarded as local variable and global variable is not accessed within the procedure.
Thank you.  Problem fixed.  One of those cases when "you can't see the wood for the trees".   Now that you have pointed out the re-declaration I understand why it wasn't working.  The declaration started off in procedure TfrmMain.ListViewChartsClick(Sender: TObject) then got moved BUT I failed to comment it out as I had intended.

 

TinyPortal © 2005-2018