图:

代码:
python
from nicegui import ui, events
from typing import List, Dict
# ========== 1. 扩展到200+ NiceGUI内置Material Design图标 ==========
MATERIAL_ICONS: List[Dict[str, str]] = [
# 导航类(25个)
{'name': 'menu', 'description': '菜单', 'category': '导航'},
{'name': 'home', 'description': '首页', 'category': '导航'},
{'name': 'search', 'description': '搜索', 'category': '导航'},
{'name': 'arrow_back', 'description': '返回', 'category': '导航'},
{'name': 'arrow_forward', 'description': '前进', 'category': '导航'},
{'name': 'arrow_upward', 'description': '向上', 'category': '导航'},
{'name': 'arrow_downward', 'description': '向下', 'category': '导航'},
{'name': 'chevron_left', 'description': '左箭头', 'category': '导航'},
{'name': 'chevron_right', 'description': '右箭头', 'category': '导航'},
{'name': 'expand_more', 'description': '展开更多', 'category': '导航'},
{'name': 'expand_less', 'description': '收起', 'category': '导航'},
{'name': 'menu_open', 'description': '展开菜单', 'category': '导航'},
{'name': 'menu_book', 'description': '菜单书', 'category': '导航'},
{'name': 'close', 'description': '关闭', 'category': '导航'},
{'name': 'backspace', 'description': '退格', 'category': '导航'},
{'name': 'arrow_left', 'description': '左箭头', 'category': '导航'},
{'name': 'arrow_right', 'description': '右箭头', 'category': '导航'},
{'name': 'arrow_up', 'description': '上箭头', 'category': '导航'},
{'name': 'arrow_down', 'description': '下箭头', 'category': '导航'},
{'name': 'navigate_before', 'description': '导航前', 'category': '导航'},
{'name': 'navigate_next', 'description': '导航后', 'category': '导航'},
{'name': 'keyboard_arrow_up', 'description': '键盘上箭头', 'category': '导航'},
{'name': 'keyboard_arrow_down', 'description': '键盘下箭头', 'category': '导航'},
{'name': 'keyboard_arrow_left', 'description': '键盘左箭头', 'category': '导航'},
{'name': 'keyboard_arrow_right', 'description': '键盘右箭头', 'category': '导航'},
# 操作类(28个)
{'name': 'add', 'description': '添加', 'category': '操作'},
{'name': 'edit', 'description': '编辑', 'category': '操作'},
{'name': 'delete', 'description': '删除', 'category': '操作'},
{'name': 'save', 'description': '保存', 'category': '操作'},
{'name': 'cancel', 'description': '取消', 'category': '操作'},
{'name': 'check', 'description': '确认', 'category': '操作'},
{'name': 'undo', 'description': '撤销', 'category': '操作'},
{'name': 'redo', 'description': '重做', 'category': '操作'},
{'name': 'copy', 'description': '复制', 'category': '操作'},
{'name': 'cut', 'description': '剪切', 'category': '操作'},
{'name': 'paste', 'description': '粘贴', 'category': '操作'},
{'name': 'select_all', 'description': '全选', 'category': '操作'},
{'name': 'refresh', 'description': '刷新', 'category': '操作'},
{'name': 'download', 'description': '下载', 'category': '操作'},
{'name': 'upload', 'description': '上传', 'category': '操作'},
{'name': 'share', 'description': '分享', 'category': '操作'},
{'name': 'send', 'description': '发送', 'category': '操作'},
{'name': 'clear', 'description': '清除', 'category': '操作'},
{'name': 'done', 'description': '完成', 'category': '操作'},
{'name': 'remove', 'description': '移除', 'category': '操作'},
{'name': 'create', 'description': '创建', 'category': '操作'},
{'name': 'archive', 'description': '归档', 'category': '操作'},
{'name': 'restore', 'description': '恢复', 'category': '操作'},
{'name': 'backup', 'description': '备份', 'category': '操作'},
{'name': 'import_export', 'description': '导入导出', 'category': '操作'},
{'name': 'move_to_inbox', 'description': '移入收件箱', 'category': '操作'},
{'name': 'unarchive', 'description': '取消归档', 'category': '操作'},
{'name': 'publish', 'description': '发布', 'category': '操作'},
# 功能类(26个)
{'name': 'settings', 'description': '设置', 'category': '功能'},
{'name': 'person', 'description': '个人', 'category': '功能'},
{'name': 'email', 'description': '邮件', 'category': '功能'},
{'name': 'phone', 'description': '电话', 'category': '功能'},
{'name': 'lock', 'description': '锁定', 'category': '功能'},
{'name': 'lock_open', 'description': '解锁', 'category': '功能'},
{'name': 'visibility', 'description': '可见', 'category': '功能'},
{'name': 'visibility_off', 'description': '隐藏', 'category': '功能'},
{'name': 'favorite', 'description': '收藏', 'category': '功能'},
{'name': 'star', 'description': '星星', 'category': '功能'},
{'name': 'star_border', 'description': '空心星', 'category': '功能'},
{'name': 'filter', 'description': '筛选', 'category': '功能'},
{'name': 'sort', 'description': '排序', 'category': '功能'},
{'name': 'more_vert', 'description': '更多(竖)', 'category': '功能'},
{'name': 'more_horiz', 'description': '更多(横)', 'category': '功能'},
{'name': 'account_circle', 'description': '账户头像', 'category': '功能'},
{'name': 'badge', 'description': '徽章', 'category': '功能'},
{'name': 'bookmark', 'description': '书签', 'category': '功能'},
{'name': 'bookmark_border', 'description': '空心书签', 'category': '功能'},
{'name': 'contact_page', 'description': '联系人页面', 'category': '功能'},
{'name': 'dashboard', 'description': '仪表盘', 'category': '功能'},
{'name': 'edit_note', 'description': '编辑笔记', 'category': '功能'},
{'name': 'flag', 'description': '旗帜', 'category': '功能'},
{'name': 'help_outline', 'description': '帮助轮廓', 'category': '功能'},
{'name': 'history', 'description': '历史', 'category': '功能'},
{'name': 'login', 'description': '登录', 'category': '功能'},
# 提示类(12个)
{'name': 'error', 'description': '错误', 'category': '提示'},
{'name': 'warning', 'description': '警告', 'category': '提示'},
{'name': 'info', 'description': '信息', 'category': '提示'},
{'name': 'help', 'description': '帮助', 'category': '提示'},
{'name': 'check_circle', 'description': '成功圈', 'category': '提示'},
{'name': 'error_outline', 'description': '错误轮廓', 'category': '提示'},
{'name': 'warning_amber', 'description': '警告琥珀色', 'category': '提示'},
{'name': 'info_outline', 'description': '信息轮廓', 'category': '提示'},
{'name': 'check_circle_outline', 'description': '成功圈轮廓', 'category': '提示'},
{'name': 'report', 'description': '报告', 'category': '提示'},
{'name': 'report_problem', 'description': '报告问题', 'category': '提示'},
{'name': 'notifications', 'description': '通知', 'category': '提示'},
# 文件类(18个)
{'name': 'folder', 'description': '文件夹', 'category': '文件'},
{'name': 'folder_open', 'description': '打开文件夹', 'category': '文件'},
{'name': 'file', 'description': '文件', 'category': '文件'},
{'name': 'file_copy', 'description': '复制文件', 'category': '文件'},
{'name': 'image', 'description': '图片', 'category': '文件'},
{'name': 'video_library', 'description': '视频库', 'category': '文件'},
{'name': 'music_note', 'description': '音乐', 'category': '文件'},
{'name': 'description', 'description': '文档', 'category': '文件'},
{'name': 'file_download', 'description': '文件下载', 'category': '文件'},
{'name': 'file_upload', 'description': '文件上传', 'category': '文件'},
{'name': 'file_present', 'description': '文件展示', 'category': '文件'},
{'name': 'folder_copy', 'description': '复制文件夹', 'category': '文件'},
{'name': 'insert_drive_file', 'description': '插入文件', 'category': '文件'},
{'name': 'pdf', 'description': 'PDF文件', 'category': '文件'},
{'name': 'picture_as_pdf', 'description': 'PDF图片', 'category': '文件'},
{'name': 'text_snippet', 'description': '文本片段', 'category': '文件'},
{'name': 'upload_file', 'description': '上传文件', 'category': '文件'},
{'name': 'cloud_upload', 'description': '云上传', 'category': '文件'},
# 设备类(20个)
{'name': 'laptop', 'description': '笔记本', 'category': '设备'},
{'name': 'desktop_windows', 'description': '桌面', 'category': '设备'},
{'name': 'phone_android', 'description': '安卓手机', 'category': '设备'},
{'name': 'tablet_android', 'description': '平板', 'category': '设备'},
{'name': 'print', 'description': '打印', 'category': '设备'},
{'name': 'wifi', 'description': 'WiFi', 'category': '设备'},
{'name': 'bluetooth', 'description': '蓝牙', 'category': '设备'},
{'name': 'battery_full', 'description': '满电', 'category': '设备'},
{'name': 'battery_half', 'description': '半电', 'category': '设备'},
{'name': 'battery_empty', 'description': '无电', 'category': '设备'},
{'name': 'battery_charging_full', 'description': '充电满', 'category': '设备'},
{'name': 'camera', 'description': '相机', 'category': '设备'},
{'name': 'headset', 'description': '耳机', 'category': '设备'},
{'name': 'keyboard', 'description': '键盘', 'category': '设备'},
{'name': 'mouse', 'description': '鼠标', 'category': '设备'},
{'name': 'scanner', 'description': '扫描仪', 'category': '设备'},
{'name': 'speaker', 'description': '扬声器', 'category': '设备'},
{'name': 'tv', 'description': '电视', 'category': '设备'},
{'name': 'usb', 'description': 'USB', 'category': '设备'},
{'name': 'watch', 'description': '手表', 'category': '设备'},
# 时间类(12个)
{'name': 'calendar_today', 'description': '今日日历', 'category': '时间'},
{'name': 'access_time', 'description': '时间', 'category': '时间'},
{'name': 'alarm', 'description': '闹钟', 'category': '时间'},
{'name': 'timer', 'description': '计时器', 'category': '时间'},
{'name': 'stopwatch', 'description': '秒表', 'category': '时间'},
{'name': 'calendar_month', 'description': '月历', 'category': '时间'},
{'name': 'calendar_week', 'description': '周历', 'category': '时间'},
{'name': 'clock', 'description': '时钟', 'category': '时间'},
{'name': 'date_range', 'description': '日期范围', 'category': '时间'},
{'name': 'schedule', 'description': '日程', 'category': '时间'},
{'name': 'timer_10', 'description': '10分钟计时器', 'category': '时间'},
{'name': 'timer_off', 'description': '关闭计时器', 'category': '时间'},
# 购物类(15个)
{'name': 'shopping_cart', 'description': '购物车', 'category': '购物'},
{'name': 'payment', 'description': '支付', 'category': '购物'},
{'name': 'tag', 'description': '标签', 'category': '购物'},
{'name': 'barcode', 'description': '条形码', 'category': '购物'},
{'name': 'qr_code', 'description': '二维码', 'category': '购物'},
{'name': 'attach_money', 'description': '金额', 'category': '购物'},
{'name': 'card_giftcard', 'description': '礼品卡', 'category': '购物'},
{'name': 'credit_card', 'description': '信用卡', 'category': '购物'},
{'name': 'money', 'description': '货币', 'category': '购物'},
{'name': 'price_check', 'description': '价格检查', 'category': '购物'},
{'name': 'receipt', 'description': '收据', 'category': '购物'},
{'name': 'sell', 'description': '出售', 'category': '购物'},
{'name': 'shopping_bag', 'description': '购物袋', 'category': '购物'},
{'name': 'store', 'description': '商店', 'category': '购物'},
{'name': 'local_atm', 'description': 'ATM机', 'category': '购物'},
# 媒体类(18个)
{'name': 'volume_up', 'description': '音量大', 'category': '媒体'},
{'name': 'volume_down', 'description': '音量小', 'category': '媒体'},
{'name': 'volume_mute', 'description': '静音', 'category': '媒体'},
{'name': 'volume_off', 'description': '无音量', 'category': '媒体'},
{'name': 'play_arrow', 'description': '播放', 'category': '媒体'},
{'name': 'pause', 'description': '暂停', 'category': '媒体'},
{'name': 'stop', 'description': '停止', 'category': '媒体'},
{'name': 'skip_next', 'description': '下一曲', 'category': '媒体'},
{'name': 'skip_previous', 'description': '上一曲', 'category': '媒体'},
{'name': 'fast_forward', 'description': '快进', 'category': '媒体'},
{'name': 'fast_rewind', 'description': '快退', 'category': '媒体'},
{'name': 'repeat', 'description': '重复', 'category': '媒体'},
{'name': 'shuffle', 'description': '随机播放', 'category': '媒体'},
{'name': 'audiotrack', 'description': '音轨', 'category': '媒体'},
{'name': 'mic', 'description': '麦克风', 'category': '媒体'},
{'name': 'mic_off', 'description': '关闭麦克风', 'category': '媒体'},
{'name': 'photo_camera', 'description': '拍照', 'category': '媒体'},
{'name': 'video_call', 'description': '视频通话', 'category': '媒体'},
# 工具类(20个)
{'name': 'zoom_in', 'description': '放大', 'category': '工具'},
{'name': 'zoom_out', 'description': '缩小', 'category': '工具'},
{'name': 'fullscreen', 'description': '全屏', 'category': '工具'},
{'name': 'fullscreen_exit', 'description': '退出全屏', 'category': '工具'},
{'name': 'rotate_left', 'description': '左转', 'category': '工具'},
{'name': 'rotate_right', 'description': '右转', 'category': '工具'},
{'name': 'delete_sweep', 'description': '清除', 'category': '工具'},
{'name': 'adjust', 'description': '调整', 'category': '工具'},
{'name': 'build', 'description': '构建', 'category': '工具'},
{'name': 'calculator', 'description': '计算器', 'category': '工具'},
{'name': 'color_lens', 'description': '色镜', 'category': '工具'},
{'name': 'compass_calibration', 'description': '罗盘校准', 'category': '工具'},
{'name': 'crop', 'description': '裁剪', 'category': '工具'},
{'name': 'draw', 'description': '绘制', 'category': '工具'},
{'name': 'extension', 'description': '扩展', 'category': '工具'},
{'name': 'flash_on', 'description': '闪光灯开', 'category': '工具'},
{'name': 'flash_off', 'description': '闪光灯关', 'category': '工具'},
{'name': 'highlight', 'description': '高亮', 'category': '工具'},
{'name': 'level', 'description': '水平', 'category': '工具'},
{'name': 'measure', 'description': '测量', 'category': '工具'}
]
# 默认图标颜色
DEFAULT_ICON_COLOR = '#4caf50'
# 获取所有分类(去重并排序)
def get_all_categories() -> List[str]:
categories = sorted(list(set(icon['category'] for icon in MATERIAL_ICONS)))
return ['全部图标'] + categories
# 复制图标名称函数(复制纯名称,如menu/home)
def copy_icon_name(name: str):
ui.run_javascript(f'navigator.clipboard.writeText(`{name}`)')
ui.notify(f'已复制图标名称: {name}', type='positive', timeout=2000)
def main():
# 强制加载Material Icons字体(解决国内显示问题)
ui.add_head_html('''
<link href="https://fonts.googleapis.cn/css2?family=Material+Icons" rel="stylesheet">
''')
# 页面基础配置
ui.page_title('NiceGUI 3.4.0 Material Design图标库')
ui.colors(primary='#4caf50', secondary='#03DAC6') # Material Design主题色
# 存储图标卡片引用和筛选状态
icon_cards = {} # key: 图标name, value: 卡片元素
icon_elements = {} # key: 图标name, value: 图标元素
current_category = '全部图标'
current_search_text = ''
current_icon_color = DEFAULT_ICON_COLOR
# ========== 顶部导航栏(分类筛选+搜索+颜色选择) ==========
with ui.header(elevated=True).style('padding: 1rem 2rem; background-color: white; display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap'):
# 标题
ui.label('NiceGUI 内置Material Design图标库').style('font-size: 1.8rem; font-weight: bold; color: #4caf50; margin-right: 1rem')
# 分类筛选下拉框
category_select = ui.select(
options=get_all_categories(),
value='全部图标',
on_change=lambda e: update_filter(category=e.value)
).props('rounded outlined').style('width: 180px; min-width: 150px')
category_select.add_slot('prepend', '<i class="material-icons">folder_category</i>')
# 搜索框(支持搜索名称/描述)
search_input = ui.input(
placeholder='搜索图标(名称/描述,如:菜单、arrow、home)',
on_change=lambda e: update_filter(search_text=e.value)
).props('rounded outlined').style('width: 300px; min-width: 200px; flex-grow: 1; max-width: 500px')
search_input.add_slot('prepend', '<i class="material-icons">search</i>')
# 新增:图标颜色选择器
color_picker = ui.color_input(
label='图标颜色',
value=DEFAULT_ICON_COLOR,
on_change=lambda e: change_icon_color(e.value)
).props('rounded outlined hide-header').style('width: 180px; min-width: 150px')
color_picker.add_slot('prepend', '<i class="material-icons">color_lens</i>')
# 新增:重置颜色按钮
ui.button(
'重置颜色',
on_click=lambda: reset_icon_color(),
icon='refresh'
).props('outline rounded').style('height: 56px')
# 统计显示
count_label = ui.label(f'共 {len(MATERIAL_ICONS)} 个图标').style('margin-left: auto; color: #666; white-space: nowrap')
# ========== 图标展示区域(响应式网格布局) ==========
with ui.column().classes('w-full box-border'):
# grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)) 表示:
# - auto-fill: 自动填充列数
# - minmax(120px, 1fr): 每列最小120px,最大自适应
grid = ui.grid().style('''
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 1.5rem;
max-width: 1600px;
margin: 0 auto;
width: 100%;
''')
# 生成所有图标卡片
for icon in MATERIAL_ICONS:
icon_name = icon['name']
icon_desc = icon['description']
icon_category = icon['category']
with grid:
# 优化卡片样式:移除固定宽度,使用百分比宽度,保证自适应
card_style = (
'padding: 1rem 0.8rem; '
'text-align: center; '
'border-radius: 8px; '
'box-shadow: 0 2px 4px rgba(0,0,0,0.1); '
'width: 100%; ' # 改为100%宽度,适应网格列宽
'height: 200px; '
'display: flex; '
'flex-direction: column; '
'align-items: center; '
'justify-content: center; '
'transition: all 0.2s ease; '
'background-color: white; '
'overflow: hidden;'
)
card = ui.card().style(card_style)
# 鼠标悬停效果(分开绑定,避免样式字符串解析错误)
card.on('mouseenter', lambda e: e.sender.style('box-shadow: 0 4px 8px rgba(0,0,0,0.15); transform: translateY(-2px)'))
card.on('mouseleave', lambda e: e.sender.style('box-shadow: 0 2px 4px rgba(0,0,0,0.1); transform: translateY(0)'))
with card:
with ui.column().classes('gap-0 items-center w-full'):
# 适配尺寸的图标 - 保存图标元素引用
icon_elem = ui.icon(icon_name).style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {current_icon_color}')
# 紧凑的文字样式
name_style = (
'font-family: Consolas, monospace; '
'font-size: 12px; '
'font-weight: bold; '
'margin-bottom: 0.2rem; '
'color: #333; '
'word-break: break-all; '
'line-height: 1.2;'
)
ui.label(icon_name).style(name_style)
ui.label(icon_desc).style('font-size: 11px; color: #666; margin-bottom: 0.3rem')
ui.label(icon_category).props('color=secondary text-xs').style('margin-bottom: 0.3rem')
# 小巧的复制按钮
ui.button('复制', on_click=lambda n=icon_name: copy_icon_name(n)) \
.props('outline rounded').style('width: 80px; height: 30px; font-size: 11px')
# 保存卡片和图标元素引用
icon_cards[icon_name] = card
icon_elements[icon_name] = icon_elem
# ========== 颜色修改函数 ==========
def change_icon_color(new_color: str):
"""修改所有显示图标的颜色"""
nonlocal current_icon_color
current_icon_color = new_color
# 遍历所有图标元素更新颜色
for icon_name, icon_elem in icon_elements.items():
# 只更新显示中的图标
if icon_cards[icon_name].style.get('display', 'flex') == 'flex':
icon_elem.style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {new_color}')
ui.notify(f'图标颜色已更新为: {new_color}', type='info', timeout=2000)
def reset_icon_color():
"""重置图标颜色为默认值"""
nonlocal current_icon_color
current_icon_color = DEFAULT_ICON_COLOR
# 更新颜色选择器值
color_picker.value = DEFAULT_ICON_COLOR
# 重置所有图标颜色
for icon_name, icon_elem in icon_elements.items():
if icon_cards[icon_name].style.get('display', 'flex') == 'flex':
icon_elem.style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {DEFAULT_ICON_COLOR}')
ui.notify('图标颜色已重置为默认值', type='success', timeout=2000)
# ========== 组合筛选函数(分类+搜索) ==========
def update_filter(category: str = None, search_text: str = None):
nonlocal current_category, current_search_text
# 更新筛选状态
if category is not None:
current_category = category
if search_text is not None:
current_search_text = search_text.lower().strip()
match_count = 0
# 遍历所有图标应用筛选
for icon in MATERIAL_ICONS:
icon_name = icon['name']
card = icon_cards[icon_name]
icon_elem = icon_elements[icon_name]
# 条件1:分类匹配(全部图标则跳过分类筛选)
category_match = (current_category == '全部图标') or (icon['category'] == current_category)
# 条件2:搜索匹配(名称/描述包含关键词)
search_match = True
if current_search_text:
search_match = (current_search_text in icon_name.lower()) or (current_search_text in icon['description'].lower())
# 显示/隐藏卡片,并确保显示的图标使用当前颜色
if category_match and search_match:
card.style('display: flex')
# 确保显示的图标使用当前选中的颜色
icon_elem.style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {current_icon_color}')
match_count += 1
else:
card.style('display: none')
# 更新统计
total_in_category = len(MATERIAL_ICONS) if current_category == '全部图标' else len([i for i in MATERIAL_ICONS if i['category'] == current_category])
count_label.set_text(f'找到 {match_count} 个图标({current_category}共 {total_in_category} 个)')
# ========== 页脚 ==========
with ui.footer().style('padding: 0.8rem; text-align: center; background-color: #4caf50; color: white'):
ui.label('NiceGUI 3.4.0 原生Material Design图标 | 200+常用图标 | 支持分类筛选+关键词搜索+颜色自定义 | 可直接复制图标名称使用')
# 兼容多进程的主程序保护语句
if __name__ in {"__main__", "__mp_main__"}:
main()
# 启动NiceGUI
ui.run(
title='NiceGUI Material图标库',
port=8080,
reload=True,
show=True,
uvicorn_logging_level='warning'
)
NiceGUI Material Design 图标库
项目介绍
本项目是基于 NiceGUI 3.4.0 开发的 Material Design 图标库工具,整合了 200+ 常用内置图标,支持按分类筛选、关键词搜索、图标颜色自定义及图标名称一键复制功能。界面简洁直观、响应式布局适配多种屏幕尺寸,旨在为 NiceGUI 开发者提供便捷的图标选型与使用体验。
核心功能
- 丰富的图标资源:包含 200+ 个 Material Design 内置图标,涵盖导航、操作、功能、提示、文件、设备等 10 大分类,满足日常开发需求。
- 多维度筛选:支持按分类筛选(如"导航""操作""文件"等),同时支持关键词搜索(匹配图标名称或描述),快速定位目标图标。
- 自定义图标颜色:内置颜色选择器,可自由切换图标显示颜色,支持十六进制颜色值输入,同时提供"重置颜色"功能快速恢复默认色。
- 一键复制功能 :每个图标卡片配备"复制"按钮,点击即可复制图标名称(如
menu、home),直接用于 NiceGUI 项目开发。 - 响应式布局:采用自适应网格布局,在电脑、平板等不同尺寸设备上均能良好展示。
- 友好的视觉反馈:图标卡片hover效果、操作成功提示(复制、颜色修改)等,提升使用体验。
环境要求
- Python 3.8+
- NiceGUI 3.4.0+(推荐与项目依赖版本一致)
安装步骤
1. 克隆/下载项目
将项目代码下载到本地,或通过 git 克隆(若使用版本控制):
bash
git clone <项目仓库地址>
cd nicegui-material-icon-library
2. 安装依赖
使用 pip 安装所需依赖(主要为 NiceGUI):
ini
pip install nicegui==3.4.0
若需快速安装最新兼容版本,可简化为:
pip install nicegui
运行方法
在项目根目录下,执行以下命令启动程序:
python icon_library.py
程序启动后,会自动在默认浏览器中打开页面(默认地址:http://localhost:8080)。若浏览器未自动打开,可手动访问该地址。
使用指南
1. 浏览与筛选图标
- 分类筛选:点击顶部导航栏的"分类筛选"下拉框,选择目标分类(如"导航""操作"),页面将仅显示该分类下的图标。选择"全部图标"可恢复显示所有图标。
- 关键词搜索:在顶部搜索框中输入关键词(支持图标名称或描述,如"菜单""arrow""home"),页面将实时筛选出匹配的图标。清空搜索框可恢复显示所有图标。
2. 自定义图标颜色
- 选择颜色:点击顶部导航栏的"图标颜色"选择器,通过颜色面板选择所需颜色,或直接输入十六进制颜色值(如 #ff0000、#2196f3),页面中所有显示的图标将实时更新为所选颜色。
- 重置颜色:点击"重置颜色"按钮,可快速将所有图标恢复为默认颜色(#4caf50,Material Design 绿色)。
3. 复制图标名称
找到目标图标后,点击图标卡片下方的"复制"按钮,系统将自动复制该图标的名称(如 search、delete),并显示"已复制图标名称"的成功提示。复制后可直接在 NiceGUI 项目中使用该名称创建图标,示例:
python
from nicegui import ui
ui.icon('menu') # 使用复制的图标名称
ui.run()
4. 查看图标信息
每个图标卡片包含以下信息:
- 图标预览:直观展示图标样式
- 图标名称:NiceGUI 中使用的图标标识(可复制)
- 图标描述:中文说明,便于理解图标用途
- 图标分类:该图标所属的分类
项目结构
bash
nicegui-material-icon-library/
├── icon_library.py # 主程序文件(核心代码)
└── README.md # 项目说明文档
核心代码说明:
MATERIAL_ICONS:存储所有图标的信息(名称、描述、分类),可在此扩展或修改图标列表。get_all_categories():获取所有图标分类(去重并排序),用于分类筛选下拉框。copy_icon_name():实现图标名称复制功能,并显示提示信息。change_icon_color():实现图标颜色更新功能。reset_icon_color():实现图标颜色重置功能。update_filter():组合分类筛选和关键词搜索功能,控制图标显示/隐藏。
扩展与定制
1. 增加更多图标
在 MATERIAL_ICONS 列表中添加新的图标字典,格式如下:
bash
{
'name': '图标名称', # NiceGUI 支持的 Material Design 图标名称
'description': '中文描述', # 图标用途说明
'category': '分类名称' # 所属分类(如"导航""操作",可新增分类)
}
2. 修改默认配置
- 默认颜色 :修改
DEFAULT_ICON_COLOR变量的值,可更改图标默认颜色。 - 页面主题 :修改
ui.colors()中的primary(主色)和secondary(辅助色),可更改页面主题色。 - 端口号 :修改
ui.run()中的port参数,可更改程序运行端口(如port=8081)。
3. 调整界面样式
可修改代码中相关的 style 属性,调整图标卡片大小、颜色、间距,导航栏样式,字体大小等,实现个性化界面定制。
常见问题
1. 图标无法正常显示?
- 检查 NiceGUI 版本是否兼容(推荐 3.4.0+),若版本过低,可能导致部分图标无法显示。
- 确保网络正常,程序需加载 Material Icons 字体(已配置国内镜像:fonts.googleapis.cn),网络异常可能导致图标加载失败。
2. 复制功能无效?
部分浏览器可能限制剪贴板访问权限,建议在浏览器地址栏旁确认权限(允许剪贴板访问),或尝试更换主流浏览器(如 Chrome、Edge、Firefox)。
3. 程序启动失败?
- 检查端口是否被占用,若 8080 端口已被其他程序使用,可修改
ui.run()中的port参数,使用其他空闲端口。 - 检查 Python 版本是否符合要求(3.8+),过低版本可能导致语法错误。
致谢
- 基于 NiceGUI 框架开发,感谢 NiceGUI 团队提供的简洁高效的开发工具。
- 图标资源基于 Material Design Icons,感谢 Google 提供的开源图标库。
由于局域网不能复制改变下用(pyperclip):
python
from nicegui import ui, events
from typing import List, Dict
import pyperclip # 核心:引入pyperclip实现服务端复制
import sys
class MaterialIconLibrary:
# ========== 类级常量定义 ==========
MATERIAL_ICONS: List[Dict[str, str]] = [
# 导航类(25个)
{'name': 'menu', 'description': '菜单', 'category': '导航'},
{'name': 'home', 'description': '首页', 'category': '导航'},
{'name': 'search', 'description': '搜索', 'category': '导航'},
{'name': 'arrow_back', 'description': '返回', 'category': '导航'},
{'name': 'arrow_forward', 'description': '前进', 'category': '导航'},
{'name': 'arrow_upward', 'description': '向上', 'category': '导航'},
{'name': 'arrow_downward', 'description': '向下', 'category': '导航'},
{'name': 'chevron_left', 'description': '左箭头', 'category': '导航'},
{'name': 'chevron_right', 'description': '右箭头', 'category': '导航'},
{'name': 'expand_more', 'description': '展开更多', 'category': '导航'},
{'name': 'expand_less', 'description': '收起', 'category': '导航'},
{'name': 'menu_open', 'description': '展开菜单', 'category': '导航'},
{'name': 'menu_book', 'description': '菜单书', 'category': '导航'},
{'name': 'close', 'description': '关闭', 'category': '导航'},
{'name': 'backspace', 'description': '退格', 'category': '导航'},
{'name': 'arrow_left', 'description': '左箭头', 'category': '导航'},
{'name': 'arrow_right', 'description': '右箭头', 'category': '导航'},
{'name': 'arrow_up', 'description': '上箭头', 'category': '导航'},
{'name': 'arrow_down', 'description': '下箭头', 'category': '导航'},
{'name': 'navigate_before', 'description': '导航前', 'category': '导航'},
{'name': 'navigate_next', 'description': '导航后', 'category': '导航'},
{'name': 'keyboard_arrow_up', 'description': '键盘上箭头', 'category': '导航'},
{'name': 'keyboard_arrow_down', 'description': '键盘下箭头', 'category': '导航'},
{'name': 'keyboard_arrow_left', 'description': '键盘左箭头', 'category': '导航'},
{'name': 'keyboard_arrow_right', 'description': '键盘右箭头', 'category': '导航'},
# 操作类(28个)
{'name': 'add', 'description': '添加', 'category': '操作'},
{'name': 'edit', 'description': '编辑', 'category': '操作'},
{'name': 'delete', 'description': '删除', 'category': '操作'},
{'name': 'save', 'description': '保存', 'category': '操作'},
{'name': 'cancel', 'description': '取消', 'category': '操作'},
{'name': 'check', 'description': '确认', 'category': '操作'},
{'name': 'undo', 'description': '撤销', 'category': '操作'},
{'name': 'redo', 'description': '重做', 'category': '操作'},
{'name': 'copy', 'description': '复制', 'category': '操作'},
{'name': 'cut', 'description': '剪切', 'category': '操作'},
{'name': 'paste', 'description': '粘贴', 'category': '操作'},
{'name': 'select_all', 'description': '全选', 'category': '操作'},
{'name': 'refresh', 'description': '刷新', 'category': '操作'},
{'name': 'download', 'description': '下载', 'category': '操作'},
{'name': 'upload', 'description': '上传', 'category': '操作'},
{'name': 'share', 'description': '分享', 'category': '操作'},
{'name': 'send', 'description': '发送', 'category': '操作'},
{'name': 'clear', 'description': '清除', 'category': '操作'},
{'name': 'done', 'description': '完成', 'category': '操作'},
{'name': 'remove', 'description': '移除', 'category': '操作'},
{'name': 'create', 'description': '创建', 'category': '操作'},
{'name': 'archive', 'description': '归档', 'category': '操作'},
{'name': 'restore', 'description': '恢复', 'category': '操作'},
{'name': 'backup', 'description': '备份', 'category': '操作'},
{'name': 'import_export', 'description': '导入导出', 'category': '操作'},
{'name': 'move_to_inbox', 'description': '移入收件箱', 'category': '操作'},
{'name': 'unarchive', 'description': '取消归档', 'category': '操作'},
{'name': 'publish', 'description': '发布', 'category': '操作'},
# 功能类(26个)
{'name': 'settings', 'description': '设置', 'category': '功能'},
{'name': 'person', 'description': '个人', 'category': '功能'},
{'name': 'email', 'description': '邮件', 'category': '功能'},
{'name': 'phone', 'description': '电话', 'category': '功能'},
{'name': 'lock', 'description': '锁定', 'category': '功能'},
{'name': 'lock_open', 'description': '解锁', 'category': '功能'},
{'name': 'visibility', 'description': '可见', 'category': '功能'},
{'name': 'visibility_off', 'description': '隐藏', 'category': '功能'},
{'name': 'favorite', 'description': '收藏', 'category': '功能'},
{'name': 'star', 'description': '星星', 'category': '功能'},
{'name': 'star_border', 'description': '空心星', 'category': '功能'},
{'name': 'filter', 'description': '筛选', 'category': '功能'},
{'name': 'sort', 'description': '排序', 'category': '功能'},
{'name': 'more_vert', 'description': '更多(竖)', 'category': '功能'},
{'name': 'more_horiz', 'description': '更多(横)', 'category': '功能'},
{'name': 'account_circle', 'description': '账户头像', 'category': '功能'},
{'name': 'badge', 'description': '徽章', 'category': '功能'},
{'name': 'bookmark', 'description': '书签', 'category': '功能'},
{'name': 'bookmark_border', 'description': '空心书签', 'category': '功能'},
{'name': 'contact_page', 'description': '联系人页面', 'category': '功能'},
{'name': 'dashboard', 'description': '仪表盘', 'category': '功能'},
{'name': 'edit_note', 'description': '编辑笔记', 'category': '功能'},
{'name': 'flag', 'description': '旗帜', 'category': '功能'},
{'name': 'help_outline', 'description': '帮助轮廓', 'category': '功能'},
{'name': 'history', 'description': '历史', 'category': '功能'},
{'name': 'login', 'description': '登录', 'category': '功能'},
# 提示类(12个)
{'name': 'error', 'description': '错误', 'category': '提示'},
{'name': 'warning', 'description': '警告', 'category': '提示'},
{'name': 'info', 'description': '信息', 'category': '提示'},
{'name': 'help', 'description': '帮助', 'category': '提示'},
{'name': 'check_circle', 'description': '成功圈', 'category': '提示'},
{'name': 'error_outline', 'description': '错误轮廓', 'category': '提示'},
{'name': 'warning_amber', 'description': '警告琥珀色', 'category': '提示'},
{'name': 'info_outline', 'description': '信息轮廓', 'category': '提示'},
{'name': 'check_circle_outline', 'description': '成功圈轮廓', 'category': '提示'},
{'name': 'report', 'description': '报告', 'category': '提示'},
{'name': 'report_problem', 'description': '报告问题', 'category': '提示'},
{'name': 'notifications', 'description': '通知', 'category': '提示'},
# 文件类(18个)
{'name': 'folder', 'description': '文件夹', 'category': '文件'},
{'name': 'folder_open', 'description': '打开文件夹', 'category': '文件'},
{'name': 'file', 'description': '文件', 'category': '文件'},
{'name': 'file_copy', 'description': '复制文件', 'category': '文件'},
{'name': 'image', 'description': '图片', 'category': '文件'},
{'name': 'video_library', 'description': '视频库', 'category': '文件'},
{'name': 'music_note', 'description': '音乐', 'category': '文件'},
{'name': 'description', 'description': '文档', 'category': '文件'},
{'name': 'file_download', 'description': '文件下载', 'category': '文件'},
{'name': 'file_upload', 'description': '文件上传', 'category': '文件'},
{'name': 'file_present', 'description': '文件展示', 'category': '文件'},
{'name': 'folder_copy', 'description': '复制文件夹', 'category': '文件'},
{'name': 'insert_drive_file', 'description': '插入文件', 'category': '文件'},
{'name': 'pdf', 'description': 'PDF文件', 'category': '文件'},
{'name': 'picture_as_pdf', 'description': 'PDF图片', 'category': '文件'},
{'name': 'text_snippet', 'description': '文本片段', 'category': '文件'},
{'name': 'upload_file', 'description': '上传文件', 'category': '文件'},
{'name': 'cloud_upload', 'description': '云上传', 'category': '文件'},
# 设备类(20个)
{'name': 'laptop', 'description': '笔记本', 'category': '设备'},
{'name': 'desktop_windows', 'description': '桌面', 'category': '设备'},
{'name': 'phone_android', 'description': '安卓手机', 'category': '设备'},
{'name': 'tablet_android', 'description': '平板', 'category': '设备'},
{'name': 'print', 'description': '打印', 'category': '设备'},
{'name': 'wifi', 'description': 'WiFi', 'category': '设备'},
{'name': 'bluetooth', 'description': '蓝牙', 'category': '设备'},
{'name': 'battery_full', 'description': '满电', 'category': '设备'},
{'name': 'battery_half', 'description': '半电', 'category': '设备'},
{'name': 'battery_empty', 'description': '无电', 'category': '设备'},
{'name': 'battery_charging_full', 'description': '充电满', 'category': '设备'},
{'name': 'camera', 'description': '相机', 'category': '设备'},
{'name': 'headset', 'description': '耳机', 'category': '设备'},
{'name': 'keyboard', 'description': '键盘', 'category': '设备'},
{'name': 'mouse', 'description': '鼠标', 'category': '设备'},
{'name': 'scanner', 'description': '扫描仪', 'category': '设备'},
{'name': 'speaker', 'description': '扬声器', 'category': '设备'},
{'name': 'tv', 'description': '电视', 'category': '设备'},
{'name': 'usb', 'description': 'USB', 'category': '设备'},
{'name': 'watch', 'description': '手表', 'category': '设备'},
# 时间类(12个)
{'name': 'calendar_today', 'description': '今日日历', 'category': '时间'},
{'name': 'access_time', 'description': '时间', 'category': '时间'},
{'name': 'alarm', 'description': '闹钟', 'category': '时间'},
{'name': 'timer', 'description': '计时器', 'category': '时间'},
{'name': 'stopwatch', 'description': '秒表', 'category': '时间'},
{'name': 'calendar_month', 'description': '月历', 'category': '时间'},
{'name': 'calendar_week', 'description': '周历', 'category': '时间'},
{'name': 'clock', 'description': '时钟', 'category': '时间'},
{'name': 'date_range', 'description': '日期范围', 'category': '时间'},
{'name': 'schedule', 'description': '日程', 'category': '时间'},
{'name': 'timer_10', 'description': '10分钟计时器', 'category': '时间'},
{'name': 'timer_off', 'description': '关闭计时器', 'category': '时间'},
# 购物类(15个)
{'name': 'shopping_cart', 'description': '购物车', 'category': '购物'},
{'name': 'payment', 'description': '支付', 'category': '购物'},
{'name': 'tag', 'description': '标签', 'category': '购物'},
{'name': 'barcode', 'description': '条形码', 'category': '购物'},
{'name': 'qr_code', 'description': '二维码', 'category': '购物'},
{'name': 'attach_money', 'description': '金额', 'category': '购物'},
{'name': 'card_giftcard', 'description': '礼品卡', 'category': '购物'},
{'name': 'credit_card', 'description': '信用卡', 'category': '购物'},
{'name': 'money', 'description': '货币', 'category': '购物'},
{'name': 'price_check', 'description': '价格检查', 'category': '购物'},
{'name': 'receipt', 'description': '收据', 'category': '购物'},
{'name': 'sell', 'description': '出售', 'category': '购物'},
{'name': 'shopping_bag', 'description': '购物袋', 'category': '购物'},
{'name': 'store', 'description': '商店', 'category': '购物'},
{'name': 'local_atm', 'description': 'ATM机', 'category': '购物'},
# 媒体类(18个)
{'name': 'volume_up', 'description': '音量大', 'category': '媒体'},
{'name': 'volume_down', 'description': '音量小', 'category': '媒体'},
{'name': 'volume_mute', 'description': '静音', 'category': '媒体'},
{'name': 'volume_off', 'description': '无音量', 'category': '媒体'},
{'name': 'play_arrow', 'description': '播放', 'category': '媒体'},
{'name': 'pause', 'description': '暂停', 'category': '媒体'},
{'name': 'stop', 'description': '停止', 'category': '媒体'},
{'name': 'skip_next', 'description': '下一曲', 'category': '媒体'},
{'name': 'skip_previous', 'description': '上一曲', 'category': '媒体'},
{'name': 'fast_forward', 'description': '快进', 'category': '媒体'},
{'name': 'fast_rewind', 'description': '快退', 'category': '媒体'},
{'name': 'repeat', 'description': '重复', 'category': '媒体'},
{'name': 'shuffle', 'description': '随机播放', 'category': '媒体'},
{'name': 'audiotrack', 'description': '音轨', 'category': '媒体'},
{'name': 'mic', 'description': '麦克风', 'category': '媒体'},
{'name': 'mic_off', 'description': '关闭麦克风', 'category': '媒体'},
{'name': 'photo_camera', 'description': '拍照', 'category': '媒体'},
{'name': 'video_call', 'description': '视频通话', 'category': '媒体'},
# 工具类(20个)
{'name': 'zoom_in', 'description': '放大', 'category': '工具'},
{'name': 'zoom_out', 'description': '缩小', 'category': '工具'},
{'name': 'fullscreen', 'description': '全屏', 'category': '工具'},
{'name': 'fullscreen_exit', 'description': '退出全屏', 'category': '工具'},
{'name': 'rotate_left', 'description': '左转', 'category': '工具'},
{'name': 'rotate_right', 'description': '右转', 'category': '工具'},
{'name': 'delete_sweep', 'description': '清除', 'category': '工具'},
{'name': 'adjust', 'description': '调整', 'category': '工具'},
{'name': 'build', 'description': '构建', 'category': '工具'},
{'name': 'calculator', 'description': '计算器', 'category': '工具'},
{'name': 'color_lens', 'description': '色镜', 'category': '工具'},
{'name': 'compass_calibration', 'description': '罗盘校准', 'category': '工具'},
{'name': 'crop', 'description': '裁剪', 'category': '工具'},
{'name': 'draw', 'description': '绘制', 'category': '工具'},
{'name': 'extension', 'description': '扩展', 'category': '工具'},
{'name': 'flash_on', 'description': '闪光灯开', 'category': '工具'},
{'name': 'flash_off', 'description': '闪光灯关', 'category': '工具'},
{'name': 'highlight', 'description': '高亮', 'category': '工具'},
{'name': 'level', 'description': '水平', 'category': '工具'},
{'name': 'measure', 'description': '测量', 'category': '工具'}
]
# 默认图标颜色
DEFAULT_ICON_COLOR = '#4caf50'
def __init__(self):
"""初始化图标库实例,设置状态变量和UI组件引用"""
# 状态变量
self.current_category = '全部图标'
self.current_search_text = ''
self.current_icon_color = self.DEFAULT_ICON_COLOR
# UI组件引用
self.icon_cards = {} # key: 图标name, value: 卡片元素
self.icon_elements = {} # key: 图标name, value: 图标元素
self.category_select = None # 分类筛选下拉框
self.color_picker = None # 颜色选择器
self.count_label = None # 统计标签
@staticmethod
def get_all_categories() -> List[str]:
"""获取所有分类(去重并排序)- 静态方法"""
categories = sorted(list(set(icon['category'] for icon in MaterialIconLibrary.MATERIAL_ICONS)))
return ['全部图标'] + categories
def copy_icon_name(self, name: str):
"""
核心改造:使用pyperclip实现服务端复制,兼容局域网
复制完整的使用代码(参考案例的做法),而不只是图标名称
"""
# 生成完整的使用代码(包含当前选中的颜色)
if self.current_icon_color and self.current_icon_color != self.DEFAULT_ICON_COLOR:
# 如果修改了颜色,复制带颜色的代码
code = f"ui.icon('{name}', color='{self.current_icon_color}')"
else:
# 默认颜色,复制基础代码
code = f"ui.icon('{name}')"
try:
# 使用pyperclip复制到剪贴板(服务端操作,不受浏览器限制)
pyperclip.copy(code)
ui.notify(f'已复制图标代码: {code}', type='positive', timeout=3000)
except Exception as e:
# 复制失败的兼容处理
error_msg = f'复制失败: {str(e)}'
ui.notify(f'{error_msg}\n请手动复制: {code}', type='negative', timeout=5000)
# 备选方案:回退到文本框选中方案
self.fallback_copy(name, code)
def fallback_copy(self, name: str, code: str):
"""复制失败时的备选方案:创建临时文本框让用户手动复制"""
# 创建隐藏的文本框(只在复制失败时显示)
copy_input = ui.input(
value=code,
label='请手动复制图标代码'
).style('''
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 9999;
width: 300px;
opacity: 0.98;
''').props('readonly')
# 自动选中文本框内容
ui.run_javascript(f'''
const input = document.querySelector('input[aria-label="请手动复制图标代码"]');
if (input) {{
input.focus();
input.select();
input.setSelectionRange(0, input.value.length);
}}
''')
# 5秒后自动隐藏文本框
ui.timer(5.0, copy_input.delete, once=True)
def change_icon_color(self, new_color: str):
"""修改所有显示图标的颜色 - 实例方法"""
self.current_icon_color = new_color
# 遍历所有图标元素更新颜色
for icon_name, icon_elem in self.icon_elements.items():
# 只更新显示中的图标
if self.icon_cards[icon_name].style.get('display', 'flex') == 'flex':
icon_elem.style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {new_color}')
ui.notify(f'图标颜色已更新为: {new_color}', type='info', timeout=2000)
def reset_icon_color(self):
"""重置图标颜色为默认值 - 实例方法"""
self.current_icon_color = self.DEFAULT_ICON_COLOR
# 更新颜色选择器值
self.color_picker.value = self.DEFAULT_ICON_COLOR
# 重置所有图标颜色
for icon_name, icon_elem in self.icon_elements.items():
if self.icon_cards[icon_name].style.get('display', 'flex') == 'flex':
icon_elem.style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {self.DEFAULT_ICON_COLOR}')
ui.notify('图标颜色已重置为默认值', type='success', timeout=2000)
def update_filter(self, category: str = None, search_text: str = None):
"""组合筛选函数(分类+搜索)- 实例方法"""
# 更新筛选状态
if category is not None:
self.current_category = category
if search_text is not None:
self.current_search_text = search_text.lower().strip()
match_count = 0
# 遍历所有图标应用筛选
for icon in self.MATERIAL_ICONS:
icon_name = icon['name']
card = self.icon_cards[icon_name]
icon_elem = self.icon_elements[icon_name]
# 条件1:分类匹配(全部图标则跳过分类筛选)
category_match = (self.current_category == '全部图标') or (icon['category'] == self.current_category)
# 条件2:搜索匹配(名称/描述包含关键词)
search_match = True
if self.current_search_text:
search_match = (self.current_search_text in icon_name.lower()) or (self.current_search_text in icon['description'].lower())
# 显示/隐藏卡片,并确保显示的图标使用当前颜色
if category_match and search_match:
card.style('display: flex')
# 确保显示的图标使用当前选中的颜色
icon_elem.style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {self.current_icon_color}')
match_count += 1
else:
card.style('display: none')
# 更新统计
total_in_category = len(self.MATERIAL_ICONS) if self.current_category == '全部图标' else len([i for i in self.MATERIAL_ICONS if i['category'] == self.current_category])
self.count_label.set_text(f'找到 {match_count} 个图标({self.current_category}共 {total_in_category} 个)')
def setup_ui(self):
"""设置UI界面 - 核心实例方法"""
# 强制加载Material Icons字体(解决国内显示问题)
ui.add_head_html('''
<link href="https://fonts.googleapis.cn/css2?family=Material+Icons" rel="stylesheet">
''')
# 页面基础配置
ui.page_title('NiceGUI 3.4.0 Material Design图标库')
ui.colors(primary='#4caf50', secondary='#03DAC6') # Material Design主题色
# ========== 顶部导航栏(分类筛选+搜索+颜色选择) ==========
with ui.header(elevated=True).style('padding: 1rem 2rem; background-color: white; display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap'):
# 标题
ui.label('NiceGUI 内置Material Design图标库').style('font-size: 1.8rem; font-weight: bold; color: #4caf50; margin-right: 1rem')
# 分类筛选下拉框 - 保存引用
self.category_select = ui.select(
options=self.get_all_categories(),
value='全部图标',
on_change=lambda e: self.update_filter(category=e.value)
).props('rounded outlined').style('width: 180px; min-width: 150px')
self.category_select.add_slot('prepend', '<i class="material-icons">folder_category</i>')
# 搜索框(支持搜索名称/描述)
search_input = ui.input(
placeholder='搜索图标(名称/描述,如:菜单、arrow、home)',
on_change=lambda e: self.update_filter(search_text=e.value)
).props('rounded outlined').style('width: 300px; min-width: 200px; flex-grow: 1; max-width: 500px')
search_input.add_slot('prepend', '<i class="material-icons">search</i>')
# 图标颜色选择器 - 保存引用
self.color_picker = ui.color_input(
label='图标颜色',
value=self.DEFAULT_ICON_COLOR,
on_change=lambda e: self.change_icon_color(e.value)
).props('rounded outlined hide-header').style('width: 180px; min-width: 150px')
self.color_picker.add_slot('prepend', '<i class="material-icons">color_lens</i>')
# 重置颜色按钮
ui.button(
'重置颜色',
on_click=lambda: self.reset_icon_color(),
icon='refresh'
).props('outline rounded').style('height: 56px')
# 统计显示 - 保存引用
self.count_label = ui.label(f'共 {len(self.MATERIAL_ICONS)} 个图标').style('margin-left: auto; color: #666; white-space: nowrap')
# ========== 图标展示区域(响应式网格布局) ==========
with ui.column().classes('w-full box-border'):
# grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)) 表示:
# - auto-fill: 自动填充列数
# - minmax(120px, 1fr): 每列最小120px,最大自适应
grid = ui.grid().style('''
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 1.5rem;
max-width: 1600px;
margin: 0 auto;
width: 100%;
''')
# 生成所有图标卡片
for icon in self.MATERIAL_ICONS:
icon_name = icon['name']
icon_desc = icon['description']
icon_category = icon['category']
with grid:
# 优化卡片样式:移除固定宽度,使用百分比宽度,保证自适应
card_style = (
'padding: 1rem 0.8rem; '
'text-align: center; '
'border-radius: 8px; '
'box-shadow: 0 2px 4px rgba(0,0,0,0.1); '
'width: 100%; ' # 改为100%宽度,适应网格列宽
'height: 200px; '
'display: flex; '
'flex-direction: column; '
'align-items: center; '
'justify-content: center; '
'transition: all 0.2s ease; '
'background-color: white; '
'overflow: hidden;'
)
card = ui.card().style(card_style)
# 鼠标悬停效果(分开绑定,避免样式字符串解析错误)
card.on('mouseenter', lambda e: e.sender.style('box-shadow: 0 4px 8px rgba(0,0,0,0.15); transform: translateY(-2px)'))
card.on('mouseleave', lambda e: e.sender.style('box-shadow: 0 2px 4px rgba(0,0,0,0.1); transform: translateY(0)'))
with card:
with ui.column().classes('gap-0 items-center w-full'):
# 适配尺寸的图标 - 保存图标元素引用
icon_elem = ui.icon(icon_name).style(f'font-size: 2.5rem; margin-bottom: 0.5rem; color: {self.current_icon_color}')
# 紧凑的文字样式
name_style = (
'font-family: Consolas, monospace; '
'font-size: 12px; '
'font-weight: bold; '
'margin-bottom: 0.2rem; '
'color: #333; '
'word-break: break-all; '
'line-height: 1.2;'
)
ui.label(icon_name).style(name_style)
ui.label(icon_desc).style('font-size: 11px; color: #666; margin-bottom: 0.3rem')
ui.label(icon_category).props('color=secondary text-xs').style('margin-bottom: 0.3rem')
# 小巧的复制按钮(参考案例,改用content_copy图标更直观)
ui.button(
icon='content_copy', # 新增:添加复制图标,参考案例
on_click=lambda n=icon_name: self.copy_icon_name(n)
).props('outline rounded').style('width: 80px; height: 30px; font-size: 11px').tooltip('复制')
# 保存卡片和图标元素引用
self.icon_cards[icon_name] = card
self.icon_elements[icon_name] = icon_elem
# ========== 页脚 ==========
with ui.footer().style('padding: 0.8rem; text-align: center; background-color: #4caf50; color: white'):
ui.label('NiceGUI 3.4.0 原生Material Design图标 | 200+常用图标 | 支持分类筛选+关键词搜索+颜色自定义 | 局域网环境下已支持一键复制')
# ========== 修复核心:将页面注册改为函数式,避免self参数冲突 ==========
# 创建全局实例(保证单例)
icon_library_instance = MaterialIconLibrary()
# 页面路由注册为普通函数,内部调用实例的setup_ui方法
@ui.page('/icon')
def icon_page():
"""图标库页面入口 - 普通函数,避免self参数问题"""
icon_library_instance.setup_ui()
# ========== 程序调用示例 ==========
if __name__ in {"__main__", "__mp_main__"}:
# 安装pyperclip提示(首次运行时)
try:
import pyperclip
except ImportError:
print("正在安装pyperclip库...")
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyperclip"])
import pyperclip
# 启动NiceGUI(关键:添加host=0.0.0.0允许局域网访问)
ui.run(
title='NiceGUI Material图标库',
reload=True,
show=True,
uvicorn_logging_level='warning',
host='0.0.0.0' # 必须:允许局域网其他设备访问
)