Is this way of handling a module correct?

I made a module to manage the menus of an lcd display.

The number of options is quite large so I plan to use this file as a module to import into a file that integrates other issues.

And my question goes this way. For example, when I select to log in to a page in the menu, what I do in the menu is put a variable that when entering that option becomes true.

So in the main file I have something like:

import menus

ShowMenu = menus.displayMenu(initial_menu)
ShowMenu.start()

while 1:
    if ShowMenu.login == True:
        makesomething
        ShowMenu.login = False
    if.... etc.

This is well? I mean, interact in this way with the other module? have a variable in the menus module that help me organize the main flow?

By Erdo via Discussions on Python.org at 04Sep2022 01:55:

I made a module to manage the menus of an lcd display.

The number of options is quite large so I plan to use this file as a module to import into a file that integrates other issues.

That’s a good plan: write something once, use it elsewhere.

And my question goes this way. For example, when I select to log in to a page in the menu, what I do in the menu is put a variable that when entering that option becomes true.

So in the main file I have something like:

import menus

ShowMenu = menus.displayMenu(initial_menu)
ShowMenu.start()

while 1:
   if ShowMenu.login == True:
       makesomething
       ShowMenu.login = False
   if.... etc.

This is well? I mean, interact in this way with the other module? have a variable in the menus module that help me organize the main flow?

It looks ok. If you’re talking about ShowMenu.login, that isn’t a
variable in the menus module. It is an attribute of the ShowMenu
object which you made here. (Well, I assume menus.displayMenu() returns
a new object - maybe it does not.) That’s a normal thing to do: have an
object representing some state.

There’s a bunch of random other comments about your code:

 ShowMenu = menus.displayMenu(initial_menu)

I’m assuming ShowMenu is some object, an instance of a class. This is
tritely true about all objects/values in Python, but what I mean here
is that you made some object representing your state, and returned it.
The common convention in Python is to use CamelCase names (like your
ShowMenu name) for classes, and to use snake_case names such as
show_menu for instances. So I’d rename StartMenu to start_menu.
The language itself does not dictate this, but the convention is nearly
universal in Python programming and adopting it will make your code
easier to understand.

 while 1:

This is an infinite loop. Which is fine. We usually use the builtin
Python Booleans True and False for outright values like this, so
you’d more normally write:

 while True:

Also, genuinely infinitely loops are rare. An interactive programme
normally runs until told to quit. So you might go:

 done = False
 while not done:

which will also run forever, but leaves you the option of setting
done=True somewhere in response to something to quit the program by
exiting the loop.

 if ShowMenu.login == True:

if-statements test truthiness: you can just write:

 if ShowMenu.login:

here.

The final remark is that this looks like a “busy loop”: it polls
ShowMenu.login every time, and if that’s not true does nothing. If
therest of the loop was also like that (poll various things) then when
all those things are off your loop spins flat out, while doing
nothing. Normally you’d have some kind of loop which responded to events
instead of spinning. This is so commmon that most GUI toolkits have a
function named something like mainloop() which does just that, and
your setup involves making various widgets, then calling mainloop().
That sits there listening to the desktop events and responding as they
occur.

Cheers,
Cameron Simpson cs@cskk.id.au

2 Likes

Oh, that sounds more coherent! Ok.

mmm. I dont understand this.
Yep, this while will be checking some if statements waiting the True of some of them. And that is wrong? I understand when nothing is True it will be spinning “for nothing…”, but, that is not the way? This is for a LCD display that it is working on a raspberry pi.

mmm, one of the class i have inside menus (“displayMenu”) have also a really really big while, but… at the beginning have a Queue so, is not spinning all the time, just waiting for the event, maybe you are talking about somthing like that.

This is part of that class:

 while 1:
            event = event_queue.get()
            print("event", event)
            
            if screen == menu_initial:
                if event == MENU_STOCKFISH:
                    screen = menu_stockfish
                    screen.init()

                if event == MENU_RODENT:
                    screen = menu_rodent
                    screen.init()

                if event == MENU_LICHESS:
                    if self.runOnce == True: #here im trying to do the talking with the main flow.
                        self.login = True
                    screen = menu_lichess
                    screen.init()

this class have a method for buttons, and when you touch a button that put a event in the queue, and this get that event and interprets it, then init a instance of a class that have the logic of the display (to show it and go through the menu well).

if I had a copy of that queue I could put a get, at the beginning of the main while (of the principal flow) and based on that “activate” the while (every time a message arrives) and also avoid the attribute “login”, just if event==MENU_LICHESS then, etc… But I guess making a copy of a queue would not be the right thing to do. or is it?
thanks for the other advices!

Yes, that’s what I meant. There’s no “blocking” call like event_queue.get() in the loop in your original post. The “block until something happens” is what prevents the busy loop.

Cheers,
Cameron

You don’t need to copy the queue. Just have a reference to it - use the queue! As long as all the events which can come from the queue are handled, you’re good. I don’t know what’s in your code, but if you separated out the “handle one event” stuff into its own function:

    while 1:
        event = event_queue.get()
        handle_event(event)

then you can write your own loop like:

    while 1:
        event = event_queue.get()
        if event == MENU_LICHESS:
            do your special thing
        else:
            # do the normal thing
            handle_event(event)

This is just made up stuff to illustrate what you could choose to do.

Cheers,
Cameron

Because I’m trying to separate the menus (they are in the menus.py) from the “main flow”. Trying to put this main flow in a main.py file. So, i have the Queue in the menus.py file. I can access to that and even put() messages from the main.py file like menus.event_queue.put() to show some message in the display. But, i cant do a get() because the get() is in the menus.py file getting all the messages first.

You are talking about two “while” in the same file i think.

Sorry if i dont understand and thanks for your help.

By Erdo via Discussions on Python.org at 05Sep2022 23:21:

Because I’m trying to separate the menus (they are in the menus.py) from the “main flow”. Trying to put this main flow in a main.py file. So, i have the Queue in the menus.py file. I can access to that and even put() messages from the main.py file like menus.event_queue.put() to show some message in the display. But, i cant do a get() because the get() is in the menus.py file getting all the messages first.

I think you’ll find that a single get() call collects only a single
event from the queue.

You are talking about two “while” in the same file i think.

Only one of those loops will be running at a time. Whichever loop is
running and responding to events needs to be pulling things from the
queue and processing them.

I suspect I’m missing a lot about the over all structure of your
program.

Because there’s normally just one loop consuming the event queue, a
traditional GUI program (drawing widgets on a desktop) tends to:

  • prepare a bunch of widgets (buttons etc) with callback functions for
    event (such as “button pressed”)
  • call a “main loop” provided by the widget library, which reads from
    the queue and depending on the event received, calls the appropriate
    callback

It appears to me that you’re writing that “main loop”. Which is fine.

The example loop from your class, with the event_queue.get() call:
when does it exit? Never, apparently. So when does your other while
loop get to run?

When a button is pressed, what mechanism puts an event in the queue?
There’s always a mechanism, even if it isn’t overt.

FInally: are you using Threads? I’m assuming not.

Cheers,
Cameron Simpson cs@cskk.id.au

Im using Threads, yep.
If you want to look this is the code (cut a lot to reduce, and is extremly repetitive because all the option, i have a lot more of menus…):

You will see the event_queue at the end of that file.

This is the code that pretend to be the main flow. this import the menus.py

The program start at 306…