split/char-wchar/文件操作

本文介绍了一种使用C++进行字符串分割的方法,并提供了宽字符与窄字符互相转换的函数实现。此外,还展示了如何利用Windows API进行文件的创建、读取与写入操作。

1>分割字符串

#pragma once
#include <string>
#include <vector>
using namespace std;
//分割字符串,之间用逗号分开
void CO_Split(const wstring &src, wstring separate_character,vector<wstring>& strs)
{
 //分割字符串长度,这样就可以支持多字符串的分隔符
 int separate_characterLen = separate_character.length();
 int lastPosition = 0, index = -1;
 while (-1 != (index = src.find(separate_character, lastPosition)))
 {
  strs.push_back(src.substr(lastPosition, index - lastPosition));
  lastPosition = index + separate_characterLen;
 }
 wstring lastString = src.substr(lastPosition); 
 if (!lastString.empty())
  strs.push_back(lastString);  
}

2>  wchar->char

char* WcharToChar(const WCHAR* wcr)
{
 char* pchar=NULL;
 int len=WideCharToMultiByte(CP_ACP,0,wcr,-1,NULL,0,NULL,NULL);
 pchar=new char[len+1];
 WideCharToMultiByte(CP_ACP,0,wcr,-1,pchar,len,NULL,NULL);
 pchar[len]='\0';
 return pchar;
}
int wcharTochar(const wchar_t* src,char* dest)
{
 int size = ::WideCharToMultiByte( 936, 0, src, -1, NULL, 0, NULL, FALSE );
 if (size > 0 )
 {
  size = ::WideCharToMultiByte( 936, 0, src, -1, dest, size, NULL, FALSE );
 }
 return size;
}

3>  char->wchar

WCHAR* CharToWchar(const char* c)
{
 WCHAR* pwchar=NULL;
 int len=MultiByteToWideChar(CP_ACP,0,c,-1,NULL,0);
 pwchar=new wchar_t[len+1];
 MultiByteToWideChar(CP_ACP,0,c,-1,pwchar,len);
 pwchar[len]='\0';
 return pwchar;
}

int charTowchar(const char* src,wchar_t* dest)
{
 int size = ::MultiByteToWideChar( 936, 0, src, -1, NULL, 0);
 if (size > 0 )
 {
  size = ::MultiByteToWideChar( 936, 0, src, -1, dest, size);
 }
 return size;
}

//文件操作

//-------------------------------------------------------------------------------

//创建文件

