Vereinfachtes Chinesisch | Englisch
Erweiterungsbibliothek für NiceGui. Integrierte reaktionsschnelle Komponenten, vollständig implementierende Datenreaktionsschnittstellenprogrammierung.
Weitere Beispiele sehen
Schlagzeilenartikel - Offizielle Implementierung von Flash Sale, Python Interface Library, NiceGui mit 90% Ereigniscode entfernt
WeChat Official Account - Offizielle Implementierung von Flash Sale, Python Interface Library, NiceGui mit 90% Ereigniscode entfernt
pip install ex4nicegui -U
Wir beginnen mit einer einfachen Zähleranwendung, bei der Benutzer die Anzahl durch Klicken auf eine Schaltfläche erhöhen oder verringern können.
Hier ist der vollständige Code:
from nicegui import ui
from ex4nicegui import rxui
# 数据状态代码
class Counter ( rxui . ViewModel ):
count : int = 0
def increment ( self ):
self . count += 1
def decrement ( self ):
self . count -= 1
# 界面代码
counter = Counter ()
with ui . row ( align_items = "center" ):
ui . button ( icon = "remove" , on_click = counter . decrement )
rxui . label ( counter . count )
ui . button ( icon = "add" , on_click = counter . increment )
ui . run () Weitere Informationen finden Sie jetzt. ex4nicegui folgt der datengesteuerten Methode, um die Schnittstelle zu definieren. Statusdaten definieren alle Daten, die in der Anwendung geändert werden können.
Das Folgende ist Counter Datendatendefinition der Zählerstatus:
class Counter ( rxui . ViewModel ):
count : int = 0rxui.ViewModel erbencount , die den aktuellen Wert des Zählers mit einem Anfangswert von 0 darstellt.Definieren Sie als nächstes eine Reihe von Methoden zum Manipulieren von Daten in der Klasse:
def increment ( self ):
self . count += 1
def decrement ( self ):
self . count -= 1count ändern können Dann im Schnittstellencode Counter Zählerobjekt instanziieren.
counter = Counter () Wir binden die count durch die rxui.label -Komponente. Binden Sie die Methode zur Manipulation von Daten an die Schaltfläche Klicken Sie auf.
ui . button ( icon = "remove" , on_click = counter . decrement )
rxui . label ( counter . count )
ui . button ( icon = "add" , on_click = counter . increment )label unter dem rxui -Namespace verwenden, nicht label im nicegui -Namespace.rxui.label rxui.label bindet die Variable counter.count counter.count .ui.button -Komponente bindet counter.decrement counter.incrementIn komplexen Projekten kann
Counter-definierte Code in separate Module platziert und dann in Schnittstellencode importiert werden.
Beachten Sie, dass der Datenstatus, wenn der Name der Klassenvariablen unterstrichen ist, der Datenstatus nicht automatisch aktualisiert wird.
class Counter ( rxui . ViewModel ):
count : int = 0 # 响应式数据,能自动同步界面
_count : int = 0 # 这里的下划线表示私有变量,不会自动同步界面Neben dem vorherigen Beispiel fügen wir eine weitere Funktion hinzu. Wenn der Zählerwert weniger als 0 ist, wird die Schriftart rot angezeigt. Wenn er größer als 0 ist, wird er grün angezeigt, ansonsten wird er in Schwarz angezeigt.
# 数据状态代码
class Counter ( rxui . ViewModel ):
count : int = 0
def text_color ( self ):
if self . count > 0 :
return "green"
elif self . count < 0 :
return "red"
else :
return "black"
def increment ( self ):
self . count += 1
def decrement ( self ):
self . count -= 1
# 界面代码
counter = Counter ()
with ui . row ( align_items = "center" ):
ui . button ( icon = "remove" , on_click = counter . decrement )
rxui . label ( counter . count ). bind_color ( counter . text_color )
ui . button ( icon = "add" , on_click = counter . increment )Der Farbwert wird basierend auf dem aktuellen Wert des Zählers berechnet. Es gehört zu einer sekundären Berechnung. Definieren Sie einfach normale Instanzfunktionen.
def text_color ( self ):
if self . count > 0 :
return "green"
elif self . count < 0 :
return "red"
else :
return "black" Anschließend wird text_color -Methode durch die bind_color -Methode der rxui.label -Komponente gebunden, sodass der Farbwert automatisch aktualisiert wird.
rxui . label ( counter . count ). bind_color ( counter . text_color )Jetzt verwenden wir Text unterhalb des Zählers, um den Farbtextwert des aktuellen Zählers anzuzeigen.
...
# 数据状态代码
class Counter ( rxui . ViewModel ):
...
# 界面代码
counter = Counter ()
with ui . row ( align_items = "center" ):
ui . button ( icon = "remove" , on_click = counter . decrement )
rxui . label ( counter . count ). bind_color ( counter . text_color )
ui . button ( icon = "add" , on_click = counter . increment )
rxui . label ( lambda : f"当前计数器值为 { counter . count } , 颜色值为 { counter . text_color () } " ) Im obigen Code gibt es zwei Stellen, an denen die counter.text_color verwendet werden.TEXT_COLOR -Methode. Wenn sich counter.count ändert, führt counter.text_color zwei Berechnungen durch. Die zweite Berechnung ist überflüssig.
Um unnötige Berechnungen zu vermeiden, können wir den Zähler counter.text_color .
# 数据状态代码
class Counter ( rxui . ViewModel ):
count : int = 0
@ rxui . cached_var
def text_color ( self ):
if self . count > 0 :
return "green"
elif self . count < 0 :
return "red"
else :
return "black"rxui.cached_var kann die Funktionsergebnisse zwischenspeichern, um unnötige Berechnungen zu vermeiden.Das folgende Beispiel zeigt, wie die Liste verwendet wird.
class AppState ( rxui . ViewModel ):
nums = []
# nums = [1,2,3] 如果需要初始化,必须在 __init__ 中设置
def __init__ ( self ):
super (). __init__ ()
self . nums = [ 1 , 2 , 3 ]
def append ( self ):
new_num = max ( self . nums ) + 1
self . nums . append ( new_num )
def pop ( self ):
self . nums . pop ()
def reverse ( self ):
self . nums . reverse ()
def display_nums ( self ):
return ", " . join ( map ( str , self . nums ))
# 界面代码
state = AppState ()
with ui . row ( align_items = "center" ):
ui . button ( "append" , on_click = state . append )
ui . button ( "pop" , on_click = state . pop )
ui . button ( "reverse" , on_click = state . reverse )
rxui . label ( state . display_nums ) Wenn Sie die Liste initialisieren müssen, wenn Sie die Liste definieren, wird empfohlen, sie in __init__ festzulegen.
class AppState ( rxui . ViewModel ):
nums = []
# nums = [1,2,3] 如果需要初始化,必须在 __init__ 中设置
def __init__ ( self ):
super (). __init__ ()
self . nums = [ 1 , 2 , 3 ]
... Eine andere Möglichkeit besteht darin, rxui.list_var zu verwenden
class AppState ( rxui . ViewModel ):
# nums = []
# nums = [1,2,3] 如果需要初始化,必须在 __init__ 中设置
nums = rxui . list_var ( lambda : [ 1 , 2 , 3 ])
...rxui.list_var ist eine Funktion, die eine Liste zurückgibt Nach dem Definieren der Liste können wir den Dekorator effect_refreshable.on verwenden, um die Listendaten in der Schnittstelle anzuzeigen.
Im folgenden Beispiel wird in der Schnittstelle die im Dropdown-Box ausgewählten Symbole dynamisch angezeigt.
from ex4nicegui import rxui , effect_refreshable
class AppState ( rxui . ViewModel ):
icons = []
_option_icons = [ "font_download" , "warning" , "format_size" , "print" ]
state = AppState ()
# 界面代码
with ui . row ( align_items = "center" ):
@ effect_refreshable . on ( state . icons )
def _ ():
for icon in state . icons :
ui . icon ( icon , size = "2rem" )
rxui . select ( state . _option_icons , value = state . icons , multiple = True ) Unter ihnen gibt @effect_refreshable.on(state.icons) explizit die Abhängigkeit an. Wenn sich state.icons ändert, wird die _ Funktion erneut ausgesetzt.
@ effect_refreshable . on ( state . icons )
def _ ():
# 这里的代码会在 state.icons 变化时重新执行
...Beachten Sie, dass jedes Mal, wenn Sie ausführen, der Inhalt im Inhalt gelöscht wird. Dies ist die datengesteuerte Version von
ui.refreshable
Im Prinzip können die überwachten Daten automatisch ohne Angabe .on überwacht werden.
@ effect_refreshable # 没有使用 .on(state.icons)
def _ ():
# 这里读取了 state.icons,因此会自动监控
for icon in state . icons :
ui . icon ( icon , size = "2rem" )Es wird empfohlen, immer Abhängigkeiten durch
.onanzugeben, um unerwartete Aktualisierungen zu vermeiden
ViewModel verwendet Proxy -Objekte, um reaktionsschnelle Daten zu erstellen. Wenn Daten speichern müssen, können Sie rxui.ViewModel.to_value verwenden, um sie in normale Daten umzuwandeln.
Im folgenden Beispiel wird im Klicken auf die Schaltfläche das Statusdaten -Wörterbuch von my_app angezeigt.
from nicegui import ui
from ex4nicegui import rxui
class MyApp ( rxui . ViewModel ):
a = 0
sign = "+"
b = 0
def show_data ( self ):
# >> {"a": 0, "sign": '+, "b": 0}
return rxui . ViewModel . to_value ( self )
def show_a ( self ):
# >> 0
return rxui . ViewModel . to_value ( self . a )
my_app = MyApp ()
rxui . number ( value = my_app . a , min = 0 , max = 10 )
rxui . radio ([ "+" , "-" , "*" , "/" ], value = my_app . sign )
rxui . number ( value = my_app . b , min = 0 , max = 10 )
ui . button ( "show data" , on_click = lambda : ui . notify ( my_app . show_data ())) In Kombination mit rxui.ViewModel.on_refs_changed können Daten automatisch auf dem lokalen Bereich gespeichert werden, wenn sich die Daten ändern.
from nicegui import ui
from ex4nicegui import rxui
from pathlib import Path
import json
class MyApp ( rxui . ViewModel ):
a = 0
sign = "+"
b = 0
_json_path = Path ( __file__ ). parent / "data.json"
def __init__ ( self ):
super (). __init__ ()
@ rxui . ViewModel . on_refs_changed ( self )
def _ ():
# a, sign, b 任意一个值变化时,自动保存到本地
self . _json_path . write_text ( json . dumps ( self . show_data ()))
def show_data ( self ):
return rxui . ViewModel . to_value ( self )
...to_refdeep_refeffectref_computedasync_computedonnew_scopebi.data_source In v0.7.0 wurde ViewModel -Klasse eingeführt, um eine Reihe von Reaktionsdaten zu verwalten.
Hier ist ein einfacher Taschenrechnerbeispiel:
from ex4nicegui import rxui
class Calculator ( rxui . ViewModel ):
num1 = 0
sign = "+"
num2 = 0
@ rxui . cached_var
def result ( self ):
# 当 num1,sign,num2 任意一个值发生变化时,result 也会重新计算
return eval ( f" { self . num1 } { self . sign } { self . num2 } " )
# 每个对象拥有独立的数据
calc = Calculator ()
with ui . row ( align_items = "center" ):
rxui . number ( value = calc . num1 , label = "Number 1" )
rxui . select ( value = calc . sign , options = [ "+" , "-" , "*" , "/" ], label = "Sign" )
rxui . number ( value = calc . num2 , label = "Number 2" )
ui . label ( "=" )
rxui . label ( calc . result ). bind_color (
lambda : "red" if calc . result () < 0 else "black"
) Im folgenden Beispiel verwendet jede Person eine Karte zum Anzeigen. Die Spitze zeigt das Durchschnittsalter aller Menschen. Wenn die Person älter als das Durchschnittsalter ist, wird der äußere Rand der Karte rot. Ändern Sie das Alter durch number und alles wird automatisch aktualisiert.
from typing import List
from ex4nicegui import rxui
from itertools import count
from nicegui import ui
id_generator = count ()
class Person ( rxui . ViewModel ):
name = ""
age = 0
def __init__ ( self , name : str , age : int ):
super (). __init__ ()
self . name = name
self . age = age
self . id = next ( id_generator )
class Home ( rxui . ViewModel ):
persons : List [ Person ] = []
deleted_person_index = 0
@ rxui . cached_var
def avg_age ( self ) -> float :
if len ( self . persons ) == 0 :
return 0
return round ( sum ( p . age for p in self . persons ) / len ( self . persons ), 2 )
def avg_name_length ( self ):
if len ( self . persons ) == 0 :
return 0
return round ( sum ( len ( p . name ) for p in self . persons ) / len ( self . persons ), 2 )
def delete_person ( self ):
if self . deleted_person_index < len ( self . persons ):
del self . persons [ int ( self . deleted_person_index )]
def sample_data ( self ):
self . persons = [
Person ( "alice" , 25 ),
Person ( "bob" , 30 ),
Person ( "charlie" , 31 ),
Person ( "dave" , 22 ),
Person ( "eve" , 26 ),
Person ( "frank" , 29 ),
]
home = Home ()
home . sample_data ()
rxui . label ( lambda : f"平均年龄: { home . avg_age () } " )
rxui . label ( lambda : f"平均名字长度: { home . avg_name_length () } " )
rxui . number (
value = home . deleted_person_index , min = 0 , max = lambda : len ( home . persons ) - 1 , step = 1
)
ui . button ( "删除" , on_click = home . delete_person )
with ui . row ():
@ rxui . vfor ( home . persons , key = "id" )
def _ ( store : rxui . VforStore [ Person ]):
person = store . get_item ()
with rxui . card (). classes ( "outline" ). bind_classes (
{
"outline-red-500" : lambda : person . age > home . avg_age (),
}
):
rxui . input ( value = person . name , placeholder = "名字" )
rxui . number ( value = person . age , min = 1 , max = 100 , step = 1 , placeholder = "年龄" )
ui . run () Wenn Sie der Meinung sind, dass der Code rxui.vfor zu kompliziert ist, können Sie stattdessen effect_refreshable Decorator verwenden.
from ex4nicegui import rxui , Ref , effect_refreshable
...
# 明确指定监控 home.persons 变化,可以避免意外刷新
@ effect_refreshable . on ( home . persons )
def _ ():
for person in home . persons . value :
...
rxui . number ( value = person . age , min = 1 , max = 100 , step = 1 , placeholder = "年龄" )
... Es ist zu beachten, dass sich die von effect_refreshable dekorierte Funktion erneut ausführen, wenn home.persons -Liste ändert (z. B. Elemente des Hinzufügens oder des Löschens von Elementen). Das heißt, alle Elemente werden neu erstellt.
Für komplexere Anwendungen können Sie Beispiele anzeigen
from ex4nicegui import (
to_ref ,
ref_computed ,
on ,
effect ,
effect_refreshable ,
batch ,
event_batch ,
deep_ref ,
async_computed
) Am häufig verwendeten to_ref , deep_ref , effect , ref_computed , on , async_computed
to_ref Definieren Sie reaktionsschnelle Objekte, lesen und schreiben Sie durch .value
a = to_ref ( 1 )
b = to_ref ( "text" )
a . value = 2
b . value = 'new text'
print ( a . value )Wenn der Wert ein komplexes Objekt ist, reagiert das verschachtelte Objekt standardmäßig nicht.
a = to_ref ([ 1 , 2 ])
@ effect
def _ ():
print ( 'len:' , len ( a . value ))
# 不会触发 effect
a . value . append ( 10 )
# 整个替换则会触发
a . value = [ 1 , 2 , 10 ] Wenn der Parameter is_deep auf True eingestellt ist, kann die tiefe Antwortfunktion erhalten werden.
a = to_ref ([ 1 , 2 ], is_deep = True )
@ effect
def _ ():
print ( 'len:' , len ( a . value ))
# print 3
a . value . append ( 10 )
deep_refentsprichtto_ref, wennis_deepaufTrueeingestellt ist
deep_ref Äquivalent zu to_ref wenn is_deep auf True eingestellt ist.
Besonders nützlich, wenn die Datenquelle eine Liste, ein Wörterbuch oder eine benutzerdefinierte Klasse ist. Objekte, die durch .value erhalten wurden, sind Proxy -Objekte
data = [ 1 , 2 , 3 ]
data_ref = deep_ref ( data )
assert data_ref . value is not data Das ursprüngliche Objekt kann über to_raw erhalten werden
from ex4nicegui import to_raw , deep_ref
data = [ 1 , 2 , 3 ]
data_ref = deep_ref ( data )
assert data_ref . value is not data
assert to_raw ( data_ref . value ) is data effectAkzeptieren Sie eine Funktion und überwachen Sie automatisch die Änderungen des in der Funktion verwendeten Responsive -Objekts, wodurch die Funktion automatisch ausgeführt wird
a = to_ref ( 1 )
b = to_ref ( "text" )
@ effect
def auto_run_when_ref_value ():
print ( f"a: { a . value } " )
def change_value ():
a . value = 2
b . value = "new text"
ui . button ( "change" , on_click = change_value ) Wenn der Effekt zum ersten Mal ausgeführt wird, wird die Funktion auto_run_when_ref_value einmal ausgeführt. Klicken Sie danach auf die Schaltfläche und ändern Sie den Wert a (durch a.value ), und die Funktion auto_run_when_ref_value wird erneut ausgeführt.
Streiten Sie keine große Menge an Datenverarbeitungslogik in mehrfachem
onodereffect. Der größte Teilonoder dereffectsollte die Logik der Schnittstellenbetriebslogik sein und nicht ansprechende Datenverarbeitungslogik.
ref_computed Mit der gleichen Funktion wie effect kann ref_computed auch das Ergebnis aus der Funktion zurückgeben. Allgemein verwendet, um quadratische Berechnungen von to_ref durchzuführen
a = to_ref ( 1 )
a_square = ref_computed ( lambda : a . value * 2 )
@ effect
def effect1 ():
print ( f"a_square: { a_square . value } " )
def change_value ():
a . value = 2
ui . button ( "change" , on_click = change_value ) Nach dem Klicken auf die Schaltfläche wird der a.value -Value -Wert modifiziert, der eine Neuberechnung a_square auslöst. Da der Wert von a_square in effect1 gelesen wird, wird effect1 -Ausführung ausgelöst.
ref_computedist nur schreibgeschütztto_ref
Ab v0.7.0 wird nicht empfohlen, ref_computed Application Instance -Methode zu verwenden. Sie können rxui.ViewModel verwenden und rxui.cached_var Decorator verwenden
class MyState ( rxui . ViewModel ):
def __init__ ( self ) -> None :
self . r_text = to_ref ( "" )
@ rxui . cached_var
def post_text ( self ):
return self . r_text . value + "post"
state = MyState ()
rxui . input ( value = state . r_text )
rxui . label ( state . post_text )async_computed Verwenden Sie bei Verwendung asynchroner Funktionen in Sekundärberechnungen async_computed
# 模拟长时间执行的异步函数
async def long_time_query ( input : str ):
await asyncio . sleep ( 2 )
num = random . randint ( 20 , 100 )
return f"query result[ { input = } ]: { num = } "
search = to_ref ( "" )
evaluating = to_ref ( False )
@ async_computed ( search , evaluating = evaluating , init = "" )
async def search_result ():
return await long_time_query ( search . value )
rxui . lazy_input ( value = search )
rxui . label (
lambda : "查询中" if evaluating . value else "上方输入框输入内容并回车搜索"
)
rxui . label ( search_result )async_computed muss explizit die reaktionsschnellen Daten angeben, die überwacht werden müssen. Verwenden Sie Listen, um mehrere reaktionsschnelle Daten gleichzeitig anzugeben.evaluating sind ansprechende Daten des Bool -Typs. Wenn die asynchrone Funktion ausgeführt wird, ist der Wert dieser Variablen True und nach Abschluss der Berechnung False .init gibt das erste Ergebnis an on Ähnlich wie bei effect , aber on muss das responsive Objekt überwacht werden
a1 = to_ref ( 1 )
a2 = to_ref ( 10 )
b = to_ref ( "text" )
@ on ( a1 )
def watch_a1_only ():
print ( f"watch_a1_only ... a1: { a1 . value } ,a2: { a2 . value } " )
@ on ([ a1 , b ], onchanges = True )
def watch_a1_and_b ():
print ( f"watch_a1_and_b ... a1: { a1 . value } ,a2: { a2 . value } ,b: { b . value } " )
def change_a1 ():
a1 . value += 1
ui . notify ( "change_a1" )
ui . button ( "change a1" , on_click = change_a1 )
def change_a2 ():
a2 . value += 1
ui . notify ( "change_a2" )
ui . button ( "change a2" , on_click = change_a2 )
def change_b ():
b . value += "x"
ui . notify ( "change_b" )
ui . button ( "change b" , on_click = change_b )onchanges true ist (der Standardwert ist falsch), wird die angegebene Funktion während der Bindung nicht ausgeführt.Streiten Sie keine große Menge an Datenverarbeitungslogik in mehrfachem
onodereffect. Der größte Teilonoder dereffectsollte die Logik der Schnittstellenbetriebslogik sein und nicht ansprechende Datenverarbeitungslogik.
new_scope Standardmäßig werden alle Erkennungsfunktionen automatisch zerstört, wenn die Clientverbindung getrennt ist. Wenn eine feinkörnige Kontrolle erforderlich ist, können Sie new_scope verwenden
from nicegui import ui
from ex4nicegui import rxui , to_ref , effect , new_scope
a = to_ref ( 0.0 )
scope1 = new_scope ()
@ scope1 . run
def _ ():
@ effect
def _ ():
print ( f"scope 1: { a . value } " )
rxui . number ( value = a )
rxui . button ( "dispose scope 1" , on_click = scope1 . dispose )Erstellen Sie eine Zwei-Wege-Bindung an einem Formulareingangselement oder -komponente.
ref von einfachen Werttypen unterstützen standardmäßig die Zwei-Wege-Bindung
from ex4nicegui import rxui , to_ref , deep_ref
data = to_ref ( "init" )
rxui . label ( lambda : f" { data . value = } " )
# 默认就是双向绑定
rxui . input ( value = data )str , int, int Bei der Verwendung komplexer Datenstrukturen wird deep_ref verwendet, um die Reaktionsfähigkeit verschachtelter Werte aufrechtzuerhalten
data = deep_ref ({ "a" : 1 , "b" : [ 1 , 2 , 3 , 4 ]})
rxui . label ( lambda : f" { data . value = !s } " )
# 当前版本没有任何绑定效果.或许未来的版本可以解决
rxui . input ( value = data . value [ "a" ])
# 只读绑定.其他途径修改了 `data.value["a"]` ,此输入框会同步,但反过来不行
rxui . input ( value = lambda : data . value [ "a" ])
# 要使用 vmodel 才能双向绑定
rxui . input ( value = rxui . vmodel ( data , "a" ))
# 也可以直接使用,但不推荐
rxui . input ( value = rxui . vmodel ( data . value [ 'a' ]))rxui.input(value=1) entspricht.rxui.vmodel verpackt istWenn Sie
rxui.ViewModelverwenden, müssen Sie wahrscheinlich keinvmodelverwenden
Sie können sich auf den Fall der Todo -Liste beziehen
Listenkomponenten basierend auf List Responsive Data. Jede Komponente wird bei Bedarf aktualisiert. Datenelemente unterstützen Wörterbücher oder Objekte jeglicher Art.
Ab v0.7.0 wird empfohlen, es mit rxui.ViewModel zu verwenden. Im Gegensatz zur Verwendung effect_refreshable Decorators erstellt vfor nicht alle Elemente, sondern aktualisiert vorhandene Elemente.
Im Folgenden finden Sie ein Beispiel für die Sortierung von Karten, Karten werden immer nach Alter sortiert. Wenn Sie die Altersdaten in einer Karte ändern, passt die Karten die Reihenfolge in Echtzeit an. Der Cursorfokus hinterlässt jedoch nicht das Eingabefeld.
from typing import List
from nicegui import ui
from ex4nicegui import rxui , deep_ref as ref , Ref
class Person ( rxui . ViewModel ):
def __init__ ( self , name : str , age : int ) -> None :
self . name = name
self . age = ref ( age )
class MyApp ( rxui . ViewModel ):
persons : Ref [ List [ Person ]] = rxui . var ( lambda : [])
order = rxui . var ( "asc" )
def sort_by_age ( self ):
return sorted (
self . persons . value ,
key = lambda p : p . age . value ,
reverse = self . order . value == "desc" ,
)
@ staticmethod
def create ():
persons = [
Person ( name = "Alice" , age = 25 ),
Person ( name = "Bob" , age = 30 ),
Person ( name = "Charlie" , age = 20 ),
Person ( name = "Dave" , age = 35 ),
Person ( name = "Eve" , age = 28 ),
]
app = MyApp ()
app . persons . value = persons
return app
# ui
app = MyApp . create ()
with rxui . tabs ( app . order ):
rxui . tab ( "asc" , "Ascending" )
rxui . tab ( "desc" , "Descending" )
@ rxui . vfor ( app . sort_by_age , key = "name" )
def each_person ( s : rxui . VforStore [ Person ]):
person = s . get_item ()
with ui . card (), ui . row ( align_items = "center" ):
rxui . label ( person . name )
rxui . number ( value = person . age , step = 1 , min = 0 , max = 100 )rxui.vfor -Dekorateur zur benutzerdefinierten Funktionapp.sort_by_age anzurufenkey : Um die Identität jedes Knotens zu verfolgen und vorhandene Elemente wiederzuverwenden und neu zu ordnen, können Sie einen eindeutigen Schlüssel für den entsprechenden Block jedes Elements bereitstellen. Listelementindex wird standardmäßig verwendet. Im Beispiel wird angenommen, dass der Name eines jeden einzigartig ist.store.get_item erhalten werden. Da die Person selbst von rxui.ViewModel erbt, können ihre verschiedenen Eigenschaften direkt an die Komponente gebunden werden. Alle Komponentenklassen liefern bind_classes für class und unterstützen drei verschiedene Datenstrukturen.
Binden Sie das Wörterbuch
bg_color = to_ref ( False )
has_error = to_ref ( False )
rxui . label ( "test" ). bind_classes ({ "bg-blue" : bg_color , "text-red" : has_error })
rxui . switch ( "bg_color" , value = bg_color )
rxui . switch ( "has_error" , value = has_error ) Der Wörterbuchschlüsselwert ist der Klassenname und der entsprechende Wert ist eine reaktionsschnelle Variable mit bool. Wenn der Reaktionswert True ist, wird der Klassenname auf die Komponentenklasse angewendet
Binden Sie reaktionsschnelle Variablen mit dem Rückgabewert als Wörterbuch ein
bg_color = to_ref ( False )
has_error = to_ref ( False )
class_obj = ref_computed (
lambda : { "bg-blue" : bg_color . value , "text-red" : has_error . value }
)
rxui . switch ( "bg_color" , value = bg_color )
rxui . switch ( "has_error" , value = has_error )
rxui . label ( "bind to ref_computed" ). bind_classes ( class_obj )
# or direct function passing
rxui . label ( "bind to ref_computed" ). bind_classes (
lambda : { "bg-blue" : bg_color . value , "text-red" : has_error . value }
)Ansprechvariablen, die an eine Liste oder eine einzelne Zeichenfolge gebunden sind
bg_color = to_ref ( "red" )
bg_color_class = ref_computed ( lambda : f"bg- { bg_color . value } " )
text_color = to_ref ( "green" )
text_color_class = ref_computed ( lambda : f"text- { text_color . value } " )
rxui . select ([ "red" , "green" , "yellow" ], label = "bg color" , value = bg_color )
rxui . select ([ "red" , "green" , "yellow" ], label = "text color" , value = text_color )
rxui . label ( "binding to arrays" ). bind_classes ([ bg_color_class , text_color_class ])
rxui . label ( "binding to single string" ). bind_classes ( bg_color_class ) from nicegui import ui
from ex4nicegui . reactive import rxui
from ex4nicegui . utils . signals import to_ref
bg_color = to_ref ( "blue" )
text_color = to_ref ( "red" )
rxui . label ( "test" ). bind_style (
{
"background-color" : bg_color ,
"color" : text_color ,
}
)
rxui . select ([ "blue" , "green" , "yellow" ], label = "bg color" , value = bg_color )
rxui . select ([ "red" , "green" , "yellow" ], label = "text color" , value = text_color ) bind_style , übergeben in das Wörterbuch, key ist der Stilname, der value der Stilwert und die reaktionsschnelle Zeichenfolge
Binden Sie ein einzelnes Attribut
label = to_ref ( "hello" )
rxui . button ( "" ). bind_prop ( "label" , label )
# 允许使用函数
rxui . button ( "" ). bind_prop (
"label" , lambda : f" { label . value } world"
)
rxui . input ( value = label )Verwenden Sie Echarts, um Diagramme zu erstellen
from nicegui import ui
from ex4nicegui import ref_computed , effect , to_ref
from ex4nicegui . reactive import rxui
r_input = to_ref ( "" )
# ref_computed 创建只读响应式变量
# 函数中使用任意其他响应式变量,会自动关联
@ ref_computed
def cp_echarts_opts ():
return {
"title" : { "text" : r_input . value }, #字典中使用任意响应式变量,通过 .value 获取值
"xAxis" : {
"type" : "category" ,
"data" : [ "Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" , "Sun" ],
},
"yAxis" : { "type" : "value" },
"series" : [
{
"data" : [ 120 , 200 , 150 , 80 , 70 , 110 , 130 ],
"type" : "bar" ,
"showBackground" : True ,
"backgroundStyle" : { "color" : "rgba(180, 180, 180, 0.2)" },
}
],
}
input = rxui . input ( "输入内容,图表标题会同步" , value = r_input )
# 通过响应式组件对象的 element 属性,获取原生 nicegui 组件对象
input . element . classes ( "w-full" )
rxui . echarts ( cp_echarts_opts )
ui . run ()
Verwenden Sie den on -Funktionsparameter event_name und query , um das chinesische Dokument Echarts -Ereignis anzuzeigen
Das folgende Beispiel bindet das Mausklickereignis
from nicegui import ui
from ex4nicegui . reactive import rxui
opts = {
"xAxis" : { "type" : "value" , "boundaryGap" : [ 0 , 0.01 ]},
"yAxis" : {
"type" : "category" ,
"data" : [ "Brazil" , "Indonesia" , "USA" , "India" , "China" , "World" ],
},
"series" : [
{
"name" : "first" ,
"type" : "bar" ,
"data" : [ 18203 , 23489 , 29034 , 104970 , 131744 , 630230 ],
},
{
"name" : "second" ,
"type" : "bar" ,
"data" : [ 19325 , 23438 , 31000 , 121594 , 134141 , 681807 ],
},
],
}
bar = rxui . echarts ( opts )
def on_click ( e : rxui . echarts . EChartsMouseEventArguments ):
ui . notify ( f"on_click: { e . seriesName } : { e . name } : { e . value } " )
bar . on ( "click" , on_click )Das folgende Beispiel löst das Maus -Swipe -Ereignis nur für die angegebene Serie aus
from nicegui import ui
from ex4nicegui . reactive import rxui
opts = {
"xAxis" : { "type" : "value" , "boundaryGap" : [ 0 , 0.01 ]},
"yAxis" : {
"type" : "category" ,
"data" : [ "Brazil" , "Indonesia" , "USA" , "India" , "China" , "World" ],
},
"series" : [
{
"name" : "first" ,
"type" : "bar" ,
"data" : [ 18203 , 23489 , 29034 , 104970 , 131744 , 630230 ],
},
{
"name" : "second" ,
"type" : "bar" ,
"data" : [ 19325 , 23438 , 31000 , 121594 , 134141 , 681807 ],
},
],
}
bar = rxui . echarts ( opts )
def on_first_series_mouseover ( e : rxui . echarts . EChartsMouseEventArguments ):
ui . notify ( f"on_first_series_mouseover: { e . seriesName } : { e . name } : { e . value } " )
bar . on ( "mouseover" , on_first_series_mouseover , query = { "seriesName" : "first" })
ui . run ()Erstellen Sie einen Echart aus dem JavaScript -Code
from pathlib import Path
rxui . echarts . from_javascript ( Path ( "code.js" ))
# or
rxui . echarts . from_javascript (
"""
(myChart) => {
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}
]
};
myChart.setOption(option);
}
"""
)setOption in der Funktion vervollständigen. Die Funktion hat auch einen zweiten Parameter, bei dem es sich um ein globales echarts -Objekt handelt. Sie können die Karte über echarts.registerMap registrieren.
rxui . echarts . from_javascript (
"""
(chart,echarts) =>{
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
.then(response => response.json())
.then(data => {
echarts.registerMap('test_map', data);
chart.setOption({
geo: {
map: 'test_map',
roam: true,
},
tooltip: {},
legend: {},
series: [],
});
});
}
"""
)Registrieren Sie eine Karte.
rxui . echarts . register_map (
"china" , "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json"
)
rxui . echarts (
{
"geo" : {
"map" : "china" ,
"roam" : True ,
},
"tooltip" : {},
"legend" : {},
"series" : [],
}
)map_name ist der benutzerdefinierte Kartenname. Beachten Sie, dass map in der Diagrammkonfiguration registriert sein musssrc ist ein gültiger Kartendatennetzwerk -Link. Wenn es sich um SVG -Daten handelt, müssen Sie den Parameter type="svg" festlegen.
rxui . echarts . register_map ( "svg-rect" , "/test/svg" , type = "svg" )Sie können das JSON -Dateipfadobjekt (Pfad) der lokalen Kartendaten auch direkt angeben
from pathlib import Path
rxui . echarts . register_map (
"china" , Path ( "map-data.json" )
) Im Vergleich zu nicegui.ui.tab_panels hat rxui.tab_panels keine Parameter tabs . Unter dem Datenreaktionsmechanismus erfordert die Verknüpfung zwischen tabs und tab_panels nur den value .
from nicegui import ui
from ex4nicegui import rxui , to_ref
names = [ "Tab 1" , "Tab 2" , "Tab 3" ]
current_tab = to_ref ( names [ 0 ])
with rxui . tabs ( current_tab ):
for name in names :
rxui . tab ( name )
with rxui . tab_panels ( current_tab ):
for name in names :
with rxui . tab_panel ( name ):
ui . label ( f"Content of { name } " ) Dies liegt daran, dass unter dem Datenantwortmechanismus die Komponentenverknüpfung über die Zwischendatenschicht ( to_ref ) erreicht wird. Daher können tab_panels mit anderen Komponenten verknüpft werden (verwenden Sie einfach das gleiche ref -Objekt)
names = [ "Tab 1" , "Tab 2" , "Tab 3" ]
current_tab = to_ref ( names [ 0 ])
with rxui . tab_panels ( current_tab ):
for name in names :
with rxui . tab_panel ( name ):
ui . label ( f"Content of { name } " )
# tabs 不必在 panels 前面
with rxui . tabs ( current_tab ):
for name in names :
rxui . tab ( name )
rxui . select ( names , value = current_tab )
rxui . radio ( names , value = current_tab ). props ( "inline" )
rxui . label ( lambda : f"当前 tab 为: { current_tab . value } " )Im faulen Lademodus wird nur die aktuell aktivierte Registerkarte wiedergegeben.
from ex4nicegui import to_ref , rxui , on , deep_ref
current_tab = to_ref ( "t1" )
with rxui . tabs ( current_tab ):
ui . tab ( "t1" )
ui . tab ( "t2" )
with rxui . lazy_tab_panels ( current_tab ) as panels :
@ panels . add_tab_panel ( "t1" )
def _ ():
# 通过 `panels.get_panel` 获取当前激活的 panel 组件
panels . get_panel ( "t1" ). classes ( "bg-green" )
ui . notify ( "Hello from t1" )
ui . label ( "This is t1" )
@ panels . add_tab_panel ( "t2" )
def _ ():
panels . get_panel ( "t2" ). style ( "background-color : red" )
ui . notify ( "Hello from t2" )
ui . label ( "This is t2" )Nach dem Laden der Seite wird sofort "Hallo aus T1" angezeigt. Wenn Sie auf die Registerkarte "T2" wechseln, wird "Hallo aus T2" angezeigt.
Mit scoped_style können Sie Stile erstellen, die auf die Komponente beschränkt sind.
# 所有子元素都会有红色轮廓,但排除自身
with rxui . row (). scoped_style ( "*" , "outline: 1px solid red;" ) as row :
ui . label ( "Hello" )
ui . label ( "World" )
# 所有子元素都会有红色轮廓,包括自身
with rxui . row (). scoped_style ( ":self *" , "outline: 1px solid red;" ) as row :
ui . label ( "Hello" )
ui . label ( "World" )
# 当鼠标悬停在 row 组件时,所有子元素都会有红色轮廓,但排除自身
with rxui . row (). scoped_style ( ":hover *" , "outline: 1px solid red;" ) as row :
ui . label ( "Hello" )
ui . label ( "World" )
# 当鼠标悬停在 row 组件时,所有子元素都会有红色轮廓,包括自身
with rxui . row (). scoped_style ( ":self:hover *" , "outline: 1px solid red;" ) as row :
ui . label ( "Hello" )
ui . label ( "World" )Erstellen Sie interaktive Daten visuelle Berichte mit den am stärksten optimierten APIs

