Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advise on python data #757

Open
kpu979 opened this issue Aug 8, 2020 · 6 comments
Open

Advise on python data #757

kpu979 opened this issue Aug 8, 2020 · 6 comments

Comments

@kpu979
Copy link

kpu979 commented Aug 8, 2020

Im hoping to pick smarter people's brains on Python. If this isn't an appropriate forum, please delete this post (hopefully after you point me in the right direction ;) ).

Im trying to develop a menuing system so I can run programs from a menu once our main is run. It takes way too long for the main program to start, and in a competition, we'll not have this kind of time.

I need to create data records to be accessed like a table. Each record will have the menu number, line number, name and program to execute. As the up/down buttons are hit, the display will display accordingly like the file browser, and the center button will execute that line. Is this possible?

@WasabiFan
Copy link
Member

Hi!

First, you might find these threads and the associated documentation helpful (the first two links are discussion about creating the class documented at the last one):

It sounds like your use-case might be a good candidate for the Console class, especially if using micropython.

More generically, the data structure I would suggest for storing such menu items is a list, where each item is a class instance. You might define a class like so (fields are just guesses based on your description):

class MenuItem:
    def __init__(self, menu, line, name, program):
        self.menu = menu
        self.line = line
        # etc...

And then you'd define your menu items similar to this:

menu_items = [
    MenuItem(5, 10, "foo", "foo.py"),
    MenuItem(10, 3, "bar", "bar.py"),
]

You would then also store the index of the currently-focused item. When up is pressed, you decrement the index; when down is pressed, you increment it. Then re-draw the menu with the new item highlighted.

Does that help?

@kpu979
Copy link
Author

kpu979 commented Aug 9, 2020

This is EXACTLY what I was looking for. I found a few articles on this construct, but they were overly complicated and hard to understand.

