1. 説明:
複雑なソフトウェアシステムでは、複数の通信プロトコルが存在する場合があり、複数の通信を組み合わせてソフトウェア制御のプロセス全体を実現する場合があります。現在、Bluetooth通信を使用して近距離で信号を送信することは比較的一般的な方法であり、特にAndroid側のソフトウェアを開発する場合、Bluetooth通信を使用することは非常に一般的です. この記事では、QML で Bluetooth 通信を使用する小さなケースを記録します。
2. 実装手順:
QML で Bluetooth 通信を使用するには、2 つのオプションがあります. 1 つは、実装が簡単なBluetoothDiscoveryModel、BluetoothService、および BluetoothSocket の3 つのコントロールを使用する方法と、 qwidget の対応する 3 つのクラスQBluetoothDeviceDiscoveryAgent、QBluetoothLocalDevice、および QBluetoothSocket を使用する方法です。
現在のところ、最初の方法は qt で完全にサポートされていないようです. 場合によってはバグが発生し、Bluetooth デバイスに接続できなくなる可能性があります. 2 番目の方法はまだ可能です.
そこで、この記事ではQMLを使ってインターフェースを構築し、上記3つのクラスを使ってBluetooth通信機能をQtに実装しています。
結果を示す:
2.1 クラス関数の説明:
前提: Bluetooth モジュールQT += bluetooth*** を ***.Pro ファイルに追加し、次のヘッダー ファイルをカスタム Bluetooth プロトコル クラス ファイルに追加します。
#include <QBluetoothSocket> //用于数据通信
#include <QBluetoothLocalDevice> //用于控制本机蓝牙状态(开启/关闭)
#include <QBluetoothDeviceDiscoveryAgent> //用于搜寻附近的蓝牙设备
#include <QBluetoothAddress> //用于提取蓝牙设备的地址
Bluetooth デバイスを接続する場合、対象の Bluetooth デバイスのアドレスを知る必要があります.これは、QBluetoothDeviceDiscoveryAgent クラスによって検索された情報を通じて抽出できます.また、UUID 識別番号も知る必要があります.一般に、シリアル ポート クラスの uuid使用されているタイプを調べることができます 検索、参照 URL: https://www.jianshu.com/p/eb85cb690e86
2.2 カスタム Bluetooth プロトコル クラス:
QML で Bluetooth 構成の関連関数を呼び出すには、QML と C++ が対話する必要があるため. Bluetooth サービス モジュールを別のクラスにカプセル化し、登録された QML で使用することができます.クラスについては、コードのコメントを参照してください。非常に詳細です。コア コードは次のとおりです。
BluetoothProxy.h:
#ifndef BLUETOOTHPROXY_H
#define BLUETOOTHPROXY_H
#include <QObject>
#include <QBluetoothSocket>
#include <QBluetoothLocalDevice>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QBluetoothAddress>
class BluetoothProxy : public QObject
{
Q_OBJECT
public:
explicit BluetoothProxy(QObject *parent = nullptr);
~BluetoothProxy();
public slots:
void addBlueToothDevicesToList(const QBluetoothDeviceInfo&);
void readBluetoothDataEvent();
void bluetoothConnectedEvent();
void bluetoothDisconnectedEvent();
void onError(QBluetoothSocket::SocketError error);
//启动搜寻蓝牙
Q_INVOKABLE void startSearch();
//发送数据
Q_INVOKABLE void sendData(QString mData);
//断开蓝牙
Q_INVOKABLE void disconnectBth();
signals:
//每次搜寻到蓝牙设备,发送此信号
void deviceFind(QString mDeviceInfo);
//配对状态更新时,发送此信号
void connectProcess(QString mProcessInfo);
private:
//用于搜寻附近的蓝牙设备
QBluetoothDeviceDiscoveryAgent *discoveryAgent;
//用于控制本机蓝牙状态(开启/关闭)
QBluetoothLocalDevice *localDevice;
//用于数据通信
QBluetoothSocket *socket;
};
#endif // BLUETOOTHPROXY_H
BluetoothProxy.cpp:
#include "bluetoothproxy.h"
//这个UUID要根据自己的使用情况来确定,我使用的是串口类的UUID,具体可https://www.jianshu.com/p/eb85cb690e86
static const QLatin1String serviceUuid("00001101-0000-1000-8000-00805F9B34FB");
BluetoothProxy::BluetoothProxy(QObject *parent) : QObject(parent)
{
//在构造函数中初始化一些成员变量
discoveryAgent = new QBluetoothDeviceDiscoveryAgent(); // 否则搜寻周围的蓝牙设备
localDevice = new QBluetoothLocalDevice(); // 负责控制设备上的蓝牙(比如开启/关闭等操作)
socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol); // 负责通信数据传输
//搜寻到蓝牙设备后,将启动设备信息存储函数
connect(discoveryAgent,SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this,SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo)));
//接收到有数据传输过来时,将启动读取信息的函数
connect(socket,SIGNAL(readyRead()),this,SLOT(readBluetoothDataEvent()));
//与目标设备成功连接够,启动提示函数
connect(socket,SIGNAL(connected()),this,SLOT(bluetoothConnectedEvent()));
//与目标设备断开连接时,启动顿开蓝牙提示函数
connect(socket,SIGNAL(disconnected()),this,SLOT(bluetoothDisconnectedEvent()));
//出西安错误时,启动错误响应函数
connect(socket,SIGNAL(error(QBluetoothSocket::SocketError)),this,SLOT(onError(QBluetoothSocket::SocketError)));
}
BluetoothProxy::~BluetoothProxy()
{
}
void BluetoothProxy::onError(QBluetoothSocket::SocketError error)
{
QString str;
if(QBluetoothSocket::UnknownSocketError == error){
str = "UnknownSocketError";
}else if(QBluetoothSocket::NoSocketError == error){
str = "NoSocketError";
}else if(QBluetoothSocket::HostNotFoundError == error){
str = "HostNotFoundError";
}else if(QBluetoothSocket::ServiceNotFoundError == error){
str = "ServiceNotFoundError";
}else if(QBluetoothSocket::NetworkError == error){
str = "NetworkError";
}else if(QBluetoothSocket::UnsupportedProtocolError == error){
str = "UnsupportedProtocolError";
}else if(QBluetoothSocket::OperationError == error){
str = "OperationError";
}else if(QBluetoothSocket::RemoteHostClosedError == error){
str = "RemoteHostClosedError";
}
qDebug()<<error;
}
//开始搜寻蓝牙设备
void BluetoothProxy::startSearch()
{
// if(localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff){
// localDevice->powerOn();//调用打开本地的蓝牙设备
// discoveryAgent->start();
// }
discoveryAgent->start();
}
//发送数据到蓝牙设备
void BluetoothProxy::sendData(QString mData)
{
socket->write(mData.toUtf8());
}
//断开蓝牙
void BluetoothProxy::disconnectBth()
{
socket->close();
}
//显示蓝牙设备信息
void BluetoothProxy::addBlueToothDevicesToList( const QBluetoothDeviceInfo &info )
{
QString deviceInfo = QString("%1 %2").arg(info.address().toString()).arg(info.name());
qDebug()<<deviceInfo;
emit deviceFind(deviceInfo);
//如果发现目标蓝牙,则进行连接
if(deviceInfo.contains("这里换成自己蓝牙设备的名称")){
int index = deviceInfo.indexOf(' ');
if(index == -1){
qDebug()<<"index";
return;
}
//获取目标蓝牙设备地址
QBluetoothAddress address(deviceInfo.left(index));
QString name(deviceInfo.mid(index + 1));
//开始连接
socket->connectToService(address, QBluetoothUuid(serviceUuid) ,QIODevice::ReadWrite);
//向qml端发送信号
emit connectProcess(QString("蓝牙连接中,请稍后....(%1)").arg(name));
}
}
//接收蓝牙设备发送过来的数据
void BluetoothProxy::readBluetoothDataEvent()
{
QByteArray receiceData = socket->readAll();
if(receiceData.size() > 4)return;
}
void BluetoothProxy::bluetoothConnectedEvent()
{
emit connectProcess("蓝牙连接成功....");
}
void BluetoothProxy::bluetoothDisconnectedEvent()
{
emit connectProcess("蓝牙已断开....");
}
2.3 特定の用途:
上記のカスタム クラスをmain.cppファイルの QML に登録します。
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlContext>
#include "bluetoothproxy.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
//自定义蓝牙类注册到QML中
BluetoothProxy blueTooth;
engine.rootContext()->setContextProperty("myBlueTooth",&blueTooth);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
上記のカスタム Bluetooth クラスを QML に登録した後、.qml ファイルで呼び出すことができます. メイン インターフェイス コードは次のとおりです:
main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
id:root
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Connections{
target: myBlueTooth
function onDeviceFind(mDeviceInfo){
blueToothList.append({
info:mDeviceInfo})
}
function onConnectProcess(mProcessInfo){
popText.text = mProcessInfo
pop.open()
}
}
Text{
id:titleName
anchors.horizontalCenter: btView.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 15
text: "此处显示蓝牙设备信息"
font.pixelSize: 20
}
ListView{
id:btView
width: 300
height: 400
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: titleName.bottom
anchors.topMargin: 15
spacing: 10
focus:true
enabled: true
highlight: Rectangle {
width: parent.width
height: 20
color: "lightsteelblue"
radius: 5
y: btView.currentItem.y
Behavior on y {
SpringAnimation {
spring: 3
damping: 0.2
}
}
}
model: ListModel{
id:blueToothList
// ListElement{
// info:""
// }
}
delegate: Rectangle{
color: Qt.rgba(0,0,0,0)
width: parent.width
height: 20
anchors.horizontalCenter: parent.horizontalCenter
Text{
id:deviceInfo
anchors.centerIn: parent
text: info
font.pixelSize: 15
color: "black"
}
MouseArea{
anchors.fill: parent
onClicked: {
btView.currentIndex = index
}
}
}
}
Button{
id:searchBtn
width: 100
height: 50
text: "搜寻蓝牙"
onClicked: {
myBlueTooth.startSearch()
}
}
Button{
id:clearBtn
width: 100
height: 50
anchors.top:searchBtn.bottom
anchors.topMargin: 10
text:"清空信息"
onClicked: {
blueToothList.clear()
}
}
Button{
id:sendBtn
width: 100
height: 50
anchors.top:clearBtn.bottom
anchors.topMargin: 10
text:"发送数据"
onClicked: {
myBlueTooth.sendData("1")
}
}
Button{
id:discBtn
width: 100
height: 50
anchors.top:sendBtn.bottom
anchors.topMargin: 10
text:"断开蓝牙"
onClicked: {
myBlueTooth.disconnectBth()
}
}
Popup{
id:pop
width: 300
height: 200
x:(root.width-pop.width)/2
y:(root.height-pop.height)/2
//visible: true// the default value is false
background: Rectangle {
anchors.fill: parent
border.width: 0
radius: 20
color: Qt.rgba(0,0,0,0.4)
}
contentItem: Rectangle{
anchors.fill: parent
color: Qt.rgba(0,0,0,0.4)
border.width: 0
radius: 20
Text{
id:popText
anchors.centerIn: parent
font.pixelSize: 20
color: "white"
}
Row{
id:btnRow
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 50
Button{
id:cancelBtn
width: 60
height: 25
anchors.right: parent.right
anchors.rightMargin: 15
anchors.bottom: parent.bottom
anchors.bottomMargin: 15
text: "Yes"
onClicked: {
pop.close()
}
}
}
}
}
}
インターフェースの設計は比較的単純で、主に機能を実現するために、インターフェースの効果は次のとおりです。
2.4 機能テスト:
Android フォンにSPP Bluetooth シリアル ポートソフトウェアをダウンロードしました, これは、電話のアプリ ストアでダウンロードできます. ソフトウェアを開いた後、ページの右上隅にある ***+ 記号を選択し、次にサーバー モード ***、下の図に示すように表示:
サーバーを起動した後、Qt プログラムを実行し、インターフェースの[Bluetooth の検索]ボタンをクリックして、近くの Bluetooth デバイスを自動的に検索できます。コード内の Bluetooth デバイスを自分のデバイスの名前に変更しないと、Bluetooth に接続できません。
Bluetooth を検出できない状況に遭遇した場合は、携帯電話の Bluetooth アシスタントの右上隅にある設定ボタンをクリックし、検出可能性を有効にすることを選択し、データの受信形式を utf に変更することに注意してください。 8 、これは、上記のコードで Bluetooth 端末によって送信されるデータ形式が utf-8 形式で定義されているためです。下の図に示すように:
そうすれば、楽しくデータを転送できます。. . .