You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何向tui::widgets::ListItem传递结构体并展示与获取详情

解决方案

要实现在ListItem中存储完整SongStruct、显示title、选中时获取结构体详情的需求,你可以利用tui.rs中ListItem的data字段携带完整结构体,同时配合事件循环处理选中逻辑。以下是具体修改步骤和完整代码:

1. 调整ListItem创建逻辑

直接遍历SongStruct向量,为每个结构体创建ListItem:用title作为显示内容,通过.data()方法将完整的SongStruct存入ListItem的自定义数据字段。

2. 添加事件循环处理交互

引入crossterm的event模块监听键盘事件,实现列表项选中切换,以及选中时获取结构体并调用自定义函数。

修改后的完整代码

pub struct SongStruct {
    pub title: String,
    pub artist: String,
    pub file_path: String,
}

use std::{
    io,
    time::{Duration, Instant},
};

use tui::{
    backend::CrosstermBackend,
    Terminal,
    widgets::{Block, Borders, List, ListItem},
    layout::{Layout, Direction, Constraint, Alignment},
    style::{Style, Color, Modifier},
    text::Span,
};

use crossterm::{
    terminal::{enable_raw_mode, disable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
    execute,
    event::{self, Event, KeyCode, KeyEvent},
};

use crate::audio::Song::SongStruct;

// 自定义函数:处理选中的歌曲结构体
fn handle_selected_song(song: &SongStruct) {
    println!("\n选中了歌曲:");
    println!("标题:{}", song.title);
    println!("艺术家:{}", song.artist);
    println!("文件路径:{}", song.file_path);
}

pub fn ui(mut song_list: Vec<SongStruct>) -> Result<(), io::Error> {
    enable_raw_mode().expect("无法启用原始模式");
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // 列表选中索引
    let mut selected_idx = 0;
    let refresh_rate = Duration::from_millis(16);

    loop {
        terminal.draw(|rect| {
            let size = rect.size();
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .margin(1)
                .constraints(
                    [
                        Constraint::Percentage(30),
                        Constraint::Percentage(70)
                    ].as_ref()
                )
                .split(size);
            
            let top_block = Block::default().title("rust-play").borders(Borders::ALL);
            rect.render_widget(top_block, chunks[0]);

            // 创建携带完整SongStruct的ListItem
            let list_items: Vec<ListItem<_>> = song_list
                .iter()
                .map(|song| ListItem::new(Span::styled(&song.title, Style::default().fg(Color::Yellow)))
                    .data(song.clone())) // 存储完整结构体
                .collect();

            let title_span = Span::styled("歌曲列表", Style::default().fg(Color::Red));
            let list = List::new(list_items)
                .block(Block::default().title(title_span).title_alignment(Alignment::Center).borders(Borders::ALL))
                .highlight_style(Style::default().add_modifier(Modifier::ITALIC).fg(Color::Green))
                .highlight_symbol(">>")
                .select(selected_idx); // 设置当前选中项

            rect.render_widget(list, chunks[1]);
        })?;

        // 监听事件
        if event::poll(refresh_rate)? {
            if let Event::Key(KeyEvent { code, .. }) = event::read()? {
                match code {
                    // 上下键切换选中项
                    KeyCode::Up => {
                        if selected_idx > 0 {
                            selected_idx -= 1;
                        }
                    }
                    KeyCode::Down => {
                        if selected_idx < song_list.len() - 1 {
                            selected_idx += 1;
                        }
                    }
                    // 回车键触发选中处理
                    KeyCode::Enter => {
                        let selected_song = &song_list[selected_idx];
                        handle_selected_song(selected_song);
                    }
                    // Esc键退出程序
                    KeyCode::Esc => break,
                    _ => {}
                }
            }
        }
    }

    // 清理终端
    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
    terminal.show_cursor()?;

    Ok(())
}

关键修改点说明

  • ListItem携带结构体:通过ListItem::new(显示内容).data(song.clone())将完整的SongStruct存入ListItem的data字段,选中时可直接取出。
  • 事件循环:添加事件监听逻辑,处理上下键切换选中索引,回车键触发自定义的handle_selected_song函数并传入选中的歌曲结构体。
  • 选中状态标记:使用List::select(selected_idx)标记当前选中项,配合高亮样式提升交互体验。

内容的提问来源于stack exchange,提问作者devMe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:07:57