One last question... Once the menu_items object is built, how do I access it?
cur_menu = 1
cur_line = 2
cur_name = menu_item[cur_menu,cur_line].name ( I know this isn't right... I just cannot figure out how to retrieve this)

@kpu979
Copy link
Author

kpu979 commented Aug 9, 2020

this is what I came up with (untested). Am I on the right track? ( i don't know how to format the below code so it appears correct... sorry :( )

class MenuItem:
    def __init__(self, menu, line,linename, linetype, lineprog):
        self.menu = menu
        self.line = line
        self.linename = linename
        self.linetype = linetype
        self.lineprog = lineprog


def getmenuitem(list,menu,line):
    #validations if menu is within range

    #validations if line is within range 

    #if all valid, find record
    for obj in list:
        if obj.menu == menu and obj.line == line:
            return list.linename, list.linetype, list.lineprog
        else:
            return 'xxx','x','xxx','xxx'


#setting up the menu
menu = []
menu.append(MenuItem(0,0,'M','Tools','1'))
menu.append(MenuItem(0,1,'M','Missions','2'))
menu.append(MenuItem(0,3,'P','DoIt','all_missions(eve)'))
menu.append(MenuItem(1,0,'P','AAASetup','aaasetup()'))
menu.append(MenuItem(1,1,'P','Calibratcs','calibratecs'))
menu.append(MenuItem(2,0,'P','mission01','mission01(eve)'))

cur_menu = 0
cur_line = 0
cur_tuple = getmenuitem(menu,cur_menu,cur_line)
cur_linename = cur_tuple[0]
cur_linetype = cur_tuple[1]
cur_linedisp = cur_tuple[2]
cur_lineprog = cur_tuple[3]

@kpu979
Copy link
Author

kpu979 commented Aug 10, 2020

ok, I fleshed out the rest of the code, but I have no way of actually executing it. Im not in possession of our EV3.

Again, I don't know how to post code that looks nice here, but I'll try.

#!/usr/bin/env python3

from ev3dev2.button import Button
from globals import debug_print
import time
import ev3dev2.fonts as fonts
from  ev3dev2.console import Console

class MenuItem:
    def __init__(self, menu, line,linename, linetype, lineprog):
        self.menu = menu
        self.line = line
        self.linename = linename
        self.linetype = linetype
        self.lineprog = lineprog

class Menu(object):
    def __init(self, menu = 0, line = 0,  **kwargs):
        self.menu = Menu
        self.line = line
 

    #sets buttons so when called and pressed will do what was coded to do once pressed
    def left(self,state):
        if state:
            #debug_print('Left button pressed')
            self.menu = self.menu -1
            if self.menu <0:
                self.menu = 0
        #else:
        #    debug_print('Left button released')
        self.refreshflag = True
        return 0

    def right(self,state):  
        if state:
            debug_print('right button pressed')
            #self.turret.on(speed=-45)
        #else:
            #debug_print('right button released')
            #self.turret.off()
        self.refreshflag = True
        return 0

    def up(self,state):
        if state:
            debug_print('Up button pressed')
            self.line = self.line -1
            if self.line <0:
                self.line = self.max_line
        #else:
            #debug_print('Up button released')
        self.refreshflag = True
        return 0

    def down(self,state):
        if state:
            debug_print('Down button pressed')
            self.line = self.line + 1
            if self.line > self.max_line:
                self.line = 0
        #else:
        #    debug_print('Down button released')
        self.refreshflag = True
        return 0

    def enter(self,state):
        if state:
            debug_print('Enter button pressed')
            if self.cur_linetype == 'M':
                self.cur_menu = int(self.cur_lineprog)
                self.cur_line = 0
            else:
                self.cur_lineprog    #this should run the function          
        #else:
        #    debug_print('Enter button released')
        self.refreshflag = True

    def getmenuitem(self,menulist,menu,line):
        for obj in menulist:
            if obj.menu == menu and obj.line == line:
                return menulist.linename, menulist.linetype, menulist.lineprog
            else:
                return 'xxx','x','xxx','xxx'
  
    def displaymenu(self,menulist,menuname, menu,line):
        lcdfontB = "Lat15-TerminusBold16"       
        lcd = Console(font=lcdfontB)

       #clear screen
        lcd.reset_console()
        #display menu name top center
        lcd.text_at(menuname, column=1,row=1, alignment="C",inverse=True)


        for obj in menulist:
            if obj.menu == menu:
                cur_tuple = self.getmenuitem(menu,obj.menu,obj.line)
                cur_linename = cur_tuple[0]

                lcd.text_at(cur_linename, column = 1,row=2+obj.line, alignment="C",inverse=(obj.line == line))

    def getmaxline(self,menulist,menu):
        maxline = 0
        for obj in menulist:
            if obj.menu == menu:
                if obj.line > maxline:
                    maxline = obj.line
        return maxline

    def runmenu(self):
        #set up menu names
        menuname = []
        menuname.append('Main')
        menuname.append('Tools')
        menuname.append('Missions')

        #setting up the menu lines
        menu = []
        menu.append(MenuItem(0,0,'M',menuname[1],'1'))
        menu.append(MenuItem(0,1,'M',menuname[2],'2'))
        menu.append(MenuItem(0,3,'P','DoIt','all_missions(eve)'))
        menu.append(MenuItem(1,0,'P','AAASetup','eve.aaasetup()'))
        menu.append(MenuItem(1,1,'P','Calibratcs','eve.calibratecs()'))
        menu.append(MenuItem(2,0,'P','mission01','mission01(eve)'))
        menu.append(MenuItem(2,1,'P','mission02','mission02(eve)'))
        menu.append(MenuItem(2,2,'P','mission03','mission03(eve)'))

        cur_menu = 0
        cur_line = 0
        refreshflag = True

        # set up button controls
        btn = Button()
        btn.on_left = self.left
        btn.on_right = self.right
        btn.on_up = self.up
        btn.on_down = self.down
        btn.on_enter = self.enter

        while True:
            if btn.check_buttons(buttons=['backspace']):
                break    
            #calculate max_line based on menu
            self.max_line = self.getmaxline(menu,cur_menu)

            #display menu on screen 
            if refreshflag:
                self.displaymenu(menu,menuname[cur_menu],cur_menu,cur_line)
                refreshflag = False

            btn.process() 
            cur_tuple = self.getmenuitem(menu,cur_menu,cur_line)
            #self.cur_linename = cur_tuple[0]
            self.cur_linetype = cur_tuple[1]
            self.cur_lineprog = cur_tuple[2]

            time.sleep(0.01)

@WasabiFan
Copy link
Member

I edited your post to format the code; see here for documentation on how to do that in the future: https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks

That looks very reasonable to me! I don't see any obvious problems, although there will likely be some debugging involved once you get it running.

Minor note -- it looks like this is supposed to be lowercase menu:

def __init(self, menu = 0, line = 0,  **kwargs):
        self.menu = Menu

@kpu979
Copy link
Author

kpu979 commented Aug 10, 2020

Thank you so much for your help. If I ever get a hold of an EV3 to debug this, I'll post the final code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants