Python轮子:remi~基于 Web 技术的 Python GUI 框架

原文链接:http://www.juzicode.com/python-module-remi

Remi 是一个基于 Web 技术的 Python GUI 开发框架,允许开发者使用纯 Python 代码构建跨平台的桌面和 Web 应用程序。其核心特点是通过浏览器渲染界面,支持响应式布局和实时更新,适用于物联网控制面板、数据监控系统等场景。

应用场景

  • 嵌入式系统可视化界面
  • 跨平台桌面应用程序
  • 工业设备远程控制面板
  • 实时数据监控仪表盘
  • 教育领域可视化教学工具

安装方法

pip install remi
import remi

使用方法

1. 创建基础窗口

构建最简单的 Remi 应用框架,继承App类创建应用实例,在main方法中创建container容器,然后用生成label实例,并append到container中,开启窗口则用start()方法。

# juzicode.com/VX公众号:juzicode
from remi import App, gui, start

class MyApp(App):
    def main(self):
        container = gui.VBox(width=500, height=350)
        self.lbl = gui.Label('桔子code,你好, 欢迎使用 Remi!')
        container.append(self.lbl)
        return container

if __name__ == "__main__":
    start(MyApp, address='127.0.0.1',port=8080) 

运行结果:

在浏览器访问 http://localhost:8080 显示带标签的空白窗口

2. 添加交互按钮

通过事件绑定实现交互逻辑,on_button_pressed演示事件响应机制,更新标签内容。

# juzicode.com/VX公众号:juzicode
from remi import App, gui, start

class ButtonApp(App):
    def main(self):
        # container = gui.VBox(width=300, height=200)  #
        container = gui.VBox() # 不限定窗口大小,则跟随浏览器
        self.lbl = gui.Label('点击次数: 0')
        btn = gui.Button('点击我   @VX公众号:juzicode', width=200, height=30)
        btn.onclick.connect(self.on_button_pressed)
        container.append(btn)
        container.append(self.lbl)
        return container
    
    def on_button_pressed(self, widget):
        current = int(self.lbl.get_text().split(': ')[1])
        self.lbl.set_text(f'点击次数: {current + 1}')

if __name__ == "__main__":
    start(ButtonApp, address='127.0.0.1',port=8080) 

运行结果:

显示可点击按钮,每次点击数字递增

3. 表单输入处理

使用TextInput组件获取用户输入,onconfirm 事件处理表单提交。

# juzicode.com/VX公众号:juzicode
from remi import App, gui, start

class FormApp(App):
    def main(self):
        container = gui.VBox()
        self.input = gui.TextInput(width=200)
        submit_btn = gui.Button('提交', width=100)
        submit_btn.onclick.connect(self.on_submit)
        self.output = gui.Label('')
        
        container.append(gui.Label('输入内容:'))
        container.append(self.input)
        container.append(submit_btn)
        container.append(self.output)
        return container
    
    def on_submit(self, widget):
        text = self.input.get_value()
        self.output.set_text(f"您输入了: {text}")
 

if __name__ == "__main__":
    start(FormApp, address='127.0.0.1',port=8080) 

运行结果:

显示文本输入框和提交按钮,提交后显示输入内容

4. 动态布局管理

使用HBox VBox实现响应式布局,style属性自定义 CSS 样式。

# juzicode.com/VX公众号:juzicode
from remi import App, gui, start

class LayoutApp(App):
    def main(self):
        # 创建横向布局容器
        hbox = gui.HBox(style={'margin': '10px', 'padding': '5px'})
        
        # 左侧垂直布局
        left_col = gui.VBox(width=200)
        left_col.append(gui.Label('导航菜单', style={'color': 'blue'}))
        
        # 右侧内容区域  
        right_col = gui.VBox(style={'flex': '1'})
        right_col.append(gui.Label('主内容区', style={'font-size': '20px'}))
        
        right_col2 = gui.VBox(style={'flex': '1'})
        right_col2.append(gui.Label('juzicode', style={'font-size': '10px'}))
        hbox.append(left_col)
        hbox.append(right_col)
        hbox.append(right_col2)
        
        return hbox

if __name__ == "__main__":
    start(LayoutApp, address='127.0.0.1',port=8080) 

运行结果:

5. 图表数据可视化

集成 Matplotlib 显示动态图表,通过Image组件展示生成的图片。

# juzicode.com/VX公众号:juzicode
from remi import App, gui, start
import matplotlib
matplotlib.use('Agg')  # 设置在导入pyplot前
import matplotlib.pyplot as plt
import io
import base64  # 导入base64模块

class ChartApp(App):
    def main(self):
        container = gui.VBox()
        self.img = gui.Image(width=600, height=400)
        btn = gui.Button('生成图表')
        btn.onclick.connect(self.update_chart)
        container.append(btn)
        container.append(self.img)
        return container
    
    def update_chart(self, widget):
        # 生成Matplotlib图表
        plt.close('all')  # 避免内存泄漏
        fig, ax = plt.subplots()
        ax.plot([1,2,3], [4,1,5])
        buf = io.BytesIO()
        plt.savefig(buf, format='png', bbox_inches='tight')
        buf.seek(0)
        # 使用base64编码图像数据
        img_data = base64.b64encode(buf.read()).decode('utf-8')
        self.img.set_image(f'data:image/png;base64,{img_data}')

if __name__ == "__main__":
    start(ChartApp, address='127.0.0.1', port=8080)

运行结果:

6. 下拉菜单

通过DropDown实现下拉菜单的选择。

# juzicode.com/VX公众号:juzicode
from remi import App, gui, start

class DropdownApp(App):
    def main(self):
        container = gui.VBox(width=500, height=350)
        self.dropdown = gui.DropDown(width=200)
        options = ['桔子', '香蕉', '苹果']
        for opt in options:
            self.dropdown.append(gui.DropDownItem(opt))
        
        self.result = gui.Label()
        self.dropdown.onchange.connect(self.select_item)
        container.append([self.dropdown, self.result])
        return container

    def select_item(self, widget, value):
        self.result.set_text(f"选择了: {value}")

if __name__ == "__main__":
    start(DropdownApp, address='127.0.0.1', port=8080)

运行结果:

总结

Remi 核心优势:

  • 纯 Python 开发 Web GUI
  • 跨平台兼容性(Windows/Linux/macOS)
  • 响应式布局支持
  • 与 Python 生态无缝集成
  • 内置 Web 服务器

注意事项:

  • 复杂界面需合理管理组件树
  • 大数据量场景注意性能优化
  • 生产环境建议配合 Nginx 反向代理
  • 移动端适配需要额外样式处理

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注