Open beyonlo opened 1 year ago
I tested with font6.py
(and others fonts) on the demo/simple.py
and I have same result
import gui.fonts.font6 as font6
wri = Writer(ssd, font6)
As you know, I was using the nano-gui and I was running nano-gui
demos in the same display and that symbol never showed.
Ohh, I realized that symbol is the exit button, right? So sorry!
Is there how do not use and do not show that exit button? Because that exit button use a very large space on the display when used little display as the ssd1306
with 128x64 pixels.
Let me to do another question: on the nano-gui
I was using the demo/mono_test.py
. I would like to use that example in the micro-gui
, where Next/Prev buttons change between fields()
, multi_fields()
and meter()
. How is better way to do that?
Thank you in advance!
I think the micro-gui
is no adapted very well to little display, like as 128x64, am I correct or not?
Mostly micro-gui
demos the widgets go to out of display or I have error ValueError: row is out of range
or showed message to use a display with at least 320x240 pixels. So, maybe is a good way use micro-gui
working with Next
/Prev
between entire Screen, like as in the fields()
, multi_fields()
and meter()
and if Select
is pressed on the multi_fields()
for example, another Screen can be called, or some thing like that - any idea or example that I can run as a start point?
The symbol is the CloseButton
: just remove that line to get rid of it.
micro-gui
is not optimisd for such a tiny screen, and I've never investigated the sort of modes you have in mind.
The symbol is the
CloseButton
: just remove that line to get rid of it.
Sorry for that dummy question. Now I see in the buttons.py
code:
# Preferred way to close a screen or dialog. Produces an X button at the top RHS.
# Note that if the bottom screen is closed, the application terminates.
class CloseButton(Button):
micro-gui
is not optimisd for such a tiny screen, and I've never investigated the sort of modes you have in mind.
Now I have three buttons on the display to use inputs Prev, Select, Next, but as the menus e etc of micro-gui are very large to that 128x64 display, I'm in a dillema what to do:
Ps:
Below are two prints using nano-gui with that re-inveted inputs next, prev, select that I opened that issue in the nano-gui project: https://github.com/peterhinch/micropython-nano-gui/issues/53
Is just two Screens, but will be much more, and the idea is prev/next change of that complete screen to another and use Select to change of Screen too.
Could you please give your thoughts about that?
Thank you
Here is the general approach I would use. Use micro-gui. Assign 3 unused pins to Button objects and use them to initialise the GUI. Their job is purely to allow the GUI to start correctly.
Assign the three pins used by your physical buttons to Button objects: let's call those Next, Prev and Sel. Note that Button instances allow you to dynamically assign callbacks.
Examine the demos to see how next and prev virtual buttons work. On your first screen, define an after_open
method which assigns a callback to your Next button*. On the next screen, after_open
would assign callbacks to Next, Prev and Sel. You'll need to be sure that every screen has an after_open
which assigns appropriate callbacks to the three buttons.
*On the first screen you'll also need to assign callbacks to Prev and Sel, because you might run this screen in response to Prev from the next. You can also disable the callback - see docs.
I'm convinced this could work, but it will require careful coding and studying the screen change mechanism.
Hello @peterhinch I liked so much about your idea and I understood your rationale. I read many docs and source code as well from demos
and ugui.py
, but I have still some difficult to put that idea to works
Here is the general approach I would use. Use micro-gui. Assign 3 unused pins to Button objects and use them to initialise the GUI. Their job is purely to allow the GUI to start correctly.
Just to clarify: I already has 3 Pins dedicated for the physical Buttons, so need I more 3 Pins (even temporary Pins) to initialize the GUI? If yes, I have no more Pins unused in my board, the last two unused pins I used to complete 3 physical Buttons instead 1 Button. But, if is really necessary, I can to start the display part of code before others async applications, so I use that 3 pins in temporary mode from that others applications until GUI will be started, and after remap that 3 Pins again to others applications.
Assign the three pins used by your physical buttons to Button objects: let's call those
Next
,Prev
andSel
. Note that Button instances allow you to dynamically assign callbacks.
I not understand how to that in code, because the hardware_setup.py
already has that 3 Pins configured as Prev
, Sel
and Next
Examine the demos to see how next and prev virtual buttons work. On your first screen, define an
after_open
method which assigns a callback to your Next button*. On the next screen,after_open
would assign callbacks to Next, Prev and Sel. You'll need to be sure that every screen has anafter_open
which assigns appropriate callbacks to the three buttons.*On the first screen you'll also need to assign callbacks to Prev and Sel, because you might run this screen in response to Prev from the next. You can also disable the callback - see docs.
I understand very well about the after_open(self). I did some tests with after_open(self)
while I was porting (with success :partying_face: ) my Screens from nano-gui
to micro-gui
and It's simple: just execute something after widgets are created on the Screen. So after each Screen start, I need on the after_open(self)
to assign a new Screen for the Next
, Prev
and Sel
- but how to do that (what code)?
I examined demo simple.py
that has two buttons where is possible test the Prev
and Next
mechanism, but inside the simple.py
I think that mechanismi is not showed, right? So I checked in the ugui.py
where has class Display(DisplayIP):
that is used to assign that 3 buttons on hardware_setup
to the 3 real pins. There is the class Input:
maybe is there (I think) where I need to reuse some variables to change the Prev
, Sel
and Next
on the after_open(self)
? Sorry, that is too much information for a newbie in GUI.
I'm convinced this could work, but it will require careful coding and studying the screen change mechanism.
I don't know if I'm asking too much, but honestly I need your help for an example to start. So, could you please, create a very simple example with two or 3 Screens implementing that idea to me as a start point? And maybe this example can be a official example
for anyone that want to use micro-gui
with Prev
, Sel
, Next
moving over Screens (when tiny display) instead to use the menus and some others widgets that are larger too much for that tiny displays.
Thank you so much!
At least I'm glad today that I have ported successfully that two nano-gui
Screens to micro-gui
(bellow the code):
multi_fields.py:
# simple.py Minimal micro-gui demo.
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2021 Peter Hinch
# hardware_setup must be imported before other modules because of RAM use.
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton, Meter
from gui.core.writer import Writer
import uasyncio as asyncio
# Font for CWriter
import gui.fonts.arial10 as arial10
import gui.fonts.font6 as small
from gui.core.colors import *
def xorshift64star(modulo, seed = 0xf9ac6ba4):
x = seed
def func():
nonlocal x
x ^= x >> 12
x ^= ((x << 25) & 0xffffffffffffffff) # modulo 2**64
x ^= x >> 27
return (x * 0x2545F4914F6CDD1D) % modulo
return func
async def change_multi_fields(nfields):
random = xorshift64star(2**24 - 1)
while True:
for field in nfields:
value = random() / 16777
field.value('{:5.2f}'.format(value))
await asyncio.sleep_ms(500)
class BaseScreen(Screen):
def __init__(self):
super().__init__()
Writer.set_textpos(ssd, 0, 0) # In case previous tests have altered it
wri = Writer(ssd, small, verbose=False)
wri.set_clip(False, False, False)
nfields = []
dy = small.height() + 6
y = 2
col = 15
width = wri.stringlen('999.99')
for txt in ('1:', '2:', '3:'):
Label(wri, y, 0, txt)
nfields.append(Label(wri, y, col, width, bdcolor=None)) # Draw border
y += dy
dy = small.height() + 6
y = 2
col = 82
for txt in ('4:', '5:', '6:'):
Label(wri, y, 67, txt)
nfields.append(Label(wri, y, col, width, bdcolor=None)) # Draw border
y += dy
self.reg_task(change_multi_fields(nfields))
CloseButton(wri)
def after_open(self):
print('----------------------------- 1')
ssd.hline(60, 60, 30, BLUE)
ssd.vline(67, 0, 28, BLUE)
print('----------------------------- 2')
def test():
Screen.change(BaseScreen) # A class is passed here, not an instance.
test()
meter1.py
# simple.py Minimal micro-gui demo.
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2021 Peter Hinch
# hardware_setup must be imported before other modules because of RAM use.
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton, Meter
from gui.core.writer import Writer
import uasyncio as asyncio
# Font for CWriter
import gui.fonts.arial10 as arial10
from gui.core.colors import *
async def change_meter(m0, m1, m2):
steps = 10
c = 1
for n in range(steps + 1):
m0.value(c/steps)
m1.value(n/steps)
m2.value(1 - n/steps)
await asyncio.sleep(1)
c += 1
class BaseScreen(Screen):
def __init__(self):
super().__init__()
wri = Writer(ssd, arial10, verbose=False)
m0 = Meter(wri, 5, 2, height = 45, divisions = 4, legends=('0.0', '50', '100', '245!', '250!'), label='4', style=Meter.BAR)
m1 = Meter(wri, 5, 44, height = 45, divisions = 4, legends=('0.0', '50', '200', '295!', '300!'), label='5', style=Meter.BAR)
m2 = Meter(wri, 5, 86, height = 45, divisions = 4, legends=('0.0', '50', '200', '335!', '340!'), label='6', style=Meter.BAR)
self.reg_task(change_meter(m0, m1, m2))
CloseButton(wri)
def after_open(self):
print('----------------------------- 1')
ssd.hline(60, 60, 30, BLUE)
ssd.vline(67, 0, 28, BLUE)
print('----------------------------- 2')
def test():
Screen.change(BaseScreen) # A class is passed here, not an instance.
test()
Hi @peterhinch Sorry for one more time request, but I would like to know if will be possible to you to create a very simple example with two or 3 Screens implementing that your idea as a start point to me? A good and perfect example with three screens could be that my two screens above and the third scree the simple.py example, because the simple.py is a perfect screen to execute a command (it has button yes and no) to enable/disable some feature. However as the simple.py has real (not more virtual) buttons (yes and no) maybe need to do a additional remap of pins in the after_open(), and this is another thing that I have no idea how to implement, and that's why it's so important an example with those three screens as start point :)
Don't worry if you can't to do that, is just to me know what way I will follow. Unfortunately I was no capable to implement your idea using micro-gui, and if you can't to create an example, I will back to nano-gui and and continue with re-invente the inputs Prev, Select and Next.
Thank you in advance!
I'm sorry but I am far too busy on another project to write and test a demo for you.
I am convinced that micro-gui is the best, and simplest, approach. Looking at simple.py
you would have two Pushbutton
objects associated with your physical buttons. The Pushbutton
close callbacks would be the callback currently associated with the Button
objects on the screen.
In the case where screens change, the Pushbutton
callbacks might need to change. This would be done in the after_open
method.
I am convinced that micro-gui is the best, and simplest, approach.
Me too. And I did read this messages bellow dozens of times and still have questions.
Looking at
simple.py
you would have twoPushbutton
objects associated with your physical buttons.
The two Pushbutton
that you are talking about are the Button() yes
on line 32 and Button() no
on line 34 of the file simple.py right?
The
Pushbutton
close callbacks would be the callback currently associated with theButton
objects on the screen.
Now you talk about again of the same Pushbutton
that I believe to be the same on line 32 and 34. If yes, that Button() do not have close callbacks. They have callback, but that call just the my_callback()
on line 22.
And you talk about "associated with the Button
objects on the screen", but If Pushbutton
are objects (line 32, 34) what line are there the Button
objects?
In the case where screens change, the
Pushbutton
callbacks might need to change. This would be done in theafter_open
method.
Here I'm confused too because I do not know what lines in the simple.py arePushbutton
objects and what are the Button
objects.
Could you please clarify that?
Other question: for that solution need I to change some code in some file inside core/ or widgets/ directories, or all the changes needed is just on the simple.py for example?
I'm sorry but I am far too busy on another project to write and test a demo for you.
I agree, but if you could at least write directly here in the GitHub a piece of code as a draft (without any test) I can get better the idea and I will to do the tests and complete what will need.
Thank you so much!
Button
objects are on-screen widgets. Pushbutton
objects are physical pushbuttons.
In your final application you won't have any Button
instances. What I am suggesting is that you implement Pushbutton
instances for your electrical buttons. You study the examples to see how the callbacks for Button
s work. And you modify the example code so that the callbacks are assigned to the Pushbutton
close
instead of the Button
. The Button
instances can then be eliminated from the screen.
I had progress.. :partying_face: I have one Question below.
In the hardware_setup.py
I used unused pins to initialize gui without errors. - Done!
Button
objects are on-screen widgets.Pushbutton
objects are physical pushbuttons.
Got it!
In your final application you won't have any
Button
instances.
Got it!
What I am suggesting is that you implement
Pushbutton
instances for your electrical buttons.
Done on simple.py
:
from gui.primitives import Pushbutton
from machine import Pin
class BaseScreen(Screen):
def __init__(self):
def my_callback(button, arg):
print('Button pressed', button, arg)
super().__init__()
# verbose default indicates if fast rendering is enabled
wri = Writer(ssd, arial10)
col = 2
row = 2
Label(wri, row, col, 'Simple Demo')
row = 50
Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',))
col += 60
Button(wri, row, col, text='No', callback=my_callback, args=('No',))
# 3 Pushbuttons implemented (prev, sel, next)
prev = Pin(41, Pin.IN, Pin.PULL_UP)
self.btn_prev = Pushbutton(prev)
sel = Pin(12, Pin.IN, Pin.PULL_UP)
self.btn_sel = Pushbutton(sel)
nxt = Pin(42, Pin.IN, Pin.PULL_UP)
self.btn_nxt = Pushbutton(nxt)
# test to implement callback on the pushbutton
#self.btn_nxt = Pushbutton(b_next, callback=my_callback, args=('Test',))
You study the examples to see how the callbacks for
Button
s work.
This is in progress yet... I'm stuying!
And you modify the example code so that the callbacks are assigned to the
Pushbutton
close
instead of theButton
.
Question: here I got the idea too, but the /gui/primitives/pushbutton.py
do not has the close
method. What or where is that close
on the Pushbutton
?
Any additional comments about the code above (including that line commented about callback on the pushbutton) is wellcome!
Thank you!
See the Pushbutton docs. You use the press_func
method to assign a callback.
Hey @peterhinch It works like you told me! :partying_face: :balloon: Thank you for your support and especially for your patience!
I still testing and finding the best way to call each Screen in the after_open(self)
I'm thinking to have a python file for each Screen and import each Python file when I will use it in the callback to sel, next or prev. Any suggestion?
A question about this error: ValueError: Screen has no active widgets.
Is possible to do something to not show this error, or to create a invisible active widget? Because sometimes I do not need active widgets. For now I'm using the CloseButton(wri) to works.
Thank you very much!
I think importing on demand will work. If you want a modular design this is fine, but this way of working won't save resources. The GUI only instantiates the Screen
instance when it is opened, and MicroPython's garbage collection will retrieve the RAM when it is closed.
Re the error, I hadn't thought of this. I think suppressing the error will only move the problem elsewhere - the GUI is built on the assumption that there is at least one active control on a screen. So the best solution is probably to make the close button invisible. Adding the following line to widgets\buttons.py
should do this:
class CloseButton(Button):
def __init__(self, writer, width=0, callback=dolittle, args=(), bgcolor=RED):
scr = Screen.current_screen
# Calculate the button width if not provided. Button allows
# 5 pixels either side.
wd = width if width else (writer.stringlen('X') + 10)
self.user_cb = callback
self.user_args = args
super().__init__(writer, *scr.locn(4, scr.width - wd - 4),
width = wd, height = wd, bgcolor = bgcolor,
callback = self.cb, text = 'X')
self.visible = False # Add this line
Hi @peterhinch works with self.visible = False
Mostly Screens that I will have is just to user see the data, like as that Screens I posted above (meter, multifields), but some Screen I want a Screen exactely as the simple.py
with that two active buttons (yes and no
), where user can for example Enable AP mode
and choose Yes or No
. So I was thinking (and I already did some tests) where in the hardware_setup.py
I can to use the correct pins, I mean, the same used in the pushbuttons on the Screens. So when is a Screen where there is no active widgets that pins on the hardware_setup.py
will do not effect, but when I open a window like as the simple.py
that hardware_setup.py
pins will works automatically, and, I in this screen I do not configure the next/prev/sel
on the after_open()
, but only when user choose yes or not
. Does that make sense for you?
Thank you in advance!
That sounds OK.
Hello @peterhinch What's the correct way to integrate my micro-gui app with other async tasks/servers?
That integrate below works, but I note that after I integrate that very simple example (the simple.py) all my system got very slow.
Ps: I changed on the /gui/core/ugui.py
from do_gc = True
to do_gc = False
but do not solve the problem :(
Any idea why integrate the example simple.py
got all system slow?
main.py:
async def main():
await start._setup()
# Start ModBus Slave TCP
slave_tcp_task = _start_slave_tcp('192.168.43.143', 502, 2)
asyncio.run(slave_tcp_task)
# Start micro-gui simple.py
print('starting display... ---------------------')
from main_simple import test
t1 = asyncio.create_task(test())
print('Display started! ---------------------')
# Start Microdot
await app.start_server(host='0.0.0.0', port=80, debug=False)
try:
asyncio.run(main())
except KeyboardInterrupt:
print('Stopped')
main_simple.py:
import hardware_setup # Create a display instance
from gui.core.ugui import Screen
from simple import BaseScreen
async def test():
print('Simple demo: button presses print to REPL.')
Screen.change(BaseScreen) # A class is passed here, not an instance.
#test()
simple.py:
# simple.py Minimal micro-gui demo.
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2021 Peter Hinch
# hardware_setup must be imported before other modules because of RAM use.
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton
from gui.core.writer import Writer
# Font for Writer
import gui.fonts.arial10 as arial10
from gui.core.colors import *
class BaseScreen(Screen):
def __init__(self):
def my_callback(button, arg):
print('Button pressed', arg)
super().__init__()
# verbose default indicates if fast rendering is enabled
wri = Writer(ssd, arial10)
col = 2
row = 2
Label(wri, row, col, 'Simple Demo')
row = 50
Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',))
col += 60
Button(wri, row, col, text='No', callback=my_callback, args=('No',))
CloseButton(wri) # Quit the application
#def test():
# print('Simple demo: button presses print to REPL.')
# Screen.change(BaseScreen) # A class is passed here, not an instance.
#
#test()
EDIT: my ESP32-S3 is clocked at full speed: 240 MHz
micro-gui
automatically starts uasyncio
- the intention being for it to be accessible by means of synchronous coding only.
Applications therefore shouldn't use asyncio.run()
. The way to run asynchronous code within a micro-gui
application is to launch tasks from a callback (e.g. after_open
) or from the base screen's __init__.py
- see for example the aclock.py demo. See the docs for a way to ensure tasks are cancelled on exit.
Hello @peterhinch
micro-gui
automatically startsuasyncio
- the intention being for it to be accessible by means of synchronous coding only.
Yes, I see that in the docs. But please, think in a very simple scenario, if I use Microdot (or/and other servers) I need to start the micro-gui
in asyncronous
mode, otherwise the micro-gui
will block all async applications, that's why I started the micro-gui
application as a task - t1 = asyncio.create_task(test_display())
Let me see if I understood what you are saying: software that need to run the micro-gui
, need to have micro-gui
as the main (sync) started application and the async servers/tasks
need only be started from the micro-gui using the self.reg_task()
?
Applications therefore shouldn't use
asyncio.run()
. The way to run asynchronous code within amicro-gui
application is to launch tasks from a callback (e.g.after_open
) or from the base screen's__init__.py
- see for example the aclock.py demo. See the docs for a way to ensure tasks are cancelled on exit.
Yes, I already following that example (for the self.reg_task()
) when I ported the nano-gui examples to micro-gui - I pasted this thread above.
But I can't see how I can to start all async servers
like Microdot and others from the self.reg_task()
, any example as start Microdot for example?
micro-gui
to be started from an async code
? Because I can to start all my async servers
correctly as their docs say and start micro-gui
as a task!micro-gui
in async mode (as a task - as my example above) apparently works ( t1 = asyncio.create_task(test_display())
), the problem is just that all applications got slow. But if the applications do not got to slow, can I use in that way? I'm asking this because I found that if I change the line await asyncio.sleep_ms(0) # Let user code respond to event
in the /core/ugui.py from await asyncio.sleep_ms(0)
to await asyncio.sleep_ms(50)
all system works perfect - not got slow anymore. Is necessary to be 0
in that sleep or can it be changed to other value, like as 50
? Or I will have some problem in the future? I not understand very well, but I think that sleep_ms(0)
means that refresh data on the display will be done as soon is possible, but if I use sleep_ms(50)
will refresh only each 50
ms, is that correct?Thank you very much
EDIT:
About the Item 2.
above: I changed to asyncio.sleep_ms(100)
to have better results, because 50ms was still a bit slow.
@peterhinch There is a situation with self.visible = False # Add this line
on the /gui/widgets/buttons.py
at the class CloseButton(Button)
. It works (CloseButton
is invible now), but that Screen stop to call the NEXT Screen configured in the after_open(self)
If I comment line #self.visible = False # Add this line
the NEXT
back to works, I mean, the next Screen
now show when I click in the NEXT pushbutton
CloseButton(wri)
def next_screen(self, arg):
print('Pushbutton pressed', arg)
Screen.change(ScreenTempMeter01)
def after_open(self):
nxt = Pin(42, Pin.IN, Pin.PULL_UP)
self.btn_nxt = Pushbutton(nxt)
self.btn_nxt.press_func(self.next_screen, ('next screen',))
@peterhinch one more question: how is possible to pass params
to the class BaseScreen(Screen):
?
I'm using the simple.py as reference.
I added a msg
param this in the init:
def __init__(self, msg=None):
print(msg)
And where the Screen is called I changed from Screen.change(BaseScreen)
to Screen.change(BaseScreen(msg='test1'))
but I have this error: ValueError: Must pass Screen class or subclass (not instance)
. Yes, I understand that it accept just class, and not an instance. So, what is the best way to pass params
to be used inside the BaseScreen
code?
simple.py changed:
# simple.py Minimal micro-gui demo.
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2021 Peter Hinch
# hardware_setup must be imported before other modules because of RAM use.
import hardware_setup # Create a display instance
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton
from gui.core.writer import Writer
# Font for Writer
import gui.fonts.arial10 as arial10
from gui.core.colors import *
class BaseScreen(Screen):
def __init__(self, msg=None):
print(msg)
def my_callback(button, arg):
print('Button pressed', arg)
super().__init__()
# verbose default indicates if fast rendering is enabled
wri = Writer(ssd, arial10)
col = 2
row = 2
Label(wri, row, col, 'Simple Demo')
row = 50
Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',))
col += 60
Button(wri, row, col, text='No', callback=my_callback, args=('No',))
CloseButton(wri) # Quit the application
def test():
print('Simple demo: button presses print to REPL.')
Screen.change(BaseScreen(msg='test1')) # A class is passed here, not an instance.
test()
Thank you again :)
@peterhinch The args works - thanks :)
The proof of concept about your pushbutton
idea works, but I have two problems and one question.
I did a very very simple code - it has screen-1, screen-2, screen-3, and screen-4
, where pushbutton
prev
and next
change (forward or backwards) between screen-1
, screen-2
and the screen-3
. The screen-4
is just changed when in the screen-3
user click in the sel
pushbutton
. And to go out from screen-4
user need just to press Button
Yes
- so, that will back to screen-1
. The code is pasted below, but I attached in tar.gz
format the files to be easy to test. There is attached as well a video with the idea running and showing the problem-2
Could you please to check my code if there is something wrong? I did a very simple code because if you want to test, you need just to call the screen_main.py
Problems:
self.visible = False
on the class CloseButton(Button)
works, CloseButton
turn on invisible, but that stop to work the prev
, sel
and the next
of the pushbuttons
(to change the screens). Any idea how to fix that? I pasted details about this problem in this thread The example below (including the video) are using CloseButton
visible, otherwise will not works the idea.sel
on Screen-3 to change to Screen-4 (that has Button
Yes
and No
) , automatically Button
Yes
is pressed - But I do not pressed anything. Do you know what is the problem?Question: I'm changing to new Screen
from inside another Screen (button.press_func()
), so every time that a Screen is changed to another, the previous Screen
will not closed and never will. I checked that if I close (click in the CloseButton
) the Screen
, that Screen is closed and back to last Screen and so on, until all Screens
are closed. So, using this idea (like as a carousel - without CloseButton
) the same Screens
will be called many times and they will never close. Can that be a problem? The same question is for when used self.reg_task()
in the Screens
- since the screens will never close, each time that Screen
will be called, a new self.reg_task()
will be executed. This code is not using self.reg_task()
, because is just a Proof of Concept, but I will use it.
screen_main.py:
import hardware_setup # Create a display instance
from gui.core.ugui import Screen
from gui.primitives import Pushbutton
from machine import Pin
from screen_1 import BaseScreen_1
from screen_2 import BaseScreen_2
from screen_3 import BaseScreen_3
from screen_4 import BaseScreen_4
screens = {}
screens['BaseScreen_1'] = BaseScreen_1
screens['BaseScreen_2'] = BaseScreen_2
screens['BaseScreen_3'] = BaseScreen_3
screens['BaseScreen_4'] = BaseScreen_4
prev_pin = Pin(41, Pin.IN, Pin.PULL_UP)
sel_pin = Pin(12, Pin.IN, Pin.PULL_UP)
next_pin = Pin(42, Pin.IN, Pin.PULL_UP)
prev_btn = Pushbutton(prev_pin)
sel_btn = Pushbutton(sel_pin)
next_btn = Pushbutton(next_pin)
buttons = {}
buttons['prev'] = prev_btn
buttons['sel'] = sel_btn
buttons['next'] = next_btn
def main_screen():
params = {'screens': screens, 'buttons': buttons}
kwargs = {'params': params}
Screen.change(screens['BaseScreen_1'], kwargs=kwargs)
main_screen()
screen_1.py:
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton
from gui.core.writer import Writer
import gui.fonts.arial10 as arial10
class BaseScreen_1(Screen):
def __init__(self, params):
self.kwargs = {'params': params}
self.params = params
self.screens = params['screens']
self.prev_btn = params['buttons']['prev']
self.sel_btn = params['buttons']['sel']
self.next_btn = params['buttons']['next']
super().__init__()
wri = Writer(ssd, arial10, verbose=False)
col = 2
row = 2
screen_name = 'Screen-1'
print(f'I am screen: {screen_name}')
Label(wri, row, col, screen_name)
CloseButton(wri)
def prev_screen(self, arg):
screen = self.screens['BaseScreen_3']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def sel_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print(f'This Screen has no function to the: {arg}')
def next_screen(self, arg):
screen = self.screens['BaseScreen_2']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def after_open(self):
self.prev_btn.press_func(self.prev_screen, ('prev screen',))
self.sel_btn.press_func(self.sel_screen, ('sel screen',))
self.next_btn.press_func(self.next_screen, ('next screen',))
screen_2.py:
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton
from gui.core.writer import Writer
import gui.fonts.arial10 as arial10
class BaseScreen_2(Screen):
def __init__(self, params):
self.kwargs = {'params': params}
self.params = params
self.screens = params['screens']
self.prev_btn = params['buttons']['prev']
self.sel_btn = params['buttons']['sel']
self.next_btn = params['buttons']['next']
super().__init__()
wri = Writer(ssd, arial10, verbose=False)
col = 2
row = 2
screen_name = 'Screen-2'
print(f'I am screen: {screen_name}')
Label(wri, row, col, screen_name)
CloseButton(wri)
def prev_screen(self, arg):
screen = self.screens['BaseScreen_1']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def sel_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print(f'This Screen has no function to the: {arg}')
def next_screen(self, arg):
screen = self.screens['BaseScreen_3']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def after_open(self):
self.prev_btn.press_func(self.prev_screen, ('prev screen',))
self.sel_btn.press_func(self.sel_screen, ('sel screen',))
self.next_btn.press_func(self.next_screen, ('next screen',))
screen_3.py:
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton
from gui.core.writer import Writer
import gui.fonts.arial10 as arial10
class BaseScreen_3(Screen):
def __init__(self, params):
self.kwargs = {'params': params}
self.params = params
self.screens = params['screens']
self.prev_btn = params['buttons']['prev']
self.sel_btn = params['buttons']['sel']
self.next_btn = params['buttons']['next']
super().__init__()
wri = Writer(ssd, arial10, verbose=False)
col = 2
row = 2
screen_name = 'Screen-3'
print(f'I am screen: {screen_name}')
Label(wri, row, col, screen_name)
col = 2
row = 20
Label(wri, row, col, 'Press *SEL* to open')
col = 2
row = 40
Label(wri, row, col, 'the Screen-4')
CloseButton(wri)
def prev_screen(self, arg):
screen = self.screens['BaseScreen_2']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def sel_screen(self, arg):
screen = self.screens['BaseScreen_4']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def next_screen(self, arg):
screen = self.screens['BaseScreen_1']
print(f'Pushbutton pressed: {arg}. Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
def after_open(self):
self.prev_btn.press_func(self.prev_screen, ('prev screen',))
self.sel_btn.press_func(self.sel_screen, ('sel screen',))
self.next_btn.press_func(self.next_screen, ('next screen',))
screen_4.py:
from gui.core.ugui import Screen, ssd
from gui.widgets import Label, Button, CloseButton
from gui.core.writer import Writer
import gui.fonts.arial10 as arial10
class BaseScreen_4(Screen):
def __init__(self, params):
self.kwargs = {'params': params}
self.params = params
self.screens = params['screens']
self.prev_btn = params['buttons']['prev']
self.sel_btn = params['buttons']['sel']
self.next_btn = params['buttons']['next']
def my_callback(button, arg):
print('Button pressed', arg)
if arg == 'Yes':
screen = self.screens['BaseScreen_1']
print(f'Your choose was *{arg}*, so Changing to the screen: {screen}')
Screen.change(screen, kwargs=self.kwargs)
super().__init__()
wri = Writer(ssd, arial10, verbose=False)
col = 2
row = 2
screen_name = 'Screen-4'
print(f'I am screen: {screen_name}')
Label(wri, row, col, screen_name)
col = 2
row = 14
Label(wri, row, col, 'Press Yes')
col = 2
row = 28
Label(wri, row, col, 'to go to Screen-1')
row = 40
Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',))
col += 50
Button(wri, row, col, text='No', callback=my_callback, args=('No',))
CloseButton(wri) # Quit the application
def prev_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print(f'This Screen has no function to the: {arg}')
def sel_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print(f'This Screen has no function to the: {arg}')
def next_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print(f'This Screen has no function to the: {arg}')
def after_open(self):
self.prev_btn.press_func(self.prev_screen, ('prev screen',))
self.sel_btn.press_func(self.sel_screen, ('sel screen',))
self.next_btn.press_func(self.next_screen, ('next screen',))
hardware_setup.py
from machine import Pin, SPI
import machine
import gc
import time
from ssd1306 import SSD1306_I2C as SSD
WIDTH = const(128)
HEIGHT = const(64)
i2c = machine.SoftI2C(scl=machine.Pin(18), sda=machine.Pin(17))
gc.collect() # Precaution before instantiating framebuf
ssd = SSD(WIDTH, HEIGHT, i2c)
from gui.core.ugui import Display
# Define control buttons
nxt = Pin(42, Pin.IN, Pin.PULL_UP) # Move to next control
#nxt = Pin(10, Pin.IN, Pin.PULL_UP) # Move to next control
sel = Pin(12, Pin.IN, Pin.PULL_UP) # Operate current control
#sel = Pin(11, Pin.IN, Pin.PULL_UP) # Operate current control
prev = Pin(41, Pin.IN, Pin.PULL_UP) # Move to previous control
#prev = Pin(14, Pin.IN, Pin.PULL_UP) # Move to previous control
display = Display(ssd, nxt, sel, prev) # 3-button mode
Output: this is the same output that show in the video (attached):
$ mpremote run screen_main.py
Using 3 switches.
I am screen: Screen-1
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_2'>
I am screen: Screen-2
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_3'>
I am screen: Screen-3
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_1'>
I am screen: Screen-1
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_2'>
I am screen: Screen-2
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_3'>
I am screen: Screen-3
Pushbutton pressed: sel screen. Changing to the screen: <class 'BaseScreen_4'>
I am screen: Screen-4
Button pressed Yes
Your choose was *Yes*, so Changing to the screen: <class 'BaseScreen_1'>
I am screen: Screen-1
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_2'>
I am screen: Screen-2
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_3'>
I am screen: Screen-3
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_1'>
I am screen: Screen-1
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_2'>
I am screen: Screen-2
Pushbutton pressed: next screen. Changing to the screen: <class 'BaseScreen_3'>
I am screen: Screen-3
Pushbutton pressed: sel screen. Changing to the screen: <class 'BaseScreen_4'>
I am screen: Screen-4
Button pressed Yes
Your choose was *Yes*, so Changing to the screen: <class 'BaseScreen_1'>
I am screen: Screen-1
GitHub complains that the video file is corrupt.
I am very busy at the moment - I'm not sure when I'll find time to debug all that code.
Good morning @peterhinch :)
GitHub complains that the video file is corrupt.
That's strange, because I watched it directly from github after I posted the thread - I'm using Chromium. Anyway here is a new url for it (shared in the google drive)
I am very busy at the moment - I'm not sure when I'll find time to debug all that code.
All right, take your time! I did a simpler code as possible as prof of concept about the idea, and to not use much your time!
Thank you so much for all your help!
EDIT: is possible, maybe, for now, at least just to answer that Question Item? That will clarify much things about the design in this Proof of Concept about the idea!
The design assumes that screens are stacked. If screen A opens screen B, which opens screen C, the stack is ABC. If screen C is closed, screen B is visible and the stack is AB. When screen B is closed, only screen A exists. Visually each screen overlays the previous one, in the expectation that the top one will be closed revealing the one below.
This is fundamental to the design. If screen C opens another instance of A - carousel mode - you would end up with ABCA which would pave the way to ABCAB - ABCABC and so on. There would indeed be an ever growing number of instances. Supporting that would require a substantial redesign, a task that I don't intend to undertake. Perhaps there is a way where, when in screen C, on closure the underlying screen B also closes. This is way beyond anything I've tried, or anything any other user has requested.
I'm happy to answer queries on design, such as this one. I'm less happy when the answer is in the docs, which I've had cause to point out several times. My least favourite is being presented with pages of code and an invitation to fix it. This would involve setting up hardware and a substantial commitment of time. Time that I don't have.
Hi @peterhinch
This is fundamental to the design. If screen C opens another instance of A - carousel mode - you would end up with ABCA which would pave the way to ABCAB - ABCABC and so on. There would indeed be an ever growing number of instances. Supporting that would require a substantial redesign, a task that I don't intend to undertake. Perhaps there is a way where, when in screen C, on closure the underlying screen B also closes. This is way beyond anything I've tried, or anything any other user has requested.
To solve this problem I used this strategy: I have a main class
that change to all Screens, so each Screen that user click on any pushbutton (prev, sel, next) or Buttons (Yes, No) I set that user option in a variable accessible by that main class
and call the Screen.shutdown()
and the control back to main class
that will change to new Screen that user choose (from that variable). In this way I never will have a stack of Screens, and will never worry by the self.reg_task()
because as say this doc about the Shutdown: "any tasks registered to the base screen are cancelled
" I did some tests and works - using this approach also fixed that problem 2 as well. If you have some consideration about this approach, please, let me know
I'm less happy when the answer is in the docs, which I've had cause to point out several times. My least favourite is being presented with pages of code and an invitation to fix it. This would involve setting up hardware and a substantial commitment of time. Time that I don't have.
I totally agree. Apologize for that. Is my responsibility read the docs, also write the code and test it. Please, ignore my invite to check my code. I will contact you just if the docs do not exists or docs is not well understand by me, or a bug, otherwise you are correct, I need to do my home work. You already help so much about design asking, strategy, suggestion, examples, docs, new features, bug fix, etc!
Well, I have just one problem yet. When I use self.visible = False
on CloseButton
the pushbutton
prev, sel, next
do not works anymore, I mean, after I click in pushbutton next
for example, everything congeals/stop. But I did a detailed debug and find exactly where it is stopping, and I would like your help how can be fixed that.
It stop in the launch
/gui/primitives/__init__.py
:
def launch(func, tup_args):
print('----------- 1')
print(func.__name__)
print(*tup_args)
res = func(*tup_args)
print('----------- 2')
if isinstance(res, type_coro):
res = asyncio.create_task(res)
return res
Test with self.visible = False
:
$ mpremote run screen_main.py
----------- 1
ctrl_move
1
Ps: Look that it stop/congeal in the res = func(*tup_args)
because do not print the '----------- 2'
I see that ctrl_move
will move the pushbutton next. Maybe as the only active widget on the screen is the CloseButton, as it is invisible the pushbutton
next can't go to that invisible widget and happen this bug.
Test with self.visible = True
:
$ mpremote run screen_main.py
----------- 1
ctrl_move
1
----------- 2
----------- 1
next_screen
next screen
----------- 2
Ps: this works ok
Thank you in advance!
Perhaps setting visible=False
was not a good idea. You're going to have to experiment because I have never tried the case where a screen has no visible controls.
To create an invisible control you might like to try the Checkbox
widget. I suggest this because it is extremely simple, in case you need to modify the code in checkbox.py
. If you created a checkbox that was very small, and set its colors to match the screen background, perhaps this will fit the bill.
Hello @peterhinch
I did set all colors possible as BLACK
, but still have a border in WHITE
.
I tried this three ways:
Checkbox(wri, row, col, height=1, fillcolor=BLACK, fgcolor=BLACK, bgcolor=BLACK, bdcolor=False)
Checkbox(wri, row, col, height=1, fillcolor=BLACK, fgcolor=BLACK, bgcolor=BLACK, bdcolor=None)
Checkbox(wri, row, col, height=1, fillcolor=BLACK, fgcolor=BLACK, bgcolor=BLACK, bdcolor=True)
but all cases still have a little WHITE
border. I used all colors params possible that there is in the class Checkbox(Widget)
on the file /gui/widgets/checkbox.py
The docs say that setting bdcolor=False
no border will be drawn, but still exists a WHITE
border.
So to get out that WHITE
border I did set an arg 'invisible'
:
Checkbox(wri, row, col, height=1, fillcolor=BLACK, fgcolor=BLACK, bgcolor=BLACK, bdcolor=False, args=('invisible',))
And added this code in the /gui/core/ugui.py
in the def draw_border(self)
if self.args:
if self.args[0] == 'invisible':
color = BLACK
def draw_border(self):
if self.screen is Screen.current_screen:
dev = display.usegrey(self._greyed_out)
x = self.col - 2
y = self.row - 2
w = self.width + 4
h = self.height + 4
# print('border', self, display.ipdev.is_adjust())
if self.has_focus() and not isinstance(self, DummyWidget):
color = color_map[FOCUS]
if self.args:
if self.args[0] == 'invisible':
color = BLACK
$ diff ugui.py ugui.py.ORIG
242c242
< do_gc = False # Allow user to take control of GC
---
> do_gc = True # Allow user to take control of GC
693,695d692
< if self.args:
< if self.args[0] == 'invisible':
< color = BLACK
With this change in the ugui.py
works fine (checkbox is hide and the pushbuttons
works), but I do not know if I'm doing the correct way, or if I missing something to set the correct BLACK colors to hide the checkbox widget.
I believe, maybe, that should be possible to set from the widgets the correct color (like as BLACK) to that line color = color_map[FOCUS]
on the def draw_border(self)
Thank you!
The white border indicates that a control has the focus. On a screen with multiple active controls, the white border moves when you press NEXT and PREV pushbuttons. This white border is not the same as the border created by draw_border()
which is permanently attached to the control. For example, in the Label
widget, a text string can be drawn with or without a border.
Only active
controls can take the focus. Because you have only one active
control it always has the focus - there is nowhere else for the focus to go. The color of this border is set here at offset 0 into the list (FOCUS
in line 46). You might like to try changing this from WHITE
to BLACK
.
Hi @peterhinch
Only
active
controls can take the focus. Because you have only oneactive
control it always has the focus - there is nowhere else for the focus to go. The color of this border is set here at offset 0 into the list (FOCUS
in line 46). You might like to try changing this fromWHITE
toBLACK
.
I saw that in the colors docs too, and I already tried that, and works, but problem that I have some Screens that has active buttons, exactly as the simple.py
, to user choose Yes
or No
to Enable/Disable
some feature. And if I change that color_map
on the position 0 do BLACK, all Screens with active widgets will not be possible to user see the focus - because now is BLACK
. But using that way that I pasted to you, only widgets that I pass as argument 'invisible' will have Focus BLACK
color, otherwise will be the standard WHILE
color. If you have some more idea, please, let me know :)
I have a bigger problem with this design that is when I have a simple.py
Screen - that has active buttons. I do not put the "invisible" Checkbox in that Screens and I remove the CloseButton
too. So, think about the simple.
py just without the CloseButton
, that when this Screen is opened, I set in the after_open()
all my pushbutton objects
prev, sel and next
to a callback that will not change to new Screen, because I want that when user are inside of Screen simple.py
user can to change of Screen only when user choose Yes
or No
. Problem is when I change to the simple.py
Screen, as the focus are by default in the Yes Button
, magically the Yes Button
is pressed. In the hardware_setup.py
the prev, sel, next
are using the same pins used in the my pushbuttons objects
prev, sel and next
. So when is a Screen that do not has active widgets, the pushbuttons objects
are functional and is possible to Change the Screens. But when is changed to a Screen that has active widgets like as the simple.py
, I set in the after_open()
a callback that not exists to my pushbutton objects
, so in this Screen the hardware_setup.py
prev, sel, next
automatically woks on the active widgets, moving (prev
and next
) between the Buttons
and selecting (sel
) it. Well, I'm supposing that problem can be that my pushbuttons objects
are interfering with the simple.py
Screen Buttons at the moment that I change to this screen, like as the Button Yes (as it has the focus by default) still is recognized the pin as pressed and magically press the Yes Button
. Any idea how to solve that?
I did a horrible and very ugly thing to try to fix this problem.
In the def my_callback(button, arg):
of simple.py
I check the diff time
between when the def after_open(self):
is executed and when the def my_callback(button, arg):
is executed. If that time is less than 1 second
(by guarantee), means that the Yes button
was pressed "magically" and it is ignored.
def my_callback(button, arg):
print('Button pressed', arg)
end_time = time.ticks_ms()
delta_time = time.ticks_diff(end_time, self.start_time)
if delta_time > 1000: # 1 second by guarantee?
if arg == 'Yes':
self.env.change_to_screen = 'ScreenTempValues'
Screen.shutdown()
elif arg == 'No':
self.env.change_to_screen = 'ScreenResetAlPtSel'
Screen.shutdown()
def prev_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print('Do nothing')
def sel_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print('Do nothing')
def next_screen(self, arg):
print(f'Pushbutton pressed: {arg}')
print('Do nothing')
def after_open(self):
self.prev_btn.press_func(self.prev_screen, ('prev screen',))
self.sel_btn.press_func(self.sel_screen, ('sel screen',))
self.next_btn.press_func(self.next_screen, ('next screen',))
self.start_time = time.ticks_ms()
Do you have a better way to solve that?
Thank you so much!
@peterhinch I'm sorry, I just realized now that I can to change the color_map[FOCUS]
in each Screen at the real time, so yes, I using now the color_map[FOCUS] = BLACK
on the Screens that do not have active widgets (just that invisible Checkbox) and using color_map[FOCUS] = WHITE
on the Screens with active widgets like as the simple.py
All are working perfect, except that problem when I change do Screen simple.py
, where the Yes
Button is pressed automatically/magically. I did more research and tests, but I still not figure out how to solve that design. If you have any idea about that, please, let me know and I can to test/implement. I think that fixing this last one problem, maybe you can to put in the docs that new users that want to use micro-gui
in the tiny Display using this idea is excellent. I can to share a very simple code as start point for people that want to use this idea!
Thank you so much
Edit: I'm almost sure that Yes
Button is pressed automatically because when the my pushbutton object
sel
select to change to Screen simple.py
, when the Screen simple.py
loads, the pin sel
pushbutton object
still is pressed and as the Yes
Button has the focus, and the sel
of the hardware_setup.py
use the same pin of my pushbutton object
sel
, so the Yes
Button is pressed. Well, do you have any idea how to solve this problem?
I can to change the color_map[FOCUS] in each Screen at the real time
That was what I had in mind. Sorry if I didn't make this clear.
Re pushbutton
, screen controls such as Button
instances are activated on pushbutton
release (code). This is done to cater for the case where (say) the close button on a screen is pressed. Typically the close button on the screen below would be in the same place. If buttons operated on pushbutton
press, all screens below would close and the application would terminate.
To fit this paradigm you want the action which closes an overlaying screen to take place on pushbutton
release.
Hi @peterhinch
Re
pushbutton
, screen controls such asButton
instances are activated onpushbutton
release (code). This is done to cater for the case where (say) the close button on a screen is pressed. Typically the close button on the screen below would be in the same place. If buttons operated onpushbutton
press, all screens below would close and the application would terminate.
I understood perfectly well, thanks for that explanation.
To fit this paradigm you want the action which closes an overlaying screen to take place on
pushbutton
release.
Now I changed to do exactly that: now the simple.py
Screen is changed just on the pushbutton
release self.sel_btn.release_func()
from the previous Screen. But that do not solved the problem - still pressing automatically the Yes
Button on the simple.py
. Maybe is that still happening because I have two pushbutton
sel
on the same pin, and the hardware_setup_.py
sel
pushbutton
still recognizing that pin released with a delay?
Hello @peterhinch
I did a test to check if the pin still pressed just before to change to the simple.py
Screen. I put a print(sel_pin.value())
on the pushbutton
release callback
on the previous Screen at the simple.py
Screen. I can to confirm that the pin used by my pushbutton
sel
and hardware_setup.py
pushbutton
sel
is NOT pressed anymore. So, how is possible when change to the simple.py
Screen it is pressing automatically the Yes
Button?
Previous Screen of simple.py
:
def release_sel_screen(self, arg):
print(f'Pushbutton released: {arg}')
self.env.change_to_screen = 'simple_screen'
print(sel_pin.value())
Screen.shutdown()
def after_open(self):
self.sel_btn.release_func(self.release_sel_screen, ('sel screen - release',))
After that shutdown()
, the control back to main_screen()
function that change to Screen passed to the self.env.change_to_screen
variable - that is the simple.py
Screen
Hello Peter
I did read many docs and many tests but unfortunately I yet do not found how to solve that problem that still pressing automatically the Yes Button
on the simple.py
even that the previous Screen
is changing to the simple.py
just on the pushbutton
release
The only ugly work around that I found to try to solve that is checking if Yes and No Button
on the simple.py
was pressed after a time (using time.ticks_diff
), like as 1200ms
, as follow. Below is just the relevant code:
class BaseScreen(Screen):
def __init__(self):
self.start_time = None
def my_callback(button, arg):
end_time = time.ticks_ms()
delta_time = time.ticks_diff(end_time, self.start_time)
if delta_time > 1200:
if arg == 'yes':
self.env.change_to_screen = 'ScreenTempValues'
elif arg == 'no':
self.env.change_to_screen = 'ScreenResetAlPtSel'
Screen.shutdown()
else:
print('Button pressed automatically')
def after_open(self):
self.start_time = time.ticks_ms()
Can that be a Bug?
Please, if you have any idea how to solve that, or any suggestion, I will appreciate!
Thank you
Hello @peterhinch
I'm using
micro-gui
with thessd1306
mono display (128 x 64
) with three buttons, but themicro-gui
is showing in all demos a strange symbol (like as a trash) on the top right side. Why that symbol and how to remove?Here a screenshot showing that trash symbol inside the green circle using
demo/simple.py
:As I'm using a mono display I just changed the
simple.py
:CWriter
toWriter
wri = CWriter(ssd, arial10, GREEN, BLACK)
towri = Writer(ssd, arial10)
gui/demos/simple.py:
Output:
My hardware_setup.py:
The
ssd1306.py
is from official micropython driver.Thank you!