功能均已在windows下经过测试
串口通讯
pro文件需要添加serialport
初始化代码,包括ui
QSerialPort *serial;
QString m_strComName;
int m_iBaudRate;
int m_iDataBit;
QString m_strParity;
QString m_strStopBit;
QString m_strFlowBit;
QList<QString> *m_strRecvList;
serial = new QSerialPort;
QString description;
QString manufacturer;
QString serialNumber;
//获取可以用的串口
QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();
//输出当前系统可以使用的串口个数
//qDebug() << "Total numbers of ports: " << serialPortInfos.count();
//将所有可以使用的串口设备添加到ComboBox中
for (const QSerialPortInfo &serialPortInfo : serialPortInfos)
{
QStringList list;
description = serialPortInfo.description();
manufacturer = serialPortInfo.manufacturer();
serialNumber = serialPortInfo.serialNumber();
list << serialPortInfo.portName()
<< (!description.isEmpty() ? description : blankString)
<< (!manufacturer.isEmpty() ? manufacturer : blankString)
<< (!serialNumber.isEmpty() ? serialNumber : blankString)
<< serialPortInfo.systemLocation()
<< (serialPortInfo.vendorIdentifier() ? QString::number(serialPortInfo.vendorIdentifier(), 16) : blankString)
<< (serialPortInfo.productIdentifier() ? QString::number(serialPortInfo.productIdentifier(), 16) : blankString);
ui->cbCom->addItem(list.first(), list);
}
//设置波特率
ui->cbRate->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
ui->cbRate->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
ui->cbRate->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
ui->cbRate->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);
ui->cbRate->addItem(tr("Custom"));
//设置数据位
ui->cbData->addItem(QStringLiteral("5"), QSerialPort::Data5);
ui->cbData->addItem(QStringLiteral("6"), QSerialPort::Data6);
ui->cbData->addItem(QStringLiteral("7"), QSerialPort::Data7);
ui->cbData->addItem(QStringLiteral("8"), QSerialPort::Data8);
ui->cbData->setCurrentIndex(3);
//设置奇偶校验位
ui->cbParity->addItem(tr("None"), QSerialPort::NoParity);
ui->cbParity->addItem(tr("Even"), QSerialPort::EvenParity);
ui->cbParity->addItem(tr("Odd"), QSerialPort::OddParity);
ui->cbParity->addItem(tr("Mark"), QSerialPort::MarkParity);
ui->cbParity->addItem(tr("Space"), QSerialPort::SpaceParity);
//设置停止位
ui->cbStop->addItem(QStringLiteral("1"), QSerialPort::OneStop);
ui->cbStop->addItem(QStringLiteral("2"), QSerialPort::TwoStop);
//添加流控
ui->cbFlowBit->addItem(tr("None"), QSerialPort::NoFlowControl);
ui->cbFlowBit->addItem(tr("RTS/CTS"), QSerialPort::HardwareControl);
ui->cbFlowBit->addItem(tr("XON/XOFF"), QSerialPort::SoftwareControl);
功能方法
//打开串口
//设置串口名字
serial->setPortName(m_strComName);
//设置波特率
serial->setBaudRate(m_iBaudRate);
//设置数据位
switch (m_iDataBit) {
case 5:
serial->setDataBits(QSerialPort::Data5);
break;
case 6:
serial->setDataBits(QSerialPort::Data6);
break;
case 7:
serial->setDataBits(QSerialPort::Data7);
break;
case 8:
serial->setDataBits(QSerialPort::Data8);
break;
}
//设置奇偶校验位
if(m_strParity=="None"){
serial->setParity(QSerialPort::NoParity);
}
else if(m_strParity=="Even"){
serial->setParity(QSerialPort::EvenParity);
}
else if(m_strParity=="Odd"){
serial->setParity(QSerialPort::OddParity);
}
else if(m_strParity=="Mark"){
serial->setParity(QSerialPort::MarkParity);
}
else if(m_strParity=="Space"){
serial->setParity(QSerialPort::SpaceParity);
}
//设置停止位
if(m_strStopBit=="1"){
serial->setStopBits(QSerialPort::OneStop);
}
else if(m_strStopBit=="2"){
serial->setStopBits(QSerialPort::TwoStop);
}
//设置流控
if(m_strFlowBit=="None"){
serial->setFlowControl(QSerialPort::NoFlowControl);
}
else if(m_strFlowBit=="RTS/CTS"){
serial->setFlowControl(QSerialPort::HardwareControl);
}
else if(m_strFlowBit=="XON/XOFF"){
serial->setFlowControl(QSerialPort::SoftwareControl);
}
//打开串口,成功就禁用控件
if (serial->open(QIODevice::ReadWrite))
{
ui->cbRate->setEnabled(false);
ui->cbData->setEnabled(false);
ui->cbFlowBit->setEnabled(false);
ui->cbParity->setEnabled(false);
ui->cbCom->setEnabled(false);
ui->cbStop->setEnabled(false);
ui->btSend->setEnabled(true);
//信号与槽函数关联,绑定回调处理的方法
connect(serial, &QSerialPort::readyRead, this, &MainWindow::readData);
}
//接收回调
void MainWindow::readData()
{
QByteArray buf;
buf = serial->readAll();
if (!buf.isEmpty())
{
QString str = ui->tbRecv->toPlainText();
str += tr(buf);
ui->tbRecv->clear();
ui->tbRecv->append(str);
m_strRecvList->append(buf);
}
}
//发送
void MainWindow::on_btSend_clicked()
{
serial->write(ui->tbSend->toPlainText().toLocal8Bit());
}
关闭串口
//关闭串口
//serial->clear();
serial->close();
m_strRecvList->clear();
//serial->deleteLater();
//恢复设置功能
ui->cbRate->setEnabled(true);
ui->cbData->setEnabled(true);
ui->cbFlowBit->setEnabled(true);
ui->cbParity->setEnabled(true);
ui->cbCom->setEnabled(true);
ui->cbStop->setEnabled(true);
ui->btOpenCom->setText(tr("打开串口"));
ui->btSend->setEnabled(false);
m_bIsConnect=false;
UI布局
网口通讯
pro文件需要添加network
tips:
服务器模式:
打开服务器使用QTcpServer(管理服务器),接收连接的客户端套接字用QTcpSocket
客户端模式使用QTcpSocket
初始化代码
QTcpServer *m_server;
QTcpSocket *m_socket;
bool m_bIsConnect;
QString m_strTcpIP;
int m_iTcpPort;
//创建用于服务端通信的套接字
m_server=new QTcpServer(this);
//连接成功就会触发connected信号
connect(m_server,&QTcpServer::newConnection,this,[=]()
{
m_socket = m_server->nextPendingConnection();//接收连入的客户端
ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n成功和客户端建立了连
m_bIsConnect=true;
//接收回调
connect(m_socket,&QTcpSocket::readyRead,this,[=]()
{
QByteArray data = m_socket->readAll();
QStringList list = QString(data).split('\n', QString::SkipEmp
m_strRecvList->append(list);//加入接收列表
for (int i = 0;i<list.count();i++) {
ui->tbTcpRecv->append("\n接收:"+list[i]);
}
});
connect(m_socket,&QTcpSocket::disconnected,this,[=]()
{
ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n客户端断开了
m_socket->close();
m_socket->deleteLater();
m_bIsConnect=false;
});
});
//创建用于客户端通信的套接字
m_socket = new QTcpSocket;
//连接成功就会触发connected信号
connect(m_socket,&QTcpSocket::connected,this,[=]()
{
ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n与服务器连接成功!"
m_bIsConnect=true;
//对方有数据传来就会触发readyRead信号
connect(m_socket,&QTcpSocket::readyRead,this,[=]()
{
QByteArray data = m_socket->readAll();
QStringList list = QString(data).split('\n', QString::SkipEmp
m_strRecvList->append(list);//加入接收列表
for (int i = 0;i<list.count();i++) {
ui->tbTcpRecv->append("\n接收:"+list[i]);
}
});
//双方断开连接后就会触发disconnected信号
connect(m_socket,&QTcpSocket::disconnected,this,[=]()
{
ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n客户端断开了
m_socket->close();
m_socket->deleteLater();
m_bIsConnect=false;
});
});
连接/监听代码:
void MainWindow::on_btTcpConnect_clicked()
{
//如果是服务器模式
if(ui->rbServer->isChecked())
{
try {
m_server->close();
} catch (...) {
}
QString localhost=QHostAddress(QHostAddress::LocalHost).toString();//127.0.0.1
QString any=QHostAddress(QHostAddress::AnyIPv4).toString();//任意端口,包括127.0.0.1和本地网络适配器的所有ip地址
m_server->listen(QHostAddress::AnyIPv4,m_iTcpPort);
}
//如果是客户端模式
else
{
try {
m_server->close();
m_socket->close();
} catch (...) {
}
//发起连接请求
m_socket->connectToHost(QHostAddress(m_strTcpIP),m_iTcpPort);
}
}
发送代码
if(m_bIsConnect){
m_socket->write(ui->tbTcpSend->toPlainText().toUtf8());
}
关闭代码
try {
if(m_bIsConnect){
m_server->close();
m_socket->close();
}
} catch (...) {
}
m_bIsConnect=false;
UI布局
内存拷贝
内存拷贝的双方软件一定要管理员模式打开,因为这是windows进程之间的通讯!!!!
这里使用C++的方式进行内存拷贝
引入头文件
#include "windows.h"
#include "winuser.h"
在使用的类中加入,否则会对windows的sendmessage,findwindow等函数报无法解析的外部符号错误,如下
#pragma comment (lib, "User32.lib")
在qt中要注意发送过来的字符格式,如果是宽字符/unicode(c++的LPCSTR,LPCWSTR,LPCTSTR),就需要用fromStdWString来接收,注意这个字符串长度也不一样,是默认的2倍,c++发送端如下
CString strText:
COPYDATASTRUCT cds;
memset(&cds, 0, sizeof(cds));
cds.dwData = 0;
//发送unicode字符,大小等于字串的size*2,sizeof(TCHAR)=2
cds.cbData = (strText.GetLength() ) * sizeof(TCHAR) + 1; // +1 for the NULL
cds.lpData = (LPVOID)(LPCWSTR)(strText);
如果是短字符,1个字节为单位的ansi(c++的W2A,char*),就需要用fromStdString来接收,这个字符串的长度是默认长度,c++发送端如下
CString strText:
COPYDATASTRUCT cds;
memset(&cds, 0, sizeof(cds));
cds.dwData = 0;
//发送ansi字符,大小等于字串的size*1,sizeof(TCHAR)=2
cds.cbData = (strText.GetLength() ) * 1 + 1; // +1 for the NULL
USES_CONVERSION;
cds.lpData = (LPVOID)W2A(strText);
c++接收端如下,不同格式ansi/unicode原理同上
LRESULT CTestCommunicationDlg::OnCopyData(WPARAM wParam,LPARAM lParam)
{
//HWND hwnd = (HWND)wParam; // handle of sending window
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
LPCWSTR szNewString = (LPCWSTR)(pcds->lpData);
m_strDataRcv = (LPCWSTR)(pcds->lpData);
//GetDlgItem(IDC_EDIT2)->SetWindowTextW(m_strDataRcv);
return 1L;
}
回到QT
QT查找窗口
m_MemTargetWin = ::FindWindow(NULL, ui->tbMemTargerWinName->text().toStdWString().c_str());//通过主窗口类名寻找主窗口句柄
if (NULL != m_MemTargetWin)
{
QMessageBox::information(this,"提示","找到名为:"+ui->tbMemTargerWinName->text()+"的窗口");
}else{
QMessageBox::warning(this,"提示","未找到名为:"+ui->tbMemTargerWinName->text()+"的窗口");
}
QT内存发送
WId wid = this->winId(); //这个窗口的winid
if (NULL != m_MemTargetWin)
{
std::thread th([=](){ //单独启动一个线程进行数据传递
QString command = QString("Command=ChangeCode=%1\r\n").arg(ui->tbMemSend->toPlainText());//传递的内容
COPYDATASTRUCT data; //使用COPYDATA的方式进行数据传递
data.dwData = 0;
data.cbData = command.length()*2+1;//unicode size = length*2+1;ansi size=length+1
data.lpData = command.data();
::SendMessage(m_MemTargetWin, WM_COPYDATA, (WPARAM)wid, (LPARAM)&data);
});
th.detach();//传递结束后,进行关闭线程
}
QT接收,在头文件中重写窗口事件消息
//virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;//此消息不行,传过来的数据不吻合,无法解析
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE;
重写
bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
if (eventType == "windows_generic_MSG") //windows平台
{
MSG* msg = reinterpret_cast<MSG*>(message);
if (msg->message == WM_APPCOMMAND || msg->message == WM_COPYDATA)//消息类型
{
COPYDATASTRUCT *data ;
data = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam);
//QString str=QString::fromStdWString((LPCWSTR)(data->lpData));//unicode过来用宽字符接收,LPCWSTR、LPCSTR或其他根据发送端而定
QString str=QString::fromStdString((char*)(data->lpData));//ansi过来用默认字符char*接收,如果是unicode过来的用ansi接收,则只能接收到第一个字符
// int size2 = sizeof(&data);
//char * dest = (char*)malloc(sizeof (char)*(int)data->cbData);
//memcpy(dest,data->lpData,(int)data->cbData);//只能接收到第一个字符
//QTextCodec *codec = QTextCodec::codecForName("UTF-8");
//QTextCodec::setCodecForLocale(codec);
//char * a=(char *)(data->lpData);//只能接收到第一个字符
//QString recevice = codec->toUnicode(a);//转码
//QString recevice((char *)(data->lpData));//只能接收到第一个字符
ui->tbMemRecv->append(str);
}
}
return QWidget::nativeEvent(eventType, message, result);//交给Qt处理,不能少
}
UI布局