浏览代码

demo: update output usage demo

wangweimin 4 年之前
父节点
当前提交
0efae530e2
共有 1 个文件被更改,包括 195 次插入33 次删除
  1. 195 33
      demos/output_usage.py

+ 195 - 33
demos/output_usage.py

@@ -3,25 +3,50 @@
 ^^^^^^^^^^^
 演示PyWebIO支持的各种输出形式
 
-:demo_host:`Demo地址 </?pywebio_api=output_usage>`  `源码 <https://github.com/wang0618/PyWebIO/blob/master/demos/output_usage.py>`_
+:demo_host:`Demo地址 </?pywebio_api=output_usage>`  `源码 <https://github.com/wang0618/PyWebIO/blob/dev/demos/output_usage.py>`_
 """
 from pywebio import start_server
 from pywebio.output import *
-from pywebio.session import hold, set_env
+from pywebio.input import *
+from pywebio.session import hold, set_env, run_async
+from functools import partial
 
 
-def main():
+def code_block(code, strip_indent=4):
+    if strip_indent:
+        lines = (
+            i[strip_indent:] if (i[:strip_indent] == ' ' * strip_indent) else i
+            for i in code.splitlines()
+        )
+        code = '\n'.join(lines)
+    code = code.strip('\n')
+
+    def run_code(code, scope):
+        with use_scope(scope):
+            exec(code, globals())
+
+    with use_scope() as scope:
+        put_code(code, 'python')
+        put_buttons([{'label': '运行', 'value': '', 'color': 'success'}],
+                    onclick=[partial(run_code, code=code, scope=scope)], small=True)
+
+
+async def main():
     set_env(title="PyWebIO输出演示", auto_scroll_bottom=False)
 
-    put_markdown("""# PyWebIO 输入演示
+    put_markdown("""# PyWebIO 输出演示
+    
+    在[这里](https://github.com/wang0618/PyWebIO/blob/master/demos/output_usage.py)可以获取本Demo的源码。
     
-    在[这里](https://github.com/wang0618/PyWebIO/blob/master/demos/input_usage.py)可以获取本Demo的源码。
+    本Demo仅提供了PyWebIO输出模块的部分功能的演示,完整特性请参阅[用户指南](https://pywebio.readthedocs.io/)
     
     PyWebIO的输出函数都定义在 `pywebio.output` 模块中,可以使用 `from pywebio.output import *` 引入。
 
     ### 基本输出
     PyWebIO提供了一些便捷函数来输出表格、链接等格式:
-    ```python
+    """, strip_indent=4)
+
+    code_block(r"""
     # 文本输出
     put_text("Hello world!")
 
@@ -37,24 +62,45 @@ def main():
 
     # 文件输出
     put_file('hello_word.txt', b'hello word!')
-    ```
+    """)
+
+    put_markdown(r"""PyWebIO提供的全部输出函数请参考PyWebIO文档
+    
+    ### 组合输出
     
-    PyWebIO提供的全部输出函数请参考PyWebIO文档
+    函数名以 `put_` 开始的输出函数,可以与一些输出函数组合使用,作为最终输出的一部分。
+
+    比如`put_table()`支持以`put_xxx()`调用作为单元格内容:
     """, strip_indent=4)
-    # 文本输出
-    put_text("Hello world!")
-    # 表格输出
+
+    code_block(r"""
     put_table([
-        ['商品', '价格'],
-        ['苹果', '5.5'],
-        ['香蕉', '7'],
+        ['Type', 'Content'],
+        ['html', put_html('X<sup>2</sup>')],
+        ['text', '<hr/>'],  # 等价于 ['text', put_text('<hr/>')]
+        ['buttons', put_buttons(['A', 'B'], onclick=toast)],  
+        ['markdown', put_markdown('`Awesome PyWebIO!`')],
+        ['file', put_file('hello.text', b'hello world')],
+        ['table', put_table([['A', 'B'], ['C', 'D']])]
     ])
-    # Markdown输出
-    put_markdown('~~删除线~~')
-    # 文件输出
-    put_file('hello_word.txt', b'hello word!')
+    """)
 
