It happened quite few times that I needed to present data in the text terminal accessible under Debian 8 Linux Dist.
The data broadcast in the terminal has the advantage of being free from the IDLE and being able to run the Python program as a system command ( after cho).
Story short after I searched the Papa Internet I decided to try to build my own version which is a "copy" of an old menu program written in Turbo Pascal 7 under MS.DOS ( OK Millennials.. I hear it ...is too Elegant)
As you would expect even if I like and use Python (2.7) my Pascal experience makes the code slightly more conventional...
Program guide lines (philosophy):
1. Not too fancy - is only one level of menus (but opens for a lot of brances in selection)
2. The main menu is a top text bar in the terminal
3. Uses simple windows for delimiting the menu options
4. The outcome of the menu browsing is a numerical value called selector (.sel) which will allow the flow of the program to go further in the direction dictated by the programmer. The selector value is 100* Main menu sel + Submenu Sel (101...)
5. ( in other words if you make a selection and the selection drives the program further it is programmer responsibility).
6. The program should be easy to use and the main code should stay separate from the programmer code.
7 . The program will present a decent level of automation which will help the user to minimize the amount of code written for generating the menu,
8. The menu set-up can be done outside of the main source by using .txt "menu files" simple text files configuring the menu content interface.
9, For the first edition only key driven ( mouse will follow)
Implementation
The files which must be in the working folder :
( I called the folder PYM but doesn't matter, ..)
C_Menu_17.py - The main module file which contains the menu generating and navigation functions
C_ini.py - The Initial file, this file is very short and it has feew lines which can be modified, and is here where I would load any extra modules with import...
Start1.py - This file starts your program , basically nothing to do there eventually you can rename it as a new .py..
KY_1.py - this is a module for kye interpretation
TestBarMenu.txt - This file is named in C_ini.py and is the menu root generator . Will discuss...
The main element (object) used in the program is a window object which has a number of methods and variables.
The use of the program is simple, in the Python file called
C_ini.py
the string parameter 'TestBarMenu.txt' represents the text file which contains the options of the main menu.
This is an example of the C_ini.py :
T=TopMenu(FileName='TestBarMenu.txt')
The string naming the FieName is the main menu file, this is a file which has to be generated or modified by the user to reflect its main menu options in the program. The file MUST be in the working folder along with the other program files described above.
Will call the file TestBarMenu.txt in the future but can be named as you wish as long as you call it correctly in the FileName association.
The content of the main menu file from FileName contains in consecutive lines the name of different sub-menus .
For example the originally delivered file looks as:
1-Main 1
E-Exit
Those strings can be written and modified as the user wants , no limits in the number of lines. Think only to the max number of horizontal characters on your screen ... (I'm working on a self-scale procedure).
The last line should be 'Exit' which automatically is ending the main menu and the program (even if you call it otherwise...)
For the easiness of the use an automated procedure is called to generate the skeleton of the menus.
If the program is lanced first time after the main menu file was created it wil encounter an error if the sub-menu files do not exist and will self generate those file with a fixed number of lines and fixed names.
1-Main 1.txt
2-Main 2.txt
3-Main 3.txt
4-Main 4.txt
5-Main 5.txt
E-Exit.txt
Those files have by definition 7 option lines and Exit:
The 7 lines come from T.Gen(NL=7) option in the T.Gen command.
1 - Line1
2 - Line2
3 - Line3
4 - Line4
5 - Line5
6 - Line6
7 - Line7
E - Exit
The number of lines and the content can be changed as you wish, to the end of the day those are only "decorative" elements to guide the human thru the menu... the outcome of the choosing process is the selector...
NOTE: Be sure that you do not erase any of the sub-menu files which were generated originally (even if you do not use the main menu option associated at all) because as the C_ini is set, an error will generate an override of the menu files and some of your work can be lost... or eliminate the try..
From here the things can be simple or complex as you want.
The Start1.py program is lancing your created menu.
All menu applications should start with Start1.py (or a later version) . The top bar will appear on the screen and you can navigate and choose options.
You can exit a sub-menu by pressing ESC or Exit option , and same thing for the main menu will get you in the terminal back , stopping the program.
The Start1.py file is relatively longer than C_inin but really you do not need to get into it unless you want to change the way in which the main program is written)
O105.py (capital O not zero )
For example the file O101.py for sel=101 which display the CORE analogues is :
The soucescan be seen at at:
https://drive.google.com/drive/folders/1UfCQ0zvoftoghaovl6MyXGjysaeiuN7X?usp=sharing
Please let me know what you find.
Note , : As I continue to try to improve the menu system the latest files will be in the drive folder. and things can look slightly different.
In my mind the programs are simple enough that an average Python understanding will help you thru, otherwise, send an e-mail.
A late aid to the program are some text based bar graphs called bar , bar.drw() and bar_meter() which try to present an horizontal proportional graph with the in[put value.
The option 203 is genrating a "full graph' of the 11 channels added by the I2C Core hardware / software.
The program 401 option looks as :
The data broadcast in the terminal has the advantage of being free from the IDLE and being able to run the Python program as a system command ( after cho).
Story short after I searched the Papa Internet I decided to try to build my own version which is a "copy" of an old menu program written in Turbo Pascal 7 under MS.DOS ( OK Millennials.. I hear it ...is too Elegant)
As you would expect even if I like and use Python (2.7) my Pascal experience makes the code slightly more conventional...
![]() |
The Top Menu navigated with arrow keys (L/R) confirmed with ENTER |
Program guide lines (philosophy):
1. Not too fancy - is only one level of menus (but opens for a lot of brances in selection)
2. The main menu is a top text bar in the terminal
3. Uses simple windows for delimiting the menu options
4. The outcome of the menu browsing is a numerical value called selector (.sel) which will allow the flow of the program to go further in the direction dictated by the programmer. The selector value is 100* Main menu sel + Submenu Sel (101...)
5. ( in other words if you make a selection and the selection drives the program further it is programmer responsibility).
6. The program should be easy to use and the main code should stay separate from the programmer code.
7 . The program will present a decent level of automation which will help the user to minimize the amount of code written for generating the menu,
8. The menu set-up can be done outside of the main source by using .txt "menu files" simple text files configuring the menu content interface.
9, For the first edition only key driven ( mouse will follow)
![]() |
The option 3 was chooses, can be navigated with Up /Down keys confirmed with Enter |
![]() |
Navigated at option 305 ( see sel=305 in the lower line ) |
![]() |
The Option .sel 305 was chosen but is noting "to do" there ... |
![]() |
For .sel=101 we measure and display the inputs from the PIC I2C CORE hardware because the file O101.py exits |
![]() |
Plot of a sequence of 100 consecutive measurements ( from CORE ) |
Implementation
The files which must be in the working folder :
( I called the folder PYM but doesn't matter, ..)
C_Menu_17.py - The main module file which contains the menu generating and navigation functions
C_ini.py - The Initial file, this file is very short and it has feew lines which can be modified, and is here where I would load any extra modules with import...
Start1.py - This file starts your program , basically nothing to do there eventually you can rename it as a new .py..
KY_1.py - this is a module for kye interpretation
TestBarMenu.txt - This file is named in C_ini.py and is the menu root generator . Will discuss...
The main element (object) used in the program is a window object which has a number of methods and variables.
The use of the program is simple, in the Python file called
C_ini.py
the string parameter 'TestBarMenu.txt' represents the text file which contains the options of the main menu.
This is an example of the C_ini.py :
T=TopMenu(FileName='TestBarMenu.txt')
try:
T.Gen(NL=1)
except:
T.SelfGen()
The C_ini.py file can be used as the initial start of the program but it has few important lines:T=TopMenu(FileName='TestBarMenu.txt')
The string naming the FieName is the main menu file, this is a file which has to be generated or modified by the user to reflect its main menu options in the program. The file MUST be in the working folder along with the other program files described above.
Will call the file TestBarMenu.txt in the future but can be named as you wish as long as you call it correctly in the FileName association.
The content of the main menu file from FileName contains in consecutive lines the name of different sub-menus .
For example the originally delivered file looks as:
1-Main 1
E-Exit
Those strings can be written and modified as the user wants , no limits in the number of lines. Think only to the max number of horizontal characters on your screen ... (I'm working on a self-scale procedure).
The last line should be 'Exit' which automatically is ending the main menu and the program (even if you call it otherwise...)
For the easiness of the use an automated procedure is called to generate the skeleton of the menus.
If the program is lanced first time after the main menu file was created it wil encounter an error if the sub-menu files do not exist and will self generate those file with a fixed number of lines and fixed names.
1-Main 1.txt
2-Main 2.txt
3-Main 3.txt
4-Main 4.txt
5-Main 5.txt
E-Exit.txt
Those files have by definition 7 option lines and Exit:
The 7 lines come from T.Gen(NL=7) option in the T.Gen command.
1 - Line1
2 - Line2
3 - Line3
4 - Line4
5 - Line5
6 - Line6
7 - Line7
E - Exit
The number of lines and the content can be changed as you wish, to the end of the day those are only "decorative" elements to guide the human thru the menu... the outcome of the choosing process is the selector...
NOTE: Be sure that you do not erase any of the sub-menu files which were generated originally (even if you do not use the main menu option associated at all) because as the C_ini is set, an error will generate an override of the menu files and some of your work can be lost... or eliminate the try..
From here the things can be simple or complex as you want.
The Start1.py program is lancing your created menu.
All menu applications should start with Start1.py (or a later version) . The top bar will appear on the screen and you can navigate and choose options.
You can exit a sub-menu by pressing ESC or Exit option , and same thing for the main menu will get you in the terminal back , stopping the program.
The Start1.py file is relatively longer than C_inin but really you do not need to get into it unless you want to change the way in which the main program is written)
from C_Menu_17 import *
from KY_1 import *
T.Gen()
while True:
T.navigate()
T.drw()
w[T.sel].navigate()
WW.T=w[T.sel].T+' '+str(w[T.sel].sel)
WW.drw()
WW.B='Sel:'+str(w[T.sel].sel)
strg=str(int(w[T.sel].sel))
strg='O'+strg+'.py'
WW.B+= '>>s to go back,.py File:'+strg
WW.SendMsg()
#-----------------------------------------------------
try:
os.path.exists(strg)
execfile(strg)
except:
if os.path.exists(strg)==False:
WW.win.addstr(1,1,'FILE NOT PRESENT !!!!')
pass
#------------------------------------------------------
strg=''
WW.B=''
curses.flushinp()
WW.screen.nodelay(False)
WW.win.refresh()
WW.screen.getch()
WW.clr()
curses.endwin()
The catch here is that the Start program is looking for a file associated with your menu selection, for example if the selector was 105 then the file containing the Python sequences to be run is :O105.py (capital O not zero )
For example the file O101.py for sel=101 which display the CORE analogues is :
WW.clr()
WW.drw()
while AstRetC()!=115:
for i in range (12):
r=AN[i].Read_Stat(7)
WW.win.addstr( i+1,2,
'AN '+
format(i,'2.0f')+'|'+
format(r[0],'4.0f')+'|'+
format(r[1],'6.4f')+'[v]|'+
format(r[2],'6.4f')+'[v]|'+
format(r[3],'6.4f')+'|'+
format(r[4],'6.4f')+'|'+
format(r[5],'6.4f')+'|'
)
for i in range (11):
r=D[i].Read()
WW.win.addstr( i+1,63,('DIO'+str(r[0])
+' ')[0:5]+' '
+str(r[2])+'->'
+str(r[3])[0:5]+'')
WW.win.refresh()
Really the minimu should be as in O202.py:WW.B+= ' ** Press s to go back '
WW.SendMsg()
i=220
while AstRetC()!=115:
WW.win.addstr(2,2,str(i))
i+=1
WW.win.refresh()
This file is displaying in the window a counter srtating with 220 as long as s (ch(115) is not pressed.
The soucescan be seen at at:
https://drive.google.com/drive/folders/1UfCQ0zvoftoghaovl6MyXGjysaeiuN7X?usp=sharing
Please let me know what you find.
Note , : As I continue to try to improve the menu system the latest files will be in the drive folder. and things can look slightly different.
In my mind the programs are simple enough that an average Python understanding will help you thru, otherwise, send an e-mail.
A late aid to the program are some text based bar graphs called bar , bar.drw() and bar_meter() which try to present an horizontal proportional graph with the in[put value.
The option 203 is genrating a "full graph' of the 11 channels added by the I2C Core hardware / software.
The program 401 option looks as :
WW.clr()
WW.drw()
WW.B=''
WW.SendMsg()
curses.echo()
curses.curs_set(1)
curses.noecho()
curses.flushinp()
WW.B='Press s to exit up'
WW.SendMsg()
curses.curs_set(0)
Brm=bar_meter()
Brm.W=WW.win.getmaxyx()[1]-2
t0=time()
while AstRetC()!=115:
for s in range(11):
Brm.NT='AN '+format(s,'2.0f')+':'
r=AN[s].Read_Stat(5,PL='')
tt=time()-t0
Brm.V=r[1]
Brm.Y=3*s+2
Brm.drw_Meter()
Brm.win.addstr( 0,1,
'AN '+
format(s,'4.0f')+'|'+
format(r[0],'4.0f')+'|'+
format(r[1],'6.4f')+'[v]|'+
format(r[2],'6.4f')+'[v]|'+
format(r[3],'6.4f')+'|'+
format(r[4],'6.4f')+'|'+
format(r[5],'6.4f')+'|'+
format(tt,'8.4f')+'|'
)
Brm.win.refresh()
WW.win.refresh()
curses.curs_set(1)
The bar_meter object looks as (C_Menu20.py):
class bar_meter(object): def __init__(self,XM=1,YM=1,WM=80,HM=3,Vmax=5,V=0,NT='AN '): curses.initscr() curses.curs_set(0) curses.noecho() curses.flushinp() curses.cbreak() self.stdscr = curses.initscr() self.stdscr.keypad(1) self.stdscr.nodelay(False) self.X=XM self.Y=YM self.H=HM self.W=WM self.V=V self.Vmax=Vmax self.NT=NT self.sl='' self.sl0='' self.win=curses.newwin(self.H,self.W,self.Y,self.X) self.Ymax,self.Xmax=self.win.getmaxyx() def drw(self): self.win=curses.newwin(self.H,self.W,self.Y,self.X) self.win.box(0,0) self.win.refresh() def bar( self,SMB='|'): Lmax=self.W Lamp=Lmax-2-len(self.NT)-6 Ampl=Lamp Ampl=int((Ampl*self.V)/self.Vmax)-1 self.sl=self.NT+format(self.V,'6.4f')+Ampl*SMB+'<' self.sl0=(Lmax-2)*'+' return self.sl,self.sl0 def drw_Meter(self): curses.curs_set(0) self.drw() self.bar() self.win.addstr(1,1,self.sl0) self.win.addstr(1,1,self.sl,curses.A_REVERSE,) self.win.refresh() curses.curs_set(1)
The bar_meter in nothing else than a narrow horizontal window which is written using reverse spaces for "ploting" the value .
The data on the top is an adde or not line with addrstr(....) curses command.
Tha parameters are :
self, - object declaration
XM=1 - top right corner X,
YM=1,- same Y
WM=80, - window "width" or length.
HM=3, . window height - standard 3 lines (0,1,2)
Vmax=5, - max value in scale , min is 0 ( only pozitive values representation)
V=0, - input value (measured)
NT='AN ' - :"string Note" is what appears at the start of the bar
The Channel Analog 1 3 measurements for avg is presented in the bar graph, the instant value is 2.4009 V.
I added also a screen for ON/OFF DIO (right column):
The data on the top is an adde or not line with addrstr(....) curses command.
Tha parameters are :
self, - object declaration
XM=1 - top right corner X,
YM=1,- same Y
WM=80, - window "width" or length.
HM=3, . window height - standard 3 lines (0,1,2)
Vmax=5, - max value in scale , min is 0 ( only pozitive values representation)
V=0, - input value (measured)
NT='AN ' - :"string Note" is what appears at the start of the bar
The Channel Analog 1 3 measurements for avg is presented in the bar graph, the instant value is 2.4009 V.
![]() |
Bar representation of AN Channel 1 , value 2.4009 |
![]() |
Rather loaded screen for demo only but showing a large combination of meters |