您的位置:首页 > 房产 > 建筑 > 音乐排行榜网页设计作业_网页制作专业选择_正在直播足球比赛_一个具体网站的seo优化方案

音乐排行榜网页设计作业_网页制作专业选择_正在直播足球比赛_一个具体网站的seo优化方案

2025/4/23 0:26:53 来源:https://blog.csdn.net/u014161864/article/details/147309460  浏览:    关键词:音乐排行榜网页设计作业_网页制作专业选择_正在直播足球比赛_一个具体网站的seo优化方案
音乐排行榜网页设计作业_网页制作专业选择_正在直播足球比赛_一个具体网站的seo优化方案

引言

之前的文章已经介绍实现了AI对话窗口,但只有个空壳,没有实现功能。本次将集中完成对话窗口的功能,主要内容为:

  • 模型动态切换:支持运行时加载配置的AI模型列表
  • 交互式输入处理:实现多行文本输入与Ctrl+Enter提交逻辑
  • 异步模型调用:通过回调机制实现流式输出与界面实时更新
  • 状态控制:提供发送/停止双模式按钮,支持任务中断
用户 输入框 主窗口 模型 界面 按钮 输入内容(Ctrl+Enter) 触发OnInputFinished 调用DirectRequest 流式返回数据 实时追加输出 点击停止 设置g_bRun=false 任务终止通知 恢复初始状态 用户 输入框 主窗口 模型 界面 按钮

模型下拉支持

启动时读取插件配置,包括当前模型名称和平台所支持的模型列表,然后启动AI对话窗口时加载该模型列表,并选中当前模型名称

// 打开AI助手停靠窗口的主入口函数
void OpenAiAssistWnd()
{// 检查窗口实例、模块句柄和Notepad++主窗口的有效性if (g_pAiWnd == nullptr && g_hModule != nullptr && g_nppData._nppHandle != nullptr){// 创建AI助手窗口实例// 参数1: 插件模块实例句柄,用于加载资源// 参数2: Notepad++核心数据接口,用于窗口绑定g_pAiWnd = new AiAssistWnd((HINSTANCE)g_hModule, g_nppData);// 执行窗口初始化操作// 包含创建子控件、设置布局、注册消息处理器等g_pAiWnd->init();// 获取当前配置的平台信息auto& platform = g_pluginConf.Platform();// 在模型列表中查找当前选定的模型// 用于初始化界面中的模型选择控件auto it = std::find(platform.models.begin(), platform.models.end(), platform.model_name);// 更新界面模型列表并设置默认选中项// 当未找到配置的模型时默认选择第一个条目(索引0)g_pAiWnd->updateModelList(platform.models, (it == platform.models.end()) ? 0 : static_cast<int>(std::distance(platform.models.begin(), it)));}// 注1: 此处假设g_pluginConf.Platform().models至少包含一个元素// 注2: 窗口关闭时应调用delete g_pAiWnd释放资源// 注3: 实际部署需添加异常处理机制
}

提交用户输入

用户输入是一个文本输入框EDIT,一开始我计划通过响应窗口事件函数获取输入的,但是发现文本框的输入根本不触发窗口事件函数,怀疑是被窗口拦截了。因此,我在创建该文本输入框的时候,为该控件创建单独的事件处理过程。

为了支持输入时支持换行,因此采用Ctrl+Enter作为快捷键提交用户输入,且用户输入也会提交到输出窗口。

  • 控件子类化:通过InputEditSubclassProc拦截编辑框消息,实现:
    • Ctrl+Enter提交与普通回车换行分离
    • 输入内容过滤(空值/纯空白字符校验)
  • 输入输出分离:用户提问内容自动添加【问】标记并清空输入区

代码实现如下:

