Comments (4)
Well, i pretty understand avoidance of verbosity, var names cluttering and building UIs through ui
object only. My point was actually more about pythonic explicit way of coding PEP20
>>> import this
The Zen of Python, by Tim Peters
...
Explicit is better than implicit.
...
I think if you mention the concept with a few details in the documentation(your explanation above, for example) it would keep people away of being a bit confused on it as they can follow the idea. I mostly mean a python developers category.
from nicegui.
Hi, thanks for reporting this issue! I think I can explain what is going on an how to fix your example.
By default NiceGUI starts a uvicorn server with auto-reload activated. This already happens during import and that's why the main script (run.py in your case) blocks within from nicegui import ui
and never reaches the main guard. The uvicorn reloader takes over and runs your script, but the reloader is not __main__
. We chose this approach because we like working with auto-reload very much and wanted to avoid evaluating the main script twice, once with the server and once with the auto-reload mechanism.
You can either remove the main guard or at least move ui = initialize()
one line up. Or you disable auto-reload with ui.run(reload=False)
. Then the server is only started during ui.run
and the control flow is as expected.
With some clean up here and there, this is your resulting code:
repr_layer.py
from nicegui import ui
def add_elements(container):
with container:
result = 'something'
ui.label(result)
def initialize_ui():
ui.label('Any label')
row = ui.row()
ui.button('+', on_click=lambda: add_elements(row))
return ui
run.py
from repr_layer import initialize_ui
if __name__ == '__main__':
ui = initialize_ui()
ui.run(reload=False)
Notes:
- no need to import
ui
in run.py - no need for
container.update()
(happens automatically when leaving thecontainer
scope) ui.label
instead ofcontainer.label
- added
'+'
(just because why not)
Let me drop a few thoughts about the OOP design decisions you mentioned.
Implicit nesting via scopes
We wanted NiceGUI to be an intuitive API for creating user interfaces. UIs are typically hierarchically organized and markup languages like HTML reflect that visually:
<div id="container">
<div id="box">
<p>Hello world!</p>
</div>
</div>
That's why we wanted a UI description with NiceGUI to have a similar form:
with ui.card():
with ui.row():
ui.label('Hello world!')
JustPy, on the other hand, becomes tricky to read when nesting UI elements:
container = Div()
box = Div()
label = Div(text='Hello world!')
box.add(label)
container.add(box)
(Sure, you could create some objects inline. But if you need their references, it clutters quickly.)
Thus, with NiceGUI you don't create hierarchy via parent
/children
arguments or add/insert
methods, but via indentation and scoping. I.e. using a with
statement opens a scope and new elements are automatically nested there. This is unusual, but turns out very handy.
Constructors as functions with side-effects
A function like ui.label
is actually a constructor of a Label
object. But we chose to use lowercase names in order to indicate the function-like behavior. Besides creating an object ui.label
, modifies the UI. In many cases, you don't event need the object reference.
Again, compared to an approach like JustPy, we think NiceGUI is more convenient.
Comparison to Streamlit
Streamlit and its weird control flow was actually the motivation for us to write NiceGUI. See #21 for a more detailed discussion.
from nicegui.
Thank you for the details. I tested both ways out.
Not working
With the reloading disabled a web server isn't getting started.
from repr_layer import initialize_ui
if __name__ == '__main__':
ui = initialize_ui()
ui.run(reload=False)
Working
With the main guard removed it works. That's my choice.
Comment on the concept
That's why we wanted a UI description with NiceGUI to have a similar form:
with ui.card(): with ui.row(): ui.label('Hello world!')
You know, it's quite intuitive and i like this approach, but let me ask you why do we use ui
object in nesting? In my opinion, subelements should be explicitly added to their parent one, label
to row
in the example above, but not to the root ui
element:
with ui.card() as card:
with card.row() as row:
row.label('Hello world!')
Now, from an html perspective, i see adding subelements as follow:
<body> <!-- let's suppose that's `ui` element -->
<subelement> <!-- code line such as `with ui.row(): ui.subelement()` in my mind is placed here and it is NOT correct-->
<div id="container">
<div id="box">
<p>Hello world!</p>
<subelement> <!-- would code line `with ui.row() as row: row.subelement()` in your mind places an element here? -->
</div>
</div>
</body>
Anyway, i enjoy Nicegui. Get my comment as a review only π
from nicegui.
The "not working" example using reload=False
works for me. You might just need to restart the script, since changes to ui.run
arguments are ignored during auto-reload. Or maybe there's something else I'm missing. Glad to here that it works without the main guard.
Regarding your comments on our concept: Thanks for the interesting thoughts! It's quiet fun to juggle with the different possibilities a languange like Python gives you to create an API.
Let me elaborate a bit on your example:
with ui.card() as card:
with card.row() as row:
row.label('Hello world!')
I see your point. The ui.scene
container is actually an example where we followed this approach. In order to separate the list of 3D objects from the "regular" UI elements, they are created like
with ui.scene() as scene:
scene.sphere()
So introducing a new 3D object label
would not conflict with ui.label
. But for UI elements we chose to use the short namespace ui
. Consider the following example with some more containers:
with ui.card() as main_card:
with card.row() as info_row:
info_row.label('Time:')
info_row.label('CPU%:')
info_row.label('RAM%:')
with card.row() as button_row:
button_row.button('Start')
button_row.button('Pause')
button_row.button('Stop')
Repeating the container names is pretty verbose, given the indentation already defines the hierarchy. Sure, you could use names like row1
and row2
or r1
and r2
, but this isn't very readable and your namespace get's spoiled quickly. In large UIs you might have to search for free variable names. Or you use the same row
for each row, but I'm not sure if this is good practice. And changing the layout (e.g. from row to column) requires you to change row
into column
many times.
Besides that, your approach would clutter the namespace of, e.g., a card: Is card.color
a property or does it create a new UI element of type color
? Your IDEs auto-suggestions will become less helpful.
from nicegui.
Related Issues (20)
- `Uncaught TypeError: Cannot set properties of undefined (setting 'Matter')` while initializing a custom Vue component
- how to get ui.label value HOT 1
- Infinite_scroll example broken on Safari HOT 5
- Nesting cards merges the elements HOT 6
- How to read Clipboard'image in my page ,uploader? or others module?
- Updating NiceGUI broke existing project with "missing client_id" error HOT 2
- Significant issue version 1.4.8 in windows HOT 1
- ui.code copy button inside ui.card dialog overlaps content HOT 5
- Documentation page automatically refreshes HOT 12
- Large number of bindings will block the main loop HOT 3
- How to integrate pyecharts with JScode in tooltip?
- The imported file was executed twiceγ
- Make Slot class better
- Plotly double click to zoom out doesn't work HOT 2
- Internal Server Error : Upgrade from 1.4.7 to 1.4.9 HOT 3
- EChart collapses when nested in a row element HOT 6
- AttributeError: 'WindowsPath' object has no attribute 'with_stem' HOT 3
- how to create a neural network graph like netron? HOT 1
- nicegui ui.dialog slow/not smooth on Firefox on Android HOT 4
- Performance issues in `binding.py`'s `remove` function causing high CPU usage HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nicegui.