-    put_markdown(r"""### 输出事件回调
+    put_markdown(r"""类似地,`popup()`也可以将`put_xxx()`调用作为弹窗内容:
+    
+    """, strip_indent=4)
+
+    code_block(r"""
+    popup('Popup title', [
+        put_html('<h3>Popup Content</h3>'),
+        'plain html: <br/>',  # 等价于 put_text('plain html: <br/>')
+        put_table([['A', 'B'], ['C', 'D']]),
+        put_buttons(['close_popup()'], onclick=lambda _: close_popup())
+    ])
+    """)
+
+    put_markdown(r"更多接受`put_xxx()`作为参数的输出函数请参考函数文档。")
+
+    put_markdown(r"""### 事件回调
     PyWebIO允许你输出一些控件,当控件被点击时执行提供的回调函数,就像编写GUI程序一样。
     
     下面是一个例子:
@@ -66,11 +112,13 @@ def main():
 
     put_table([
         ['Idx', 'Actions'],
-        [1, table_cell_buttons(['edit', 'delete'], onclick=partial(edit_row, row=1))],
-        [2, table_cell_buttons(['edit', 'delete'], onclick=partial(edit_row, row=2))],
-        [3, table_cell_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
+        [1, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=1))],
+        [2, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=2))],
+        [3, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
     ])
     ```
+    `put_table()`的调用不会阻塞。当用户点击了某行中的按钮时,PyWebIO会自动调用相应的回调函数:
+    
     """, strip_indent=4)
 
     from functools import partial
@@ -81,9 +129,9 @@ def main():
 
     put_table([
         ['Idx', 'Actions'],
-        [1, table_cell_buttons(['edit', 'delete'], onclick=partial(edit_row, row=1))],
-        [2, table_cell_buttons(['edit', 'delete'], onclick=partial(edit_row, row=2))],
-        [3, table_cell_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
+        [1, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=1))],
+        [2, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=2))],
+        [3, put_buttons(['edit', 'delete'], onclick=partial(edit_row, row=3))],
     ])
     set_scope('table-callback')
 
@@ -103,20 +151,134 @@ def main():
     put_buttons(['A', 'B', 'C'], onclick=btn_click)
     set_scope('button-callback')
 
-    put_markdown(r"""### 页面环境设置
-    #### 输出区外观
-    PyWebIO支持两种外观:输出区固定高度/可变高度。 可以通过调用 `set_output_fixed_height(True)` 来开启输出区固定高度。
+    put_markdown(r"""### 输出域Scope
+
+    PyWebIO使用Scope模型来对内容输出的位置进行灵活地控制,PyWebIO的内容输出区可以划分出不同的输出域,PyWebIO将输出域称作`Scope`。
+    
+    输出域为输出内容的容器,各个输出域之间上下排列,输出域也可以进行嵌套。
+    
+    每个输出函数(函数名形如 `put_xxx()` )都会将内容输出到一个Scope,默认为”当前Scope”,”当前Scope”由运行时上下文确定,输出函数也可以手动指定输出到的Scope。Scope名在会话内唯一。
+    
+    可以使用 `use_scope()` 开启并进入一个新的输出域,或进入一个已经存在的输出域:
+
+    ```python
+    with use_scope('A'):
+        put_text('Text in scope A')
     
-    #### 设置页面标题
+        with use_scope('B'):
+            put_text('Text in scope B')
     
