如何在C++Builder中从Firebird表字符串字段设置TComPort枚举属性
解决Winsoft TComPort枚举属性与字符串的转换问题
问题场景
使用Winsoft的TComPort组件时,将其枚举类型属性(如TBaudRate、TDataBits等)以字符串形式存储到Firebird数据库后,无法直接将读取到的字符串转换回对应的枚举类型,常规的强制转换方式(static_cast、reinterpret_cast)均无效。
现有代码
// 存储属性 IBSQL1->SQL->Clear(); IBSQL1->SQL->Add("Update or insert into FBTable1 (IdTable, DeviceName, BaudRate, DataBits, StopBits, Parity, FlowControlDTR, FlowControlRTS, FlowControlXOnXOff, FlowControlXOffLimit, FlowControlXOnLimit)"); IBSQL1->SQL->Add("values (:IdTable, :DeviceName, :BaudRate, :DataBits, :StopBits, :Parity, :FlowControlDTR, :FlowControlRTS, :FlowControlXOnXOff, :FlowControlXOffLimit, :FlowControlXOnLimit) matching (IdTable)"); IBSQL1->ParamByName("IdTable")->Value = ClientDataSet1->FieldByName("IdTable")->AsInteger; IBSQL1->ParamByName("DeviceName")->Value = ClientDataSet1->FieldByName("DeviceName")->AsString; IBSQL1->ParamByName("BaudRate")->Value = ClientDataSet1->FieldByName("BaudRate")->AsString; IBSQL1->ParamByName("DataBits")->Value = ClientDataSet1->FieldByName("DataBits")->AsString; IBSQL1->ParamByName("StopBits")->Value = ClientDataSet1->FieldByName("StopBits")->AsString; IBSQL1->ParamByName("Parity")->Value = ClientDataSet1->FieldByName("Parity")->AsString; IBSQL1->ParamByName("FlowControlDTR")->Value = ClientDataSet1->FieldByName("FlowControlDTR")->AsString; IBSQL1->ParamByName("FlowControlRTS")->Value = ClientDataSet1->FieldByName("FlowControlRTS")->AsString; IBSQL1->ParamByName("FlowControlXOnXOff")->Value = ClientDataSet1->FieldByName("FlowControlXOnXOff")->AsString; IBSQL1->ParamByName("FlowControlXOffLimit")->Value = ClientDataSet1->FieldByName("FlowControlXOffLimit")->AsInteger; IBSQL1->ParamByName("FlowControlXOnLimit")->Value = ClientDataSet1->FieldByName("FlowControlXOnLimit")->AsInteger; IBSQL1->ExecQuery(); IBSQL1->Close(); // 设置属性 IBSQL1->SQL->Clear(); IBSQL1->SQL->Add("Select DeviceName, BaudRate, DataBits, StopBits, Parity, FlowControlDTR, FlowControlRTS, FlowControlXOnXOff, FlowControlXOffLimit, FlowControlXOnLimit from FBTable1"); IBSQL1->SQL->Add("Where IdTable = 1"); IBSQL1->ExecQuery(); IBSQL1->Close(); ComPort1->DeviceName = IBSQL1->FieldByName("DeviceName")->AsString; // 正常运行 ComPort1->BaudRate = static_cast<TBaudRate *>(IBSQL1->FieldByName("BaudRate")->AsString); // 编译失败:无法将UnicodeString转换为TBaudRate* ComPort1->DataBits = static_cast<TDataBits *>(IBSQL1->FieldByName("DataBits")->AsString); // 编译失败:无法将UnicodeString转换为TDataBits* ComPort1->StopBits = static_cast<TStopBits *>(IBSQL1->FieldByName("StopBits")->AsString); // 编译失败:无法将UnicodeString转换为TStopBits* ComPort1->Parity = static_cast<TParity *>(IBSQL1->FieldByName("Parity")->AsString); // 编译失败:无法将UnicodeString转换为TParity* ComPort1->FlowControl->DTR = static_cast<TDTRControl *>(IBSQL1->FieldByName("FlowControlDTR")->AsString); // 编译失败:无法将UnicodeString转换为TDTRControl* ComPort1->FlowControl->RTS = static_cast<TRTSControl *>(IBSQL1->FieldByName("FlowControlRTS")->AsString); // 编译失败:无法将UnicodeString转换为TRTSControl* ComPort1->FlowControl->XOnXOff = static_cast<TXOnXOffControl *>(IBSQL1->FieldByName("FlowControlXOnXOff")->AsString); // 编译失败:无法将UnicodeString转换为TXOnXOffControl* ComPort1->FlowControl->XOffLimit = IBSQL1->FieldByName("FlowControlXOffLimit")->AsInteger; // 正常运行 ComPort1->FlowControl->XOnLimit = IBSQL1->FieldByName("FlowControlXOnLimit")->AsInteger; // 正常运行
解决方法
方法1:手动编写字符串转枚举的映射函数
针对每个枚举类型,编写对应的转换函数,通过字符串匹配返回对应的枚举值。以TBaudRate为例:
TBaudRate StringToBaudRate(const UnicodeString& BaudStr) { if (BaudStr == "br110") return br110; else if (BaudStr == "br300") return br300; else if (BaudStr == "br600") return br600; else if (BaudStr == "br1200") return br1200; else if (BaudStr == "br2400") return br2400; else if (BaudStr == "br4800") return br4800; else if (BaudStr == "br9600") return br9600; else if (BaudStr == "br14400") return br14400; else if (BaudStr == "br19200") return br19200; else if (BaudStr == "br38400") return br38400; else if (BaudStr == "br57600") return br57600; else if (BaudStr == "br115200") return br115200; // 补充其他波特率枚举值 else return br9600; // 默认值 }
同理编写StringToDataBits、StringToStopBits等函数,调用方式如下:
ComPort1->BaudRate = StringToBaudRate(IBSQL1->FieldByName("BaudRate")->AsString); ComPort1->DataBits = StringToDataBits(IBSQL1->FieldByName("DataBits")->AsString); // 其他属性依次处理
方法2:利用RTTI实现通用转换
如果使用的C++Builder版本支持RTTI,可通过GetEnumValue函数直接完成字符串到枚举的转换,无需逐个编写映射函数:
#include <TypInfo.hpp> template<typename TEnum> TEnum StringToEnum(const UnicodeString& EnumStr) { return static_cast<TEnum>(GetEnumValue(__typeinfo(TEnum), EnumStr)); }
使用示例:
ComPort1->BaudRate = StringToEnum<TBaudRate>(IBSQL1->FieldByName("BaudRate")->AsString); ComPort1->DataBits = StringToEnum<TDataBits>(IBSQL1->FieldByName("DataBits")->AsString); ComPort1->StopBits = StringToEnum<TStopBits>(IBSQL1->FieldByName("StopBits")->AsString); ComPort1->Parity = StringToEnum<TParity>(IBSQL1->FieldByName("Parity")->AsString); ComPort1->FlowControl->DTR = StringToEnum<TDTRControl>(IBSQL1->FieldByName("FlowControlDTR")->AsString); ComPort1->FlowControl->RTS = StringToEnum<TRTSControl>(IBSQL1->FieldByName("FlowControlRTS")->AsString); ComPort1->FlowControl->XOnXOff = StringToEnum<TXOnXOffControl>(IBSQL1->FieldByName("FlowControlXOnXOff")->AsString);
注意:字符串必须与枚举常量的精确名称完全一致(包括大小写,比如枚举是br9600,字符串必须是"br9600")。
方法3:存储枚举的整数值而非字符串
修改存储逻辑,将枚举类型转换为整数存储,读取时再转换回枚举,这种方式更高效且不易出错:
修改存储代码:
// 直接从ComPort组件读取枚举值并转整数存储 IBSQL1->ParamByName("BaudRate")->Value = static_cast<int>(ComPort1->BaudRate); IBSQL1->ParamByName("DataBits")->Value = static_cast<int>(ComPort1->DataBits); IBSQL1->ParamByName("StopBits")->Value = static_cast<int>(ComPort1->StopBits); IBSQL1->ParamByName("Parity")->Value = static_cast<int>(ComPort1->Parity); IBSQL1->ParamByName("FlowControlDTR")->Value = static_cast<int>(ComPort1->FlowControl->DTR); IBSQL1->ParamByName("FlowControlRTS")->Value = static_cast<int>(ComPort1->FlowControl->RTS); IBSQL1->ParamByName("FlowControlXOnXOff")->Value = static_cast<int>(ComPort1->FlowControl->XOnXOff);
修改读取代码:
ComPort1->BaudRate = static_cast<TBaudRate>(IBSQL1->FieldByName("BaudRate")->AsInteger); ComPort1->DataBits = static_cast<TDataBits>(IBSQL1->FieldByName("DataBits")->AsInteger); ComPort1->StopBits = static_cast<TStopBits>(IBSQL1->FieldByName("StopBits")->AsInteger); ComPort1->Parity = static_cast<TParity>(IBSQL1->FieldByName("Parity")->AsInteger); ComPort1->FlowControl->DTR = static_cast<TDTRControl>(IBSQL1->FieldByName("FlowControlDTR")->AsInteger); ComPort1->FlowControl->RTS = static_cast<TRTSControl>(IBSQL1->FieldByName("FlowControlRTS")->AsInteger); ComPort1->FlowControl->XOnXOff = static_cast<TXOnXOffControl>(IBSQL1->FieldByName("FlowControlXOnXOff")->AsInteger);
这种方式避免了字符串匹配的开销,兼容性更强,推荐优先使用。
内容的提问来源于stack exchange,提问作者ibouka
相关产品推荐
相关产品推荐