bool CO_Create()
{	//创建文件
	bool isCreation=true;
	HANDLE hFile = CreateFileW(L"C:\\save_radio_list.txt",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	if (INVALID_HANDLE_VALUE==hFile)
	{
		isCreation=false;
		printf("创建文件失败!");
	}
	//关闭文件
	CloseHandle(hFile);
	return isCreation;
}

//读文件

CHAR* CO_Read()
{	
	HANDLE hFile = CreateFileW(L"C:\\save_radio_list.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,	FILE_ATTRIBUTE_NORMAL,NULL);
	//获取文件长度
	DWORD fileSize  = GetFileSize( hFile, NULL);
	//分配空间
	CHAR* pszBuf=new CHAR[fileSize + 1];
	memset( pszBuf, 0, fileSize + 1 );
	//设置当前读取的位置
	SetFilePointer( hFile, 0, NULL, FILE_BEGIN);
	//读取数据
	DWORD nRead = 0;
	ReadFile( hFile, pszBuf, fileSize+1, &nRead, NULL );
	CloseHandle( hFile );
	return pszBuf;
	//free( pszBuf );
	////关闭文件
	//CloseHandle( hFile );
}

//写文件

void CO_Write(CHAR* szBuff)
{	
	DWORD nWritten = 0;
	HANDLE hFile = CreateFileW(L"C:\\save_radio_list.txt",GENERIC_WRITE,0,NULL,TRUNCATE_EXISTING,	FILE_ATTRIBUTE_NORMAL,NULL);
	WriteFile( hFile, szBuff, (DWORD)strlen(szBuff),&nWritten, NULL);
	FlushFileBuffers(hFile);
	CloseHandle( hFile );
}

//main

void main()
{
	CHAR* pszBuf=NULL;
	CHAR* str="1234567890asadf";
	CO_Create();
	CO_Write(str);
	pszBuf=CO_Read();			
	printf( "result:%s\n", pszBuf );
	printf("hello");
	delete pszBuf;
	getchar();
}

#ifndef DATAPROCESSOR_H #define DATAPROCESSOR_H #include <QString> #include <QByteArray> #include <QColor> class DataProcessor { public: DataProcessor(); // ANSI序列处理 static QString processIncompleteData(const QString &newData, QString &buffer); static QString parseAnsiToRichText(const QString &input); // 数据转换 static QString byteArrayToHexString(const QByteArray &byteArray); // 文件类型判断 enum FileType { FILE_TYPE_UNKNOWN, FILE_TYPE_DIRECTORY, FILE_TYPE_EXECUTABLE }; static FileType getFileType(const QString &fileName); private: static bool checkAnsiSequenceIntegrity(const QString &text); static QColor ansiToQColor(int ansiCode); }; #endif // DATAPROCESSOR_H #ifndef HIDMANAGER_H #define HIDMANAGER_H #include <QObject> #include <QLibrary> #include <QThread> #include <QMutex> #include <QStringList> #include <QTime> #include <vector> #include <string> // 声明HID相关函数指针 typedef struct hid_device_info hid_device_info; typedef hid_device_info* (*HidEnumerateFunc)(unsigned short vendor_id, unsigned short product_id); typedef void (*HidFreeEnumerationFunc)(hid_device_info* devs); typedef void* (*HidOpenPathFunc)(const char* path); typedef void (*HidCloseFunc)(void* dev_handle); typedef int (*HidWriteFunc)(void* dev_handle, const unsigned char* data, size_t length); typedef int (*HidReadTimeoutFunc)(void* dev_handle, unsigned char* data, size_t length, int milliseconds); typedef const wchar_t* (*HidErrorFunc)(void* dev_handle); class HidWorker; class HidManager : public QObject { Q_OBJECT public: explicit HidManager(QObject *parent = nullptr); ~HidManager(); bool initHidLibrary(); QStringList enumerateHidDevices(); bool connectHidDevice(const QString &devicePath); void disconnectHidDevice(); bool isHidConnected() const; void sendData(const QString &data); signals: void deviceListChanged(const QStringList &deviceList); void dataReceived(const QByteArray &data, int bytesRead); void errorOccurred(const QString &errorMsg); void connectionStateChanged(bool isConnected); // 新增信号:用于通知设备已断开连接(只发送一次) void deviceDisconnected(const QString &errorMsg); private slots: void handleAsyncHidData(const QByteArray& data, int bytesRead); void handleHidReadError(const QString& errorMsg); void onReadLoopExited(); private: // 连接状态相关(线程安全) volatile bool m_isHidConnected; // 新增标志:跟踪设备是否已发送断开通知 volatile bool m_deviceDisconnectNotified; mutable QMutex m_connectionMutex; void setHidConnected(bool connected); // 设备枚举相关 std::vector<std::string> hidDevicePaths; QStringList hidDeviceInfos; QMutex m_enumMutex; // 保护设备路径和信息的读写 // 基础成员变量 QLibrary *hidLibrary; bool isHidLoaded; void *currentHidDevice; // 设备句柄,由HidManager统一管理 QThread *hidReadThread; bool isHidThreadRunning; QMutex m_threadMutex; // 重命名为m_threadMutex,避免与其他锁混淆 // HID函数指针 HidEnumerateFunc hidEnumerate; HidFreeEnumerationFunc hidFreeEnumeration; HidOpenPathFunc hidOpenPath; HidCloseFunc hidClose; HidWriteFunc hidWrite; HidReadTimeoutFunc hidReadTimeout; HidErrorFunc hidError; void asyncHidReadLoop(); }; class HidWorker : public QObject { Q_OBJECT public: explicit HidWorker(void* hidDev, HidReadTimeoutFunc readFunc, HidErrorFunc errorFunc, QObject* parent = nullptr); ~HidWorker(); void setHidDev(void* dev); void stopReadLoop(); void interruptRead(); public slots: void startReadLoop(); signals: void dataReceived(const QByteArray& data, int bytesRead); void readError(const QString& errorMsg); void readLoopExited(); private: void* m_hidDev; // 仅用于读取,不负责释放 HidReadTimeoutFunc m_hidReadTimeout; HidErrorFunc m_hidError; volatile bool m_isRunning; QMutex m_mutex; // 添加互斥锁保护m_isRunning }; #endif // HIDMANAGER_H #ifndef SERIALPORTMANAGER_H #define SERIALPORTMANAGER_H #include <QObject> #include <QSerialPort> #include <QTimer> #include <QStringList> class SerialPortManager : public QObject { Q_OBJECT public: explicit SerialPortManager(QObject *parent = nullptr); ~SerialPortManager(); void startPortCheckTimer(int interval = 100); void stopPortCheckTimer(); QStringList getAvailablePorts(); bool connectPort(const QString &portName, qint32 baudRate = 460800); void disconnectPort(); bool isPortConnected() const; void sendData(const QString &data); signals: void portListChanged(const QStringList &portList); void dataReceived(const QByteArray &data); void connectionStateChanged(bool isConnected); void errorOccurred(const QString &errorMsg); private slots: void checkPortChanges(); void readSerialData(); private: QSerialPort *serialPort; QTimer *portCheckTimer; QStringList lastPortNameList; bool isConnected; }; #endif // SERIALPORTMANAGER_H //#ifndef WIDGET_H //#define WIDGET_H //#include <QWidget> //#include <QSerialPort> //#include <QTimer> //#include <QEvent> //#include <QKeyEvent> //#include <QStringList> //#include "serialportmanager.h" //#include "hidmanager.h" //#include "dataprocessor.h" //namespace Ui { //class Widget; //} //class Widget : public QWidget //{ // Q_OBJECT //public: // explicit Widget(QWidget *parent = nullptr); // ~Widget(); // enum class DeviceType { // DEVICE_SERIAL, // DEVICE_HID // }; //signals: // void serialConnectionStateChanged(bool isConnected); //private slots: // void on_refresh_pb_clicked(); // void on_break_pb_clicked(); // void on_pushButton_clicked(); // // 串口相关槽函数 // void onSerialPortListChanged(const QStringList &portList); // void onSerialDataReceived(const QByteArray &data); // void onSerialConnectionStateChanged(bool isConnected); // void onSerialErrorOccurred(const QString &errorMsg); // // HID相关槽函数 // void onHidDeviceListChanged(const QStringList &deviceList); // void onHidDataReceived(const QByteArray &data, int bytesRead); // void onHidConnectionStateChanged(bool isConnected); // void onHidErrorOccurred(const QString &errorMsg); //private: // Ui::Widget *ui; // SerialPortManager *serialManager; // HidManager *hidManager; // DataProcessor *dataProcessor; // bool isSerialConnected; // bool isHidConnected; // QList<DeviceType> deviceTypes; // QStringList commandHistory; // int historyIndex; // QString currentDraft; // QString ansiBuffer; // QString hidAnsiBuffer; // void initUI(); // void initConnections(); // void getAvailableDevices(); // QString getSelectedPortName(); // void updateConnectButtonState(); // DeviceType getSelectedDeviceType(); // void logMessage(const QString &message); // void sendDataToDevice(const QString &data); // void handleHistoryNavigation(int direction); // bool eventFilter(QObject *watched, QEvent *event); //}; //#endif // WIDGET_H #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QSerialPort> #include <QTimer> #include <QEvent> #include <QKeyEvent> #include <QStringList> #include "serialportmanager.h" #include "hidmanager.h" #include "dataprocessor.h" namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget(); enum class DeviceType { DEVICE_SERIAL, DEVICE_HID }; signals: void serialConnectionStateChanged(bool isConnected); private slots: void on_refresh_pb_clicked(); void on_break_pb_clicked(); void on_pushButton_clicked(); // 串口相关槽函数 void onSerialPortListChanged(const QStringList &portList); void onSerialDataReceived(const QByteArray &data); void onSerialConnectionStateChanged(bool isConnected); void onSerialErrorOccurred(const QString &errorMsg); // HID相关槽函数 void onHidDeviceDisconnected(const QString &errorMsg); void onHidDeviceListChanged(const QStringList &deviceList); void onHidDataReceived(const QByteArray &data, int bytesRead); void onHidConnectionStateChanged(bool isConnected); void onHidErrorOccurred(const QString &errorMsg); private: Ui::Widget *ui; SerialPortManager *serialManager; HidManager *hidManager; DataProcessor *dataProcessor; bool isSerialConnected; bool isHidConnected; QList<DeviceType> deviceTypes; QStringList commandHistory; int historyIndex; QString currentDraft; QString ansiBuffer; QString hidAnsiBuffer; void initUI(); void initConnections(); void getAvailableDevices(); QString getSelectedPortName(); void updateConnectButtonState(); DeviceType getSelectedDeviceType(); void logMessage(const QString &message); void sendDataToDevice(const QString &data); void handleHistoryNavigation(int direction); bool eventFilter(QObject *watched, QEvent *event); }; #endif // WIDGET_H #include "dataprocessor.h" #include <QRegExp> #include <QTime> DataProcessor::DataProcessor() { } bool DataProcessor::checkAnsiSequenceIntegrity(const QString &text) { QStringList commands = {"ls", "pwd", "cd", "mkdir", "rm", "cp", "mv", "cat"}; int commandStart = -1; QString foundCommand; foreach (const QString &cmd, commands) { commandStart = text.indexOf(cmd); if (commandStart != -1) { foundCommand = cmd; break; } } if (commandStart == -1) { QRegExp unknownCmdRegex("\\b\\w+\\b"); if (unknownCmdRegex.indexIn(text) == -1) { return false; } foundCommand = unknownCmdRegex.cap(0); commandStart = unknownCmdRegex.pos(0); } int commandEnd = commandStart + foundCommand.length(); if (commandEnd >= text.length() || text.mid(commandEnd, 2) != "\r\n") { return false; } int endMarkerPos = text.indexOf("\r\n[LB]:-)", commandEnd); if (endMarkerPos != -1) { QString contentBetween = text.mid(commandEnd + 2, endMarkerPos - (commandEnd + 2)); if (foundCommand == "ls") { QRegExp ansiRegex("\x1B\\[([0-9;]*[mKfsu])(\\w+)"); int ansiCount = 0; int pos = 0; while ((pos = ansiRegex.indexIn(contentBetween, pos)) != -1) { ansiCount++; pos += ansiRegex.matchedLength(); } return ansiCount >= 1; } else if (foundCommand == "pwd") { return contentBetween.contains("/"); } else { return true; } } else { return (commandEnd + 2) == text.length(); } } QString DataProcessor::processIncompleteData(const QString &newData, QString &buffer) { buffer += newData; QRegExp completeAnsiRegex("\x1B\\[([0-9;]*[mKfsu])"); QRegExp incompleteAnsiRegex(".*\x1B\\[([0-9;]*)$"); if (incompleteAnsiRegex.exactMatch(buffer)) { int splitPos = buffer.lastIndexOf("\x1B["); QString processable = buffer.left(splitPos); buffer = buffer.mid(splitPos); if (!processable.isEmpty() && !checkAnsiSequenceIntegrity(processable)) { buffer = processable + buffer; return ""; } return processable; } if (!checkAnsiSequenceIntegrity(buffer)) { return ""; } QString processable = buffer; buffer.clear(); return processable; } QColor DataProcessor::ansiToQColor(int ansiCode) { switch(ansiCode) { case 30: return QColor(0, 0, 0); // 黑色 case 31: return QColor(170, 0, 0); // 红色 case 32: return QColor(0, 170, 0); // 绿色 case 33: return QColor(170, 85, 0); // 黄色 case 34: return QColor(0, 0, 170); // 蓝色 case 35: return QColor(170, 0, 170); // 洋红色 case 36: return QColor(0, 170, 170); // 青色 case 37: return QColor(170, 170, 170); // 白色 case 90: return QColor(85, 85, 85); // 亮黑(灰) case 91: return QColor(255, 85, 85); // 亮红 case 92: return QColor(85, 255, 85); // 亮绿 case 93: return QColor(255, 255, 85); // 亮黄 case 94: return QColor(85, 85, 255); // 亮蓝 case 95: return QColor(255, 85, 255); // 亮洋红 case 96: return QColor(85, 255, 255); // 亮青 case 97: return QColor(255, 255, 255); // 亮白 case 38: return QColor(114, 159, 207); // 亮蓝色 - 普通文件 case 100: return QColor(85, 85, 85); // 亮黑背景 default: return QColor(170, 170, 170); // 默认灰白色 } } DataProcessor::FileType DataProcessor::getFileType(const QString &fileName) { if (fileName == "bin" || fileName == "sbin" || fileName == "usr" || fileName == "var" || fileName == "mnt" || fileName == "proc" || fileName == "sys" || fileName == "root" || fileName == "tmp" || fileName == "lib" || fileName == "etc" || fileName == "overlay" || fileName == "rom") { return FILE_TYPE_DIRECTORY; } else if (fileName == "www") { return FILE_TYPE_EXECUTABLE; } return FILE_TYPE_UNKNOWN; } QString DataProcessor::byteArrayToHexString(const QByteArray &byteArray) { QString hexString; for (const char &c : byteArray) { hexString += QString("%1 ").arg((unsigned char)c, 2, 16, QChar('0')).toUpper(); } return hexString.trimmed(); } QString DataProcessor::parseAnsiToRichText(const QString &input) { QString html; QString currentStyle; QRegExp ansiRegex("\x1B\\[([0-9;]*)([mKfsu])"); QRegExp fileNameRegex("(\x1B\\[[0-9;]*m)(\\w+)"); html += "<div style='font-family: Consolas, monospace; white-space: pre; padding: 8px; background-color: #fff; color: #000;'>"; int pos = 0; int lastPos = 0; while ((pos = ansiRegex.indexIn(input, pos)) != -1) { if (pos > lastPos) { QString text = input.mid(lastPos, pos - lastPos); text.replace("&", "&").replace("<", "<").replace(">", ">"); if (!currentStyle.isEmpty()) { html += QString("<span style=\"%1\">%2</span>").arg(currentStyle, text); } else { html += text; } } QString codeStr = ansiRegex.cap(1); QString command = ansiRegex.cap(2); if (command == "m") { QStringList codes = codeStr.split(';', QString::SkipEmptyParts); if (codes.isEmpty() || codes.contains("0")) { currentStyle.clear(); } else { foreach (QString code, codes) { bool ok; int codeNum = code.toInt(&ok); if (!ok) continue; switch (codeNum) { case 1: currentStyle += "font-weight: bold; "; break; case 4: currentStyle += "text-decoration: underline; "; break; case 22: currentStyle.remove("font-weight: bold; "); break; case 24: currentStyle.remove("text-decoration: underline; "); break; default: if (codeNum >= 30 && codeNum <= 37) { QColor color = ansiToQColor(codeNum); currentStyle += QString("color: rgb(%1,%2,%3); ") .arg(color.red()).arg(color.green()).arg(color.blue()); } else if (codeNum >= 90 && codeNum <= 97) { QColor color = ansiToQColor(codeNum); currentStyle += QString("color: rgb(%1,%2,%3); ") .arg(color.red()).arg(color.green()).arg(color.blue()); } else if (codeNum >= 40 && codeNum <= 47) { QColor color = ansiToQColor(codeNum - 10); currentStyle += QString("background-color: rgb(%1,%2,%3); ") .arg(color.red()).arg(color.green()).arg(color.blue()); } else if (codeNum >= 100 && codeNum <= 107) { QColor color = ansiToQColor(codeNum - 70); currentStyle += QString("background-color: rgb(%1,%2,%3); ") .arg(color.red()).arg(color.green()).arg(color.blue()); } break; } } } } else if (command == "K") { html += "<br>"; } pos += ansiRegex.matchedLength(); lastPos = pos; } if (lastPos < input.length()) { QString text = input.mid(lastPos); text.replace("&", "&").replace("<", "<").replace(">", ">"); int filePos = 0; while ((filePos = fileNameRegex.indexIn(text, filePos)) != -1) { QString ansiCode = fileNameRegex.cap(1); QString fileName = fileNameRegex.cap(2); FileType type = getFileType(fileName); QString fileStyle = currentStyle; if (type == FILE_TYPE_DIRECTORY) { fileStyle += "color: rgb(85, 85, 255); "; } else if (type == FILE_TYPE_EXECUTABLE) { fileStyle += "color: rgb(85, 255, 85); font-weight: bold; "; } html += QString("<span style=\"%1\">%2</span>").arg(fileStyle, fileName); filePos += fileNameRegex.matchedLength(); } if (!currentStyle.isEmpty() && filePos == 0) { html += QString("<span style=\"%1\">%2</span>").arg(currentStyle, text); } else if (filePos < text.length()) { html += text.mid(filePos); } } html += "</div>"; return html; } #include "hidmanager.h" #include <QDebug> #include "hidapi.h" // ------------------------------ HidManager 实现 ------------------------------ void HidManager::setHidConnected(bool connected) { QMutexLocker locker(&m_connectionMutex); if (m_isHidConnected != connected) { m_isHidConnected = connected; // 连接状态改变时重置断开通知标志 if (connected) { m_deviceDisconnectNotified = false; } emit connectionStateChanged(connected); } } bool HidManager::isHidConnected() const { QMutexLocker locker(&m_connectionMutex); return m_isHidConnected; } HidManager::HidManager(QObject *parent) : QObject(parent), m_isHidConnected(false), m_deviceDisconnectNotified(false),isHidLoaded(false), currentHidDevice(nullptr), hidReadThread(nullptr), isHidThreadRunning(false) { } HidManager::~HidManager() { disconnectHidDevice(); if (hidLibrary) { hidLibrary->unload(); delete hidLibrary; hidLibrary = nullptr; } } bool HidManager::initHidLibrary() { // 检查是否已加载,避免重复初始化 if (isHidLoaded) { emit errorOccurred("HID库已加载,无需重复初始化"); return true; } hidLibrary = new QLibrary("hidapi.dll"); if (!hidLibrary->load()) { QString err = QString("HID库加载失败:%1").arg(hidLibrary->errorString()); emit errorOccurred(err); delete hidLibrary; hidLibrary = nullptr; return false; } // 解析函数指针 hidEnumerate = (HidEnumerateFunc)hidLibrary->resolve("hid_enumerate"); hidFreeEnumeration = (HidFreeEnumerationFunc)hidLibrary->resolve("hid_free_enumeration"); hidOpenPath = (HidOpenPathFunc)hidLibrary->resolve("hid_open_path"); hidClose = (HidCloseFunc)hidLibrary->resolve("hid_close"); hidWrite = (HidWriteFunc)hidLibrary->resolve("hid_write"); hidReadTimeout = (HidReadTimeoutFunc)hidLibrary->resolve("hid_read_timeout"); hidError = (HidErrorFunc)hidLibrary->resolve("hid_error"); if (!hidEnumerate || !hidFreeEnumeration || !hidOpenPath || !hidClose || !hidWrite || !hidReadTimeout || !hidError) { emit errorOccurred("HID库函数解析失败,部分函数指针为空"); hidLibrary->unload(); delete hidLibrary; hidLibrary = nullptr; return false; } isHidLoaded = true; emit errorOccurred("HID库初始化成功"); return true; } QStringList HidManager::enumerateHidDevices() { if (!isHidLoaded) { emit errorOccurred("HID库未加载,无法枚举设备"); return QStringList(); } QMutexLocker enumLocker(&m_enumMutex); hidDevicePaths.clear(); hidDeviceInfos.clear(); // 添加空指针检查 if (!hidEnumerate) { emit errorOccurred("hidEnumerate函数指针为空,无法枚举设备"); return QStringList(); } hid_device_info *devs = hidEnumerate(0x0, 0x0); if (!devs) { emit errorOccurred("HID设备枚举失败,未获取到设备列表"); return QStringList(); } hid_device_info *cur_dev = devs; QStringList deviceList; int count = 0; while (cur_dev) { // 增加对设备信息的有效性检查 if (!cur_dev) break; if (cur_dev->path == nullptr) { cur_dev = cur_dev->next; continue; } // 处理可能的空指针 const wchar_t* productStr = cur_dev->product_string ? cur_dev->product_string : L"未知设备"; const wchar_t* manufacturerStr = cur_dev->manufacturer_string ? cur_dev->manufacturer_string : L"未知厂商"; // 使用更安全的字符串处理 QString productInfo = QString::fromWCharArray(productStr); QString manufacturerInfo = QString::fromWCharArray(manufacturerStr); QString info = QString("[HID] VID:0x%1, PID:0x%2, 厂商:%3, 产品:%4") .arg(cur_dev->vendor_id, 4, 16, QChar('0')) .arg(cur_dev->product_id, 4, 16, QChar('0')) .arg(manufacturerInfo) .arg(productInfo); // 检查路径有效性 std::string devPathStr(cur_dev->path); if (devPathStr.empty()) { cur_dev = cur_dev->next; continue; } hidDevicePaths.push_back(devPathStr); hidDeviceInfos.append(info); deviceList.append(info); cur_dev = cur_dev->next; count++; } // 确保释放资源 hidFreeEnumeration(devs); // 无论如何都释放资源 if (count == 0) { emit errorOccurred("未发现HID设备"); } else { emit errorOccurred(QString("发现%1个HID设备,枚举完成").arg(count)); } return deviceList; } bool HidManager::connectHidDevice(const QString &devicePath) { if (!isHidLoaded) { emit errorOccurred("HID连接失败:hidapi库未加载"); return false; } QMutexLocker enumLocker(&m_enumMutex); if (isHidConnected()) { disconnectHidDevice(); QThread::msleep(100); } int index = -1; for (int i = 0; i < hidDeviceInfos.size(); i++) { if (hidDeviceInfos[i] == devicePath) { index = i; break; } } if (index < 0 || static_cast<size_t>(index) >= hidDevicePaths.size()) { emit errorOccurred(QString("HID连接失败:无效的设备路径[%1]").arg(devicePath)); return false; } const char* devPath = hidDevicePaths[index].c_str(); currentHidDevice = hidOpenPath(devPath); if (!currentHidDevice) { emit errorOccurred(QString("HID设备打开失败:路径[%1]").arg(QString::fromUtf8(devPath))); setHidConnected(false); return false; } setHidConnected(true); emit errorOccurred(QString("HID设备连接成功:%1").arg(devicePath)); asyncHidReadLoop(); return true; } void HidManager::disconnectHidDevice() { QMutexLocker threadLocker(&m_threadMutex); if (!isHidConnected() || !currentHidDevice) { emit errorOccurred("HID设备未连接或句柄已无效,无需断开"); return; } if (isHidThreadRunning && hidReadThread && hidReadThread->isRunning()) { HidWorker* worker = hidReadThread->findChild<HidWorker*>(); if (worker) { worker->stopReadLoop(); bool isExited = hidReadThread->wait(1000);//3000 if (!isExited) { qWarning() << "HID线程超时未退出,强制终止"; hidReadThread->terminate(); hidReadThread->wait(500);//1000 } disconnect(worker, nullptr, this, nullptr); } hidReadThread = nullptr; isHidThreadRunning = false; } if (currentHidDevice) { hidClose(currentHidDevice); currentHidDevice = nullptr; } setHidConnected(false); emit errorOccurred("HID设备断开流程完成"); } void HidManager::sendData(const QString &data) { if (!isHidConnected()) { emit errorOccurred("HID发送失败:未连接HID设备"); return; } if (!isHidLoaded || !currentHidDevice) { setHidConnected(false); emit errorOccurred("HID发送失败:库未加载或设备句柄无效"); return; } QString trimmedData = data.trimmed(); if (trimmedData.isEmpty()) { emit errorOccurred("HID发送失败:输入数据为空(已过滤空白字符)"); return; } QByteArray sendData = trimmedData.toUtf8(); if (sendData.isEmpty()) { emit errorOccurred("HID发送失败:数据转换为UTF-8后为空(无效字符)"); return; } QByteArray reportData; reportData.append((char)0x00); // 报告ID int maxDataLen = 64 - reportData.size(); if (sendData.size() > maxDataLen) { sendData = sendData.left(maxDataLen); emit errorOccurred(QString("HID发送数据超长,已截断至%1字节").arg(maxDataLen)); } reportData.append(sendData); int result = hidWrite(currentHidDevice, (const unsigned char*)reportData.data(), reportData.size()); if (result == -1) { QString errMsg = QString("HID发送失败:%1").arg(QString::fromWCharArray(hidError(currentHidDevice))); emit errorOccurred(errMsg); if (errMsg.contains("句柄无效") || errMsg.contains("设备没有连接", Qt::CaseInsensitive)) { disconnectHidDevice(); } } else { emit errorOccurred(QString("HID发送成功:%1字节").arg(result)); } } void HidManager::handleAsyncHidData(const QByteArray& data, int bytesRead) { emit dataReceived(data, bytesRead); } void HidManager::handleHidReadError(const QString& errorMsg) { QMutexLocker locker(&m_connectionMutex); // 检查是否是设备断开类错误 bool isDisconnectError = errorMsg.contains("句柄无效") || errorMsg.contains("设备未连接", Qt::CaseInsensitive) || errorMsg.contains("设备没有连接", Qt::CaseInsensitive) || errorMsg.contains("操作超时", Qt::CaseInsensitive); // 如果是设备断开错误且尚未通知,则只发送一次 if (isDisconnectError) { if (!m_deviceDisconnectNotified) { m_deviceDisconnectNotified = true; emit deviceDisconnected(errorMsg); // 发送专门的断开通知 emit errorOccurred("HID 读取错误:" + errorMsg); // 断开连接 locker.unlock(); // 解锁以避免死锁 disconnectHidDevice(); emit connectionStateChanged(false); } } else { // 其他错误正常处理 static QString lastError; static QTime lastErrorTime; if (errorMsg == lastError && lastErrorTime.elapsed() < 1000) { return; } lastError = errorMsg; lastErrorTime.start(); emit errorOccurred("HID 读取错误:" + errorMsg); } } void HidManager::onReadLoopExited() { QMutexLocker threadLocker(&m_threadMutex); isHidThreadRunning = false; emit errorOccurred("HID读取循环已退出"); } void HidManager::asyncHidReadLoop() { QMutexLocker threadLocker(&m_threadMutex); if (isHidThreadRunning && hidReadThread) { HidWorker* worker = hidReadThread->findChild<HidWorker*>(); if (worker) { worker->stopReadLoop(); hidReadThread->wait(1000); } delete hidReadThread; hidReadThread = nullptr; } hidReadThread = new QThread(); HidWorker* worker = new HidWorker(currentHidDevice, hidReadTimeout, hidError); worker->moveToThread(hidReadThread); connect(worker, &HidWorker::dataReceived, this, &HidManager::handleAsyncHidData); connect(worker, &HidWorker::readError, this, &HidManager::handleHidReadError); connect(worker, &HidWorker::readLoopExited, this, &HidManager::onReadLoopExited); connect(worker, &HidWorker::readLoopExited, worker, &HidWorker::deleteLater); connect(worker, &HidWorker::readLoopExited, hidReadThread, &QThread::quit); connect(hidReadThread, &QThread::finished, hidReadThread, &QThread::deleteLater); // 连接启动信号 connect(hidReadThread, &QThread::started, worker, &HidWorker::startReadLoop); isHidThreadRunning = true; hidReadThread->start(); } // ------------------------------ HidWorker 实现 ------------------------------ HidWorker::HidWorker(void* hidDev, HidReadTimeoutFunc readFunc, HidErrorFunc errorFunc, QObject* parent) : QObject(parent), m_hidDev(hidDev), m_hidReadTimeout(readFunc), m_hidError(errorFunc), m_isRunning(false) { } HidWorker::~HidWorker() { stopReadLoop(); } void HidWorker::setHidDev(void* dev) { QMutexLocker locker(&m_mutex); m_hidDev = dev; } void HidWorker::stopReadLoop() { QMutexLocker locker(&m_mutex); m_isRunning = false; } void HidWorker::interruptRead() { // 如果需要中断阻塞的read操作,可以在这里实现 } void HidWorker::startReadLoop() { QMutexLocker locker(&m_mutex); m_isRunning = true; locker.unlock(); // 释放锁,允许其他操作修改m_isRunning unsigned char buffer[64]; // HID通常使用64字节的缓冲区 while (true) { // 检查是否需要退出循环 locker.relock(); bool running = m_isRunning; locker.unlock(); if (!running) { break; } // 检查设备句柄是否有效 locker.relock(); void* hidDev = m_hidDev; locker.unlock(); if (!hidDev) { emit readError("设备句柄无效"); break; } // 读取数据,超时时间设为100ms,以便定期检查退出标志 int bytesRead = m_hidReadTimeout(hidDev, buffer, sizeof(buffer), 100); if (bytesRead > 0) { // 读取到数据,发送信号 emit dataReceived(QByteArray((char*)buffer, bytesRead), bytesRead); } else if (bytesRead < 0) { // 发生错误 QString errorMsg = QString::fromWCharArray(m_hidError(hidDev)); emit readError(errorMsg); // 如果是致命错误,退出循环 if (errorMsg.contains("句柄无效") || errorMsg.contains("设备未连接") || errorMsg.contains("设备没有连接")) { break; } } // bytesRead == 0 表示超时,继续循环 } emit readLoopExited(); } #include "serialportmanager.h" #include <QSerialPortInfo> #include <QDebug> SerialPortManager::SerialPortManager(QObject *parent) : QObject(parent), isConnected(false) { serialPort = new QSerialPort(this); portCheckTimer = new QTimer(this); connect(portCheckTimer, &QTimer::timeout, this, &SerialPortManager::checkPortChanges); connect(serialPort, &QSerialPort::readyRead, this, &SerialPortManager::readSerialData); } SerialPortManager::~SerialPortManager() { if (serialPort->isOpen()) { serialPort->close(); } } void SerialPortManager::startPortCheckTimer(int interval) { portCheckTimer->setInterval(interval); portCheckTimer->start(); } void SerialPortManager::stopPortCheckTimer() { portCheckTimer->stop(); } QStringList SerialPortManager::getAvailablePorts() { QStringList portList; foreach (const QSerialPortInfo &portInfo, QSerialPortInfo::availablePorts()) { portList << portInfo.portName(); } return portList; } bool SerialPortManager::connectPort(const QString &portName, qint32 baudRate) { if (serialPort->isOpen()) { serialPort->close(); } serialPort->setPortName(portName); serialPort->setBaudRate(baudRate); serialPort->setDataBits(QSerialPort::Data8); serialPort->setParity(QSerialPort::NoParity); serialPort->setStopBits(QSerialPort::OneStop); serialPort->setFlowControl(QSerialPort::NoFlowControl); if (!serialPort->open(QIODevice::ReadWrite)) { emit errorOccurred(serialPort->errorString()); return false; } isConnected = true; emit connectionStateChanged(true); return true; } void SerialPortManager::disconnectPort() { if (serialPort->isOpen()) { serialPort->close(); } isConnected = false; emit connectionStateChanged(false); } bool SerialPortManager::isPortConnected() const { return isConnected; } void SerialPortManager::sendData(const QString &data) { if (!isConnected || !serialPort->isOpen()) { emit errorOccurred("Serial port not connected"); return; } QString sendData = data.trimmed() + "\r\n"; QByteArray sendBytes = sendData.toUtf8(); qint64 sendLen = serialPort->write(sendBytes); if (sendLen == -1) { emit errorOccurred(serialPort->errorString()); } } void SerialPortManager::checkPortChanges() { QStringList currentPortList = getAvailablePorts(); if (currentPortList != lastPortNameList) { lastPortNameList = currentPortList; emit portListChanged(currentPortList); } } void SerialPortManager::readSerialData() { if (!serialPort->isOpen()) return; QByteArray recvBytes = serialPort->readAll(); if (!recvBytes.isEmpty()) { emit dataReceived(recvBytes); } } #include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QTextCursor> #include <QDateTime> #include <QRegExp> #include <QFont> #include <QMessageBox> #include <QSerialPortInfo> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) , isSerialConnected(false) , isHidConnected(false) , historyIndex(-1) { ui->setupUi(this); serialManager = new SerialPortManager(this); hidManager = new HidManager(this); dataProcessor = new DataProcessor(); initUI(); initConnections(); // 初始化HID库 bool isHidLoaded = hidManager->initHidLibrary(); if (isHidLoaded) { logMessage("HID初始化成功:支持HID设备读写"); } else { logMessage("HID初始化失败:请确保hidapi.dll在程序目录"); } // 获取可用设备 getAvailableDevices(); // 优先选中COM3 bool com3Exists = false; int com3Index = -1; for (int i = 0; i < ui->number_cm->count(); ++i) { QString portText = ui->number_cm->itemText(i); if (portText.contains("USB 串行设备", Qt::CaseInsensitive) ) { com3Exists = true; com3Index = i; break; } } if (com3Exists) { //logMessage("检测到USB串行,自动选中"); //ui->number_cm->setCurrentIndex(com3Index); } else { logMessage("未检测到USB串行(COM3),等待设备插入"); } // 启动串口检查定时器 serialManager->startPortCheckTimer(100); } Widget::~Widget() { delete ui; delete serialManager; delete hidManager; delete dataProcessor; } void Widget::initUI() { setWindowTitle("串口+HID"); setWindowIcon(QIcon(":/images/HID.ico")); // 初始化输入区事件过滤器 ui->te_instruct->installEventFilter(this); // 初始化接收区样式 ui->recv_textEdit->setLineWrapMode(QTextEdit::WidgetWidth); ui->recv_textEdit->setFont(QFont("Consolas", 10)); ui->recv_textEdit->setStyleSheet("background-color: #f0f0f0; color: #333;"); ui->recv_textEdit->setAcceptRichText(true); } void Widget::initConnections() { // 串口信号连接 connect(serialManager, &SerialPortManager::portListChanged, this, &Widget::onSerialPortListChanged); connect(serialManager, &SerialPortManager::dataReceived, this, &Widget::onSerialDataReceived); connect(serialManager, &SerialPortManager::connectionStateChanged, this, &Widget::onSerialConnectionStateChanged); connect(serialManager, &SerialPortManager::errorOccurred, this, &Widget::onSerialErrorOccurred); // HID信号连接 connect(hidManager, &HidManager::deviceListChanged, this, &Widget::onHidDeviceListChanged); connect(hidManager, &HidManager::dataReceived, this, &Widget::onHidDataReceived); connect(hidManager, &HidManager::connectionStateChanged, this, &Widget::onHidConnectionStateChanged); connect(hidManager, &HidManager::errorOccurred, this, &Widget::onHidErrorOccurred); // 连接HID设备断开信号 connect(hidManager, &HidManager::deviceDisconnected, this, &Widget::onHidDeviceDisconnected); // // 可选:处理专门的断开通知 // connect(hidManager, &HidManager::deviceDisconnected, this, [this](const QString &errorMsg) { // QMessageBox::warning(this, "设备断开", "HID设备已断开连接:" + errorMsg); // }); } // 修改Widget::getAvailableDevices函数,添加异常捕获 void Widget::getAvailableDevices() { try { QString prevSelectedText = ui->number_cm->currentText(); ui->number_cm->clear(); deviceTypes.clear(); // 添加所有串口设备 QStringList serialPorts = serialManager->getAvailablePorts(); foreach (const QString &portName, serialPorts) { QSerialPortInfo portInfo(portName); QStringList displayParts; displayParts << portName; if (!portInfo.description().isEmpty()) displayParts << portInfo.description(); if (!portInfo.manufacturer().isEmpty()) displayParts << portInfo.manufacturer(); QString displayText = "[串口] " + displayParts.join(" - "); ui->number_cm->addItem(displayText); deviceTypes.append(DeviceType::DEVICE_SERIAL); } // 添加所有HID设备 QStringList hidDevices = hidManager->enumerateHidDevices(); foreach (const QString &deviceInfo, hidDevices) { // 检查设备信息有效性 if (!deviceInfo.isEmpty()) { ui->number_cm->addItem(deviceInfo); deviceTypes.append(DeviceType::DEVICE_HID); } } // 恢复之前的选中状态 int prevIndex = ui->number_cm->findText(prevSelectedText); if (prevIndex != -1) { ui->number_cm->setCurrentIndex(prevIndex); } } catch (...) { logMessage("获取设备列表时发生未知错误"); } } QString Widget::getSelectedPortName() { if (ui->number_cm->currentIndex() == -1) return ""; QString selectedText = ui->number_cm->currentText(); if (selectedText.startsWith("[串口] ")) { QString portPart = selectedText.mid(5); int separatorPos = portPart.indexOf(" - "); return separatorPos != -1 ? portPart.left(separatorPos) : portPart; } return ""; } // 修改updateConnectButtonState方法 void Widget::updateConnectButtonState() { if (ui->number_cm->count() == 0) { ui->break_pb->setText("无可用设备"); ui->break_pb->setEnabled(false); return; } DeviceType currentType = getSelectedDeviceType(); bool isConnected = (currentType == DeviceType::DEVICE_SERIAL) ? isSerialConnected : isHidConnected; // 统一按钮文本:未连接时显示"连接",连接后显示"断开" ui->break_pb->setText(isConnected ? "断开" : "连接"); ui->break_pb->setEnabled(true); } Widget::DeviceType Widget::getSelectedDeviceType() { int index = ui->number_cm->currentIndex(); if (index >= 0 && index < deviceTypes.size()) { return deviceTypes[index]; } return DeviceType::DEVICE_SERIAL; } void Widget::logMessage(const QString &message) { if (ui->recv_textEdit) { QString timeStamp = QTime::currentTime().toString("HH:mm:ss"); ui->recv_textEdit->append(QString("[%1] [日志] %2").arg(timeStamp, message)); ui->recv_textEdit->moveCursor(QTextCursor::End); } qDebug() << message; } void Widget::sendDataToDevice(const QString &data) { DeviceType currentType = getSelectedDeviceType(); if (currentType == DeviceType::DEVICE_SERIAL) { if (!isSerialConnected) { logMessage("串口发送失败:未连接串口"); QMessageBox::warning(this, "发送失败", "请先连接串口再发送数据"); return; } QString sendData = data.trimmed(); if (sendData.isEmpty()) { logMessage("发送失败:内容为空"); return; } if (commandHistory.isEmpty() || commandHistory.last() != sendData) { commandHistory.append(sendData); if (commandHistory.size() > 100) commandHistory.removeFirst(); } historyIndex = -1; serialManager->sendData(data); ui->recv_textEdit->append(QString(" 串口发送: %1").arg(data)); ui->recv_textEdit->moveCursor(QTextCursor::End); } else { hidManager->sendData(data); QString timeStamp = QTime::currentTime().toString("HH:mm:ss.zzz"); QString html = "<div style='margin:8px 0;'>"; html += "<hr style='border:1px dashed #CCCCCC; margin:5px 0;'>"; html += QString("<p style='margin:5px 0;'><span style='color:#0000CD;'>[%1] HID发送: %2</span></p>") .arg(timeStamp, data); html += "<div style='margin:5px 0;'></div>"; html += "</div>"; QTextCursor cursor(ui->recv_textEdit->textCursor()); cursor.movePosition(QTextCursor::End); cursor.insertHtml(html); ui->recv_textEdit->moveCursor(QTextCursor::End); } } void Widget::handleHistoryNavigation(int direction) { if (commandHistory.isEmpty()) return; if (historyIndex == -1) { currentDraft = ui->te_instruct->toPlainText(); } if (direction == 1) { // 上方向键 if (historyIndex + 1 < commandHistory.size()) { historyIndex++; } } else { // 下方向键 if (historyIndex > 0) { historyIndex--; } else if (historyIndex == 0) { historyIndex = -1; ui->te_instruct->setPlainText(currentDraft); return; } } if (historyIndex != -1) { int displayIndex = commandHistory.size() - 1 - historyIndex; ui->te_instruct->setPlainText(commandHistory[displayIndex]); } QTextCursor cursor = ui->te_instruct->textCursor(); cursor.movePosition(QTextCursor::End); ui->te_instruct->setTextCursor(cursor); } bool Widget::eventFilter(QObject *watched, QEvent *event) { if (watched == ui->te_instruct && event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { QString inputText = ui->te_instruct->toPlainText(); sendDataToDevice(inputText); ui->te_instruct->clear(); return true; } else if (keyEvent->key() == Qt::Key_Up) { handleHistoryNavigation(1); return true; } else if (keyEvent->key() == Qt::Key_Down) { handleHistoryNavigation(-1); return true; } } return QWidget::eventFilter(watched, event); } void Widget::on_refresh_pb_clicked() { if (isSerialConnected) { QString closedPort = getSelectedPortName(); serialManager->disconnectPort(); logMessage(QString("刷新操作:已断开串口 %1 的连接").arg(closedPort)); } if (isHidConnected) { hidManager->disconnectHidDevice(); } getAvailableDevices(); updateConnectButtonState(); } void Widget::on_break_pb_clicked() { if (ui->number_cm->count() == 0) { QMessageBox::warning(this, "操作提示", "当前无可用设备,请检查设备连接!"); return; } DeviceType currentType = getSelectedDeviceType(); bool isCurrentlyConnected = (currentType == DeviceType::DEVICE_SERIAL) ? isSerialConnected : isHidConnected; if (currentType == DeviceType::DEVICE_SERIAL) { if (isCurrentlyConnected) { QString closedPort = getSelectedPortName(); serialManager->disconnectPort(); } else { QString targetPort = getSelectedPortName(); if (!targetPort.isEmpty()) { serialManager->connectPort(targetPort, 460800); } else { logMessage("连接失败:未选中任何串口"); QMessageBox::warning(this, "连接失败", "请先从下拉列表中选中一个串口!"); } } } else { if (isCurrentlyConnected) { hidManager->disconnectHidDevice(); } else { QString currentText = ui->number_cm->currentText(); hidManager->connectHidDevice(currentText); } } ansiBuffer.clear(); hidAnsiBuffer.clear(); bool isFinalConnected = (currentType == DeviceType::DEVICE_SERIAL) ? isSerialConnected : isHidConnected; ui->number_cm->setEnabled(!isFinalConnected); ui->number_cm->setStyleSheet(isFinalConnected ? "color: #888; background-color: #f5f5f5;" : ""); updateConnectButtonState(); } void Widget::on_pushButton_clicked() { ui->recv_textEdit->clear(); logMessage("接收区已清空"); } void Widget::onSerialPortListChanged(const QStringList &portList) { Q_UNUSED(portList); getAvailableDevices(); updateConnectButtonState(); } void Widget::onSerialDataReceived(const QByteArray &data) { QString rawText = QString::fromUtf8(data); QString processableText = dataProcessor->processIncompleteData(rawText, ansiBuffer); if (processableText.isEmpty()) { return; } QString richText = dataProcessor->parseAnsiToRichText(processableText); ui->recv_textEdit->setAcceptRichText(true); QString html = QString("<p><br></p>%1<hr>").arg(richText); QTextCursor cursor(ui->recv_textEdit->textCursor()); cursor.movePosition(QTextCursor::End); cursor.insertHtml(html); ui->recv_textEdit->moveCursor(QTextCursor::End); } void Widget::onSerialConnectionStateChanged(bool isConnected) { isSerialConnected = isConnected; updateConnectButtonState(); // 更新ComboBox状态 ui->number_cm->setEnabled(!isConnected); ui->number_cm->setStyleSheet(isConnected ? "color: #888; background-color: #f5f5f5;" : ""); if (isConnected) { logMessage(QString("成功连接串口 %1(波特率:460800)").arg(getSelectedPortName())); } else { logMessage(QString("已断开串口 %1 的连接").arg(getSelectedPortName())); // 刷新设备列表,确保显示最新状态 getAvailableDevices(); } } void Widget::onSerialErrorOccurred(const QString &errorMsg) { logMessage(QString("串口错误:%1").arg(errorMsg)); } // 修改Widget::onHidDeviceListChanged函数 void Widget::onHidDeviceListChanged(const QStringList &deviceList) { qDebug() << "onHidDeviceListChanged called"; // 添加调试日志 // 确保在主线程处理UI更新 if (QThread::currentThread() != this->thread()) { QMetaObject::invokeMethod(this, "onHidDeviceListChanged", Qt::QueuedConnection, Q_ARG(QStringList, deviceList)); return; } // 保存当前选中项 QString currentSelection = ui->number_cm->currentText(); bool wasConnected = isHidConnected; // 重新加载设备列表 getAvailableDevices(); // 尝试恢复之前的选择 int index = ui->number_cm->findText(currentSelection); if (index >= 0) { ui->number_cm->setCurrentIndex(index); } updateConnectButtonState(); } void Widget::onHidDataReceived(const QByteArray &data, int bytesRead) { qDebug() << "原始HID数据 [" << bytesRead << "字节]: " << data.toHex(); QString timeStamp = QTime::currentTime().toString("HH:mm:ss.zzz"); QString html = "<div style='margin:8px 0; color: white; background-color: #333;'>"; html += QString("<p style='margin:5px 0;'><span style='color:#228B22;'>[%1] HID接收(%2字节): %3</span></p>") .arg(timeStamp) .arg(bytesRead) .arg(dataProcessor->byteArrayToHexString(data)); html += "</div>"; QTextCursor cursor(ui->recv_textEdit->textCursor()); cursor.movePosition(QTextCursor::End); cursor.insertHtml(html); ui->recv_textEdit->moveCursor(QTextCursor::End); } // 修改HID连接状态变化处理函数 void Widget::onHidConnectionStateChanged(bool connected) { isHidConnected = connected; // 更新连接状态 updateConnectButtonState(); // 调用统一的按钮状态更新方法 if (connected) { logMessage("HID设备连接成功"); } else { logMessage("HID设备已断开连接"); } } void Widget::onHidErrorOccurred(const QString &errorMsg) { logMessage(errorMsg); } void Widget::onHidDeviceDisconnected(const QString &errorMsg) { logMessage("HID设备已断开: " + errorMsg); // 更新连接状态 isHidConnected = false; // 刷新设备列表 getAvailableDevices(); // 更新按钮状态 updateConnectButtonState(); // 重新启用ComboBox ui->number_cm->setEnabled(true); ui->number_cm->setStyleSheet(""); } 上面是我程序代码qt有很多问题请你修复下
最新发布
09-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值