-    调用 `set_title(title)` 可以设置页面标题。
+    with use_scope('C'):
+        put_text('Text in scope C')
+    ```
+    以上代码将会产生如下Scope布局:
+    """, strip_indent=4)
+    with use_scope('A'):
+        put_text('Text in scope A')
+
+        with use_scope('B'):
+            put_text('Text in scope B')
+
+    with use_scope('C'):
+        put_text('Text in scope C')
+
+    put_html("""<style>                                           
+    #pywebio-scope-A {border: 1px solid red;}                    
+    #pywebio-scope-B {border: 1px solid blue;margin:2px}         
+    #pywebio-scope-C {border: 1px solid green;margin-top:2px}    
+    </style><br/>""")
+
+    put_markdown(r"""
+    输出函数(函数名形如 `put_xxx()` )在默认情况下,会将内容输出到”当前Scope”,可以通过 `use_scope()` 设置运行时上下文的”当前Scope”。
     
-    #### 自动滚动
+    此外,也可以通过输出函数的 scope 参数指定输出的目的Scope:
+    """, strip_indent=4)
+
+    put_grid([
+        [put_code("put_text('A', scope='A')", 'python'), None, put_buttons(['运行'], [lambda: put_text('A', scope='A')])],
+        [put_code("put_text('B', scope='B')", 'python'), None, put_buttons(['运行'], [lambda: put_text('B', scope='B')])],
+        [put_code("put_text('C', scope='C')", 'python'), None, put_buttons(['运行'], [lambda: put_text('C', scope='C')])],
+    ], cell_widths='1fr 10px auto')
+
+    put_markdown(r"""输出函数可以使用position参数指定内容在Scope中输出的位置
+    ```python
+    put_text(now(), scope='A', position=...)
+    ```
+    """, strip_indent=4)
+    import datetime
+
+    put_buttons([('position=%s' % i, i) for i in [1, 2, 3, -1, -2, -3]],
+                lambda i: put_text(datetime.datetime.now(), position=i, scope='A'), small=True)
+
+    put_markdown(r"除了 `use_scope()` , PyWebIO同样提供了以下scope控制函数: ")
+
+    put_grid([
+        [put_code("clear('B')  # 清除Scope B中的内容", 'python'), None, put_buttons(['运行'], [lambda: clear('B')])],
+        [put_code("remove('C')  # 移除Scope C", 'python'), None, put_buttons(['运行'], [lambda: remove('C')])],
+        [put_code("scroll_to('A')  # 将页面滚动到Scope A处", 'python'), None, put_buttons(['运行'], [lambda: scroll_to('A')])],
+    ], cell_widths='1fr 10px auto')
+
+    put_markdown(r"""### 布局
+    一般情况下,使用上文介绍的各种输出函数足以完成各种内容的展示,但直接调用输出函数产生的输出之间都是竖直排列的,如果想实现更复杂的布局(比如在页 面左侧显示一个代码块,在右侧显示一个图像),就需要借助布局函数。
+
+    `pywebio.output` 模块提供了3个布局函数,通过对他们进行组合可以完成各种复杂的布局:
     
-    在不指定锚点进行输出时,PyWebIO默认在输出完毕后自动将页面滚动到页面最下方;在调用输入函数时,也会将页面滚动到表单处。 通过调用 `set_auto_scroll_bottom(False)` 来关闭自动滚动。
+     - `put_row()` : 使用行布局输出内容. 内容在水平方向上排列
+     - `put_column()` : 使用列布局输出内容. 内容在竖直方向上排列
+     - `put_grid()` : 使用网格布局输出内容
 
+    比如,通过通过组合 `put_row()` 和 `put_column()` 实现的布局:
     """, strip_indent=4)
-    hold()
+
+    code_block(r"""
+    put_row([
+        put_column([
+            put_code('A'),
+            put_row([
+                put_code('B1'), None,  # None 表示输出之间的空白
+                put_code('B2'), None,
+                put_code('B3'),
+            ]),
+            put_code('C'),
+        ]), None,
+        put_code('D'), None,
+        put_code('E')
+    ])
+    """)
+
+    put_markdown(r"""
+    ### 样式
+    
+    如果你熟悉 CSS样式 ,你还可以使用 `style()` 函数给输出设定自定义样式。
+
+    可以给单个的 `put_xxx()` 输出设定CSS样式,也可以配合组合输出使用:
+    """, strip_indent=4)
+
+    code_block(r"""
+    style(put_text('Red'), 'color: red')
+    
+    put_table([
+        ['A', 'B'],
+        ['C', style(put_text('Red'), 'color: red')],
+    ])
+    """, strip_indent=4)
+
+    put_markdown(r"`style()` 也接受列表作为输入:")
+
+    code_block(r"""
+    style([
+        put_text('Red'),
+        put_markdown('~~del~~')
+    ], 'color: red')
+    
+    put_collapse('title', style([
+        put_text('text'),
+        put_markdown('~~del~~'),
+    ], 'margin-left: 20px'))
+
+    """, strip_indent=4)
+
+    await hold()
 
 
 if __name__ == '__main__':