from nicegui import ui
import pandas as pd
import numpy as np
from ex4nicegui import bi
from ex4nicegui . reactive import rxui
from ex4nicegui import effect , effect_refreshable
from pyecharts . charts import Bar
# data ready
def gen_data ():
np . random . seed ( 265 )
field1 = [ "a1" , "a2" , "a3" , "a4" ]
field2 = [ f"name { i } " for i in range ( 1 , 11 )]
df = (
pd . MultiIndex . from_product ([ field1 , field2 ], names = [ "cat" , "name" ])
. to_frame ()
. reset_index ( drop = True )
)
df [[ "idc1" , "idc2" ]] = np . random . randint ( 50 , 1000 , size = ( len ( df ), 2 ))
return df
df = gen_data ()
# 创建数据源
ds = bi . data_source ( df )
# ui
ui . query ( ".nicegui-content" ). classes ( "items-stretch no-wrap" )
with ui . row (). classes ( "justify-evenly" ):
# 基于数据源 `ds` 创建界面组件
ds . ui_select ( "cat" ). classes ( "min-w-[10rem]" )
ds . ui_select ( "name" ). classes ( "min-w-[10rem]" )
with ui . grid ( columns = 2 ):
# 使用字典配置图表
@ ds . ui_echarts
def bar1 ( data : pd . DataFrame ):
data = data . groupby ( "name" ). agg ({ "idc1" : "sum" , "idc2" : "sum" }). reset_index ()
return {
"xAxis" : { "type" : "value" },
"yAxis" : {
"type" : "category" ,
"data" : data [ "name" ]. tolist (),
"inverse" : True ,
},
"legend" : { "textStyle" : { "color" : "gray" }},
"series" : [
{ "type" : "bar" , "name" : "idc1" , "data" : data [ "idc1" ]. tolist ()},
{ "type" : "bar" , "name" : "idc2" , "data" : data [ "idc2" ]. tolist ()},
],
}
bar1 . classes ( "h-[20rem]" )
# 使用pyecharts配置图表
@ ds . ui_echarts
def bar2 ( data : pd . DataFrame ):
data = data . groupby ( "name" ). agg ({ "idc1" : "sum" , "idc2" : "sum" }). reset_index ()
return (
Bar ()
. add_xaxis ( data [ "name" ]. tolist ())
. add_yaxis ( "idc1" , data [ "idc1" ]. tolist ())
. add_yaxis ( "idc2" , data [ "idc2" ]. tolist ())
)
bar2 . classes ( "h-[20rem]" )
# 绑定点击事件,即可实现跳转
@ bar2 . on_chart_click
def _ ( e : rxui . echarts . EChartsMouseEventArguments ):
ui . open ( f"/details/ { e . name } " , new_tab = True )
# 利用响应式机制,你可以随意组合原生 nicegui 组件
label_a1_total = ui . label ( "" )
# 当 ds 有变化,都会触发此函数
@ effect
def _ ():
# filtered_data 为过滤后的 DataFrame
df = ds . filtered_data
total = df [ df [ "cat" ] == "a1" ][ "idc1" ]. sum ()
label_a1_total . text = f"idc1 total(cat==a1): { total } "
# 你也可以使用 `effect_refreshable`,但需要注意函数中的组件每次都被重建
@ effect_refreshable
def _ ():
df = ds . filtered_data
total = df [ df [ "cat" ] == "a2" ][ "idc1" ]. sum ()
ui . label ( f"idc1 total(cat==a2): { total } " )
# 当点击图表系列时,跳转的页面
@ ui . page ( "/details/{name}" )
def details_page ( name : str ):
ui . label ( "This table data will not change" )
ui . aggrid . from_pandas ( ds . data . query ( f'name==" { name } "' ))
ui . label ( "This table will change when the homepage data changes. " )
@ bi . data_source
def new_ds ():
return ds . filtered_data [[ "name" , "idc1" , "idc2" ]]
new_ds . ui_aggrid ()
ui . run ()bi.data_sourceDie Datenquelle ist das Kernkonzept des BI -Moduls, und die Verknüpfung aller Daten basiert darauf. In der aktuellen Version (0.4.3) gibt es zwei Möglichkeiten, Datenquellen zu erstellen.
DataFrame , der pandas empfängt:
from nicegui import ui
from ex4nicegui import bi
import pandas as pd
df = pd . DataFrame (
{
"name" : list ( "aabcdf" ),
"cls" : [ "c1" , "c2" , "c1" , "c1" , "c3" , None ],
"value" : range ( 6 ),
}
)
ds = bi . data_source ( df )Manchmal möchten wir eine neue Datenquelle erstellen, die auf einer anderen Datenquelle basiert. Zu diesem Zeitpunkt können wir den Dekorateur verwenden, um eine Verknüpfungsdatenquelle zu erstellen:
df = pd . DataFrame (
{
"name" : list ( "aabcdf" ),
"cls" : [ "c1" , "c2" , "c1" , "c1" , "c3" , None ],
"value" : range ( 6 ),
}
)
ds = bi . data_source ( df )
@ bi . data_source
def new_ds ():
# df is pd.DataFrame
df = ds . filtered_data
df = df . copy ()
df [ 'value' ] = df [ 'value' ] * 100
return df
ds . ui_select ( 'name' )
new_ds . ui_aggrid () Beachten Sie, dass die Änderung von ds die Verknüpfungsänderung von new_ds auslöst, da in new_ds ds.filtered_data verwendet wird, was zu Änderungen in den von new_ds
Entfernen Sie den gesamten Filterstatus über die Methode ds.remove_filters :
ds = bi . data_source ( df )
def on_remove_filters ():
ds . remove_filters ()
ui . button ( "remove all filters" , on_click = on_remove_filters )
ds . ui_select ( "name" )
ds . ui_aggrid () Setzen Sie die Datenquelle durch die ds.reload -Methode zurück:
df = pd . DataFrame (
{
"name" : list ( "aabcdf" ),
"cls" : [ "c1" , "c2" , "c1" , "c1" , "c3" , None ],
"value" : range ( 6 ),
}
)
new_df = pd . DataFrame (
{
"name" : list ( "xxyyds" ),
"cls" : [ "cla1" , "cla2" , "cla3" , "cla3" , "cla3" , None ],
"value" : range ( 100 , 106 ),
}
)
ds = bi . data_source ( df )
def on_remove_filters ():
ds . reload ( new_df )
ui . button ( "reload data" , on_click = on_remove_filters )
ds . ui_select ( "name" )
ds . ui_aggrid () from nicegui import ui
from ex4nicegui import bi
import pandas as pd
df = pd . DataFrame (
{
"name" : list ( "aabcdf" ),
"cls" : [ "c1" , "c2" , "c1" , "c1" , "c3" , None ],
"value" : range ( 6 ),
}
)
ds = bi . data_source ( df )
ds . ui_select ( "name" )Die erste Parameterspalte gibt den Spaltennamen der Datenquelle an
Legen Sie die Reihenfolge der Optionen nach Parameter sort_options fest:
ds . ui_select ( "name" , sort_options = { "value" : "desc" , "name" : "asc" }) Parameter exclude_null_value legt fest, ob Nullwerte ausgeschlossen werden sollen:
df = pd . DataFrame (
{
"cls" : [ "c1" , "c2" , "c1" , "c1" , "c3" , None ],
}
)
ds = bi . data_source ( df )
ds . ui_select ( "cls" , exclude_null_value = True )Sie können die Parameter der nativen NiceGui -Komponente durch Schlüsselwortparameter festlegen.
Setzen Sie den Standardwert über das Wert -Attribut:
ds . ui_select ( "cls" , value = [ 'c1' , 'c2' ])
ds . ui_select ( "cls" , multiple = False , value = 'c1' ) Wenn die Mehrfachauswahl (das Parameter multiple ist standardmäßig wahr), muss value als Liste angegeben werden
Bei der Auswahl value auf Nichtliste einstellen
Blatt
from nicegui import ui
from ex4nicegui import bi
import pandas as pd
data = pd . DataFrame ({ "name" : [ "f" , "a" , "c" , "b" ], "age" : [ 1 , 2 , 3 , 1 ]})
ds = bi . data_source ( data )
ds . ui_table (
columns = [
{ "label" : "new colA" , "field" : "colA" , "sortable" : True },
]
)ui.table überein. Das field entspricht dem Spaltennamen der Datenquelle. Wenn es nicht vorhanden ist, wird die Konfiguration nicht wirksam. from nicegui import ui
from ex4nicegui import bi
import pandas as pd
data = pd . DataFrame (
{
"colA" : list ( "abcde" ),
"colB" : [ f"n { idx } " for idx in range ( 5 )],
"colC" : list ( range ( 5 )),
}
)
df = pd . DataFrame ( data )
source = bi . data_source ( df )
source . ui_aggrid (
options = {
"columnDefs" : [
{ "headerName" : "xx" , "field" : "no exists" },
{ "headerName" : "new colA" , "field" : "colA" },
{
"field" : "colC" ,
"cellClassRules" : {
"bg-red-300" : "x < 3" ,
"bg-green-300" : "x >= 3" ,
},
},
],
"rowData" : [{ "colX" : [ 1 , 2 , 3 , 4 , 5 ]}],
}
)ui.aggrid überein. Das field des Schlüsselwerts in columnDefs entspricht dem Spaltennamen der Datenquelle. Wenn es nicht vorhanden ist, wird die Konfiguration nicht wirksam.rowData wird nicht wirksam. Da die Datenquelle der Tabelle immer von der Datenquelle gesteuert wird toolbox -Modul bietet einige häufig verwendete Werkzeugfunktionen.
from ex4nicegui import toolbox Dunkelmodus wechseln
from ex4nicegui import rxui , toolbox as tb
from nicegui import ui
dark = tb . use_dark ( False )
rxui . label ( lambda : f"暗模式: { dark . value } " )
rxui . button (
icon = lambda : "sunny" if dark . value else "dark_mode" ,
color = lambda : "red" if dark . value else "blue" ,
on_click = dark . toggle ,
). props ( "flat round" )Responsive Breakpoint
from ex4nicegui import rxui , toolbox as tb
from nicegui import ui
options = { "手机" : 0 , "平板" : 640 , "笔记本" : 1024 , "桌面" : 1280 }
bp = tb . use_breakpoints ( options )
active = bp . active
is_between = bp . between ( "手机" , "笔记本" )
with ui . card ():
rxui . label ( lambda : f"当前断点: { active . value } " )
rxui . label ( lambda : f"是否在手机-笔记本(不含)之间: { is_between . value } " ). bind_classes (
{ "text-red-500" : is_between }
)
rxui . label ( lambda : f'手机(0px - 640px): { active . value == "手机" } ' ). bind_classes (
{ "bg-red-300" : lambda : active . value == "手机" }
)
rxui . label ( lambda : f'平板(640px - 1024px): { active . value == "平板" } ' ). bind_classes (
{ "bg-red-300" : lambda : active . value == "平板" }
)
rxui . label (
lambda : f'笔记本(1024px - 1280px): { active . value == "笔记本" } '
). bind_classes ({ "bg-red-300" : lambda : active . value == "笔记本" })
rxui . label ( lambda : f'桌面(1280px+): { active . value == "桌面" } ' ). bind_classes (
{ "bg-red-300" : lambda : active . value == "桌面" }
)
Generieren Sie den QR -Code
from ex4nicegui import rxui , to_ref , toolbox as tb
from nicegui import ui
text = to_ref ( "ex4nicegui" )
qr_code = tb . use_qr_code ( text )
rxui . input ( value = text )
rxui . image ( qr_code . code ). classes ( "w-20 h-20" ). props ( "no-transition" )