// 输入框子类化处理函数,用于自定义编辑控件行为
LRESULT CALLBACK InputEditSubclassProc(HWND hWnd,          // 控件窗口句柄UINT uMsg,          // 消息类型WPARAM wParam,      // 消息参数LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData  // 存储关联的类实例指针
)
{// 将保存的指针转换为窗口类实例auto pThis = (AiAssistWnd*)dwRefData;// 处理键盘按下消息if (uMsg == WM_KEYDOWN && wParam == VK_RETURN) {// 检测Ctrl键是否被按住if (GetKeyState(VK_CONTROL) & 0x8000) {// 调用输入完成处理函数,成功则阻止默认回车行为if (pThis->OnInputFinished()){return 0;  // 中断消息传递}}}// 处理字符输入消息else if (uMsg == WM_CHAR){// 当Ctrl键按下时处理特殊字符if (GetKeyState(VK_CONTROL) & 0x8000){// 屏蔽回车和换行符的输入if (wParam == VK_RETURN || wParam == 0x0A){return 0;}}// 处理普通回车输入if (wParam == VK_RETURN){// 若Ctrl按下则忽略if (GetKeyState(VK_CONTROL) & 0x8000){return 0;}// 插入Windows风格换行符const wchar_t* pLR = L"\r\n";SendMessageW(hWnd, EM_REPLACESEL, FALSE, (LPARAM)pLR); }}// 执行默认消息处理return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}// 输入完成处理函数
bool AiAssistWnd::OnInputFinished()
{// 获取输入框文本长度int len = GetWindowTextLengthW(_hInputEdit);if (len <= 0){return false;  // 空输入不处理}// 分配缓冲区并获取文本内容std::wstring buf((size_t)len + 1, L'\0');GetWindowTextW(_hInputEdit, &buf[0], (int)buf.size());// 转换并清理字符串auto text = Scintilla::String::TrimAll(Scintilla::String::wstring2s(&buf[0], false));if (text.empty()){return false;  // 无效内容过滤}// 清空输入区域SetWindowTextW(_hInputEdit, L"");          // 重置文本内容SendMessageW(_hInputEdit, EM_SETSEL, 0, 0); // 重置选择区域SendMessageW(_hInputEdit, EM_SCROLLCARET, 0, 0); // 滚动到起始位置// 更新界面状态appendAnswer("【问】\r\n" + text);  // 在回答区域添加问题标记SendMessageW(_hActionBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)_hStopIcon); // 切换按钮图标::EnableWindow(_hAnswerView, FALSE);  // 禁用回答区域编辑// 触发外部回调if (fnOnInputFinished != nullptr) fnOnInputFinished(text);return true;
}// 控件初始化函数
void AiAssistWnd::initControls()
{// 创建多行编辑控件_hInputEdit = ::CreateWindowExW(WS_EX_CLIENTEDGE,   // 带边框样式L"EDIT",            // 控件类名L"",                // 初始文本WS_CHILD | WS_VISIBLE | ES_MULTILINE | // 多行模式ES_AUTOVSCROLL | WS_VSCROLL,          // 滚动条支持0, 0, 0, 0,        // 初始位置尺寸(由布局管理)_hSelf,             // 父窗口句柄(HMENU)IDC_INPUT_EDIT, // 控件ID_hInst,             // 实例句柄nullptr);// 设置子类化处理SetWindowSubclass(_hInputEdit,        // 目标控件InputEditSubclassProc, // 处理函数0,                  // 子类ID(DWORD_PTR)this     // 传递类实例指针);// ... 其他控件初始化代码
}

模型调用和输出

上述处理用户输入完成后,会触发外部回调,该回调即模型调用及输出,初始化代码如下:

// 配置模型选择变更回调
g_pAiWnd->fnOnModelSelChange = [](const std::string& model) {// 更新当前平台的默认模型配置// 操作路径:全局配置对象 -> 当前平台 -> 模型名称g_pluginConf.platforms[g_pluginConf.platform].model_name = model;
};// 配置输入完成回调
g_pAiWnd->fnOnInputFinished = [](const std::string& text) {// 设置实时输出回调:将模型返回数据流式显示到界面g_pAiModel->fnAppentOutput = [](const std::string& ans) {// 转换编码格式:UTF8 -> GBK(适配本地字符集)// 参数false表示新建行,即时追加,有打字机效果g_pAiWnd->appendAnswer(Scintilla::String::UTF8ToGBK(ans.c_str(), ans.size()), false); };// 设置输出完成回调:绑定窗口类的完成处理方法// 使用bind保留窗口实例指针和参数传递能力g_pAiModel->fnOutputFinished = std::bind(&AiAssistWnd::OnOutputFinished, g_pAiWnd, std::placeholders::_1);// 在回答区域添加应答标记g_pAiWnd->appendAnswer("【答】");// 提交异步AI处理任务// 通过UI任务队列保证线程安全g_pNppImp->RunUiTask(// 绑定模型请求方法与参数std::bind(&AiModel::DirectRequest, g_pAiModel, std::placeholders::_1), text  // 用户输入文本作为请求参数);
};
用户提交输入
设置流式输出回调
触发异步AI任务
实时追加模型输出
任务完成恢复界面状态
  • 线程安全:通过g_pNppImp->RunUiTask确保UI操作在主线程执行
  • 编码转换:模型返回的UTF-8数据经UTF8ToGBK转换适配本地环境

发送和停止按钮

考虑用户发起提问后,模型就一直嗒嗒嗒地输出,或者不动了也不知道是停止了还是卡顿了,所以做了一个按钮。该按钮可以:

  • 提交用户输入
  • 停止模型调用
  • 显示当前模型后台任务状态

通过全局变量std::atomic<bool> g_bRun控制后台任务状态。

// 对话框消息处理主函数
INT_PTR AiAssistWnd::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{switch (message) {case WM_COMMAND:  // 处理控件通知消息{int wmId = LOWORD(wParam);     // 获取控件IDint wmEvent = HIWORD(wParam);  // 获取通知代码// 处理模型选择下拉框变化事件if (wmId == IDC_MODEL_COMBO && wmEvent == CBN_SELCHANGE){OnModelComboSelChange();  // 更新选中的模型配置return TRUE;              // 已处理该消息}// 处理操作按钮点击事件if (wmId == IDC_ACTION_BUTTON && wmEvent == BN_CLICKED){// 根据运行状态切换按钮功能if (g_bRun.load())  // 检查原子变量状态{g_bRun.store(false);  // 设置停止标志}else {OnInputFinished();    // 触发输入处理流程}return TRUE;}}break;}// 未处理的消息传递给基类处理return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
}// 初始化控件布局和属性
void AiAssistWnd::initControls()
{// 创建操作按钮控件_hActionBtn = ::CreateWindowExW(WS_EX_CLIENTEDGE,       // 带3D边框样式L"BUTTON",              // 按钮控件类L"",                    // 初始文本为空(使用图标)WS_CHILD | WS_VISIBLE | // 必须的窗口样式BS_ICON | BS_PUSHBUTTON,// 显示图标的按钮类型0, 0, 28, 28,           // 初始位置和尺寸(后续布局调整)_hSelf,                 // 父窗口句柄(HMENU)IDC_ACTION_BUTTON, // 控件ID_hInst,                 // 模块实例句柄nullptr);// 设置辅助功能文本(供屏幕阅读器识别)SetWindowText(_hActionBtn, _T("发送"));// 加载发送状态图标资源_hSendIcon = (HICON)LoadImageW(_hInst,                      // 资源所在模块MAKEINTRESOURCEW(IDI_ICON_SEND), // 资源IDIMAGE_ICON,                  // 资源类型为图标24, 24,                     // 请求的图标尺寸LR_DEFAULTCOLOR             // 保留原始颜色);// 加载停止状态图标资源_hStopIcon = (HICON)LoadImageW(_hInst,MAKEINTRESOURCEW(IDI_ICON_STOP),IMAGE_ICON,24, 24,LR_DEFAULTCOLOR);// 设置按钮初始图标为发送状态SendMessageW(_hActionBtn, BM_SETIMAGE,        // 设置按钮图像消息IMAGE_ICON,         // 指定图像类型为图标(LPARAM)_hSendIcon  // 传递图标句柄);
}// 处理用户输入完成事件
bool AiAssistWnd::OnInputFinished()
{// 在回答区域添加问题标识appendAnswer("【问】\r\n" + text);// 切换按钮图标为停止状态SendMessageW(_hActionBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)_hStopIcon);// 禁用回答区域编辑功能::EnableWindow(_hAnswerView, FALSE);// 触发外部输入完成回调if (fnOnInputFinished != nullptr) fnOnInputFinished(text);return true;  // 事件已处理
}// 处理模型输出完成事件
void AiAssistWnd::OnOutputFinished(const std::string& end)
{// 追加最终输出内容appendAnswer(end, false);// 重新启用回答区域编辑::EnableWindow(_hAnswerView, TRUE);// 恢复按钮图标为发送状态SendMessageW(_hActionBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)_hSendIcon);
}
  • 原子变量std::atomic<bool> g_bRun控制后台任务中断
  • 按钮多态
    • 发送状态:显示纸飞机图标,绑定输入提交逻辑
    • 停止状态:显示方块图标,触发g_bRun.store(false)
  • 界面联动:输出时禁用编辑区域,任务结束后自动恢复

效果图

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com