Qt使用和常用代碼


Qt使用和常用代碼

https://blog.csdn.net/u014678728/article/details/101155667

 

Qt基礎和庫
QObject
//刪除

obj->deleteLater()或 delete obj
deleteLater會等這次事件循環結束再釋放內存 必須在運行事件循環的線程中調用

//類型轉化
QObject *obj = new QTimer; // QTimer inherits QObject
QTimer *timer = qobject_cast<QTimer *>(obj);
// timer == (QObject *)obj
QAbstractButton *button = qobject_cast<QAbstractButton *>(obj);
// button == 0

要轉化的類必須繼承QObject和聲明Q_OBJECT宏

//查找子類
QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");
QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>();
QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);

//事件過濾
class KeyPressEater : public QObject
{
Q_OBJECT
...

protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};

bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
qDebug("Ate key press %d", keyEvent->key());
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
}

And here's how to install it on two widgets:

KeyPressEater *keyPressEater = new KeyPressEater(this);
QPushButton *pushButton = new QPushButton(this);
QListView *listView = new QListView(this);

pushButton->installEventFilter(keyPressEater);
listView->installEventFilter(keyPressEater);

//注冊函數到原對象系統

Q_INVOKABLE void invokableMethod();
使用QMetaObject::invokeMethod(obj, "invokableMethod");

//原對象系統
跨線程連接信號和槽 參數不是qt基本類
使用
int id = qRegisterMetaType<MyStruct>();

所有要使用信號和槽的類 必須繼承QObject和聲明Q_OBJECT宏
//屬性
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
Q_PROPERTY(QString title READ title WRITE setTitle USER true)

//信號
signals:
void signal_1();
emit signal_1 發射信號

//槽
public slots:
void slot_1();

connect(obj, SIGNAL(signal_1), obj2, SLOT(slot_1));

c++11
connect(sender, &Sender::valueChanged, reciver, &Reciver::showValue)
lambad
connect(sender, &Sender::valueChanged, [](){
});


支持編譯時檢查, 支持相容類型自動轉化, 可以連接任何函數不用聲明 slot

如果信號和槽有重載:
connect(sender, static_cast<void(QSpinBox::*) (int)> (&QSpinBox::valueChanged)) ,
this, &MainWindow::onSpinBoxChanged);

qt基本容器
QList<T>
QLinkedList<T>
QVector<T>
QStack<T>
QQueue<T>
QSet<T>
QMap<Key, T>
QMultiMap<Key, T>
QHash<Key, T>
QMultiHash<Key, T>

//JAVA風格遍歷
QList<QString> list;
list << "A" << "B" << "C" << "D";

QListIterator<QString> i(list);
while (i.hasNext())
qDebug() << i.next();

QListIterator<QString> i(list);
i.toBack();
while (i.hasPrevious())
qDebug() << i.previous();

//迭代器中 插入刪除使用 QMutableMapIterator

QMap<QString, QString> map;
map.insert("Paris", "France");
map.insert("Guatemala City", "Guatemala");
map.insert("Mexico City", "Mexico");
map.insert("Moscow", "Russia");
...

QMutableMapIterator<QString, QString> i(map);
while (i.hasNext()) {
if (i.next().key().endsWith("City"))
i.remove();
}

//STL風格遍歷
QList<QString> list;
list << "A" << "B" << "C" << "D";

QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
*i = (*i).toLower();

//反向迭代
QList<QString> list;
list << "A" << "B" << "C" << "D";

QList<QString>::reverse_iterator i;
for (i = list.rbegin(); i != list.rend(); ++i)
*i = i->toLower();
}
//只讀
QList<QString>::const_iterator i;
for (i = list.constBegin(); i != list.constEnd(); ++i)
qDebug() << *i;

//foreach迭代---注意不要在迭代器里刪除元素

QLinkedList<QString> list;
...
foreach (const QString &str, list) {
if (str.isEmpty())
break;
qDebug() << str;
}


 

數據庫

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "Project"); //數據庫類型,別名
db.setDatabaseName("mysql"); db.setHostName("127.0.0.1");
db.setUserName("root");
db.setPassword("");
db.open();
//執行sql語句
query = QSqlQuery(QSqlDatabase::database("Project"));
query.exec("create table if not exists time_table (`time` text NOT NULL, `info` text)");
//查詢表

query.exec(QString("select * from time_table"));
while (query.next()) {
QString info = query.value("info").toString();
foreach (QString timeInfo, allTimeInfoList) {
if(info.contains(timeInfo)) {
QStringList &list= m_timeSendList[QTime::fromString(query.value("time").toString(), "hh::mm::ss")];
if(!list.contains(info)) {
list.append(info);
}
break;
}
}
}

//tableview
model = new QSqlQueryModel(this);
ui->tableView->setModel(model);
model->setQuery(QString("SELECT *from %3 where time >= '%1' and time <= '%2'").
arg(ui->dateTimeEdit->dateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(ui->dateTimeEdit_2->dateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(m_table), QSqlDatabase::database("Project"));

//設置顯示頭
if(model->columnCount() >= 4) {
model->setHeaderData(0, Qt::Horizontal, tr("系統"));
model->setHeaderData(1, Qt::Horizontal, tr("描述"));
model->setHeaderData(2, Qt::Horizontal, tr("時間"));
model->setHeaderData(3, Qt::Horizontal, tr("操作者"));
} else {
model->setHeaderData(0, Qt::Horizontal, tr("描述"));
model->setHeaderData(1, Qt::Horizontal, tr("時間"));
model->setHeaderData(2, Qt::Horizontal, tr("操作者"));
}
HTTP
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished,
this, &MyClass::replyFinished);

manager->get(QNetworkRequest(QUrl("http://qt-project.org")));



QNetworkRequest request;
request.setUrl(QUrl("http://qt-project.org"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");

QNetworkReply *reply = manager->get(request);
connect(reply, &QIODevice::readyRead, this, &MyClass::slotReadyRead);
connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
this, &MyClass::slotError);
connect(reply, &QNetworkReply::sslErrors,
this, &MyClass::slotSslErrors);


//使用
accessManager = new new QNetworkAccessManager();
//POST
void Common::post(const QString &url, const QString &data)
{
QNetworkRequest request;
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
//request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
//request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());

request.setUrl(QUrl(url));
QByteArray postData;
postData.append(data);
QNetworkReply* reply = accessManager->post(request, postData);

connect(reply, &QNetworkReply::finished, [this, reply, url]{
emit getmessage(reply->readAll());
reply->deleteLater();
});
}

void Common::get(const QString &url)
{
QNetworkRequest request;
request.setUrl(QUrl(url));
QNetworkReply* reply = accessManager->get(request);
connect(reply, &QNetworkReply::finished, [this, reply, url]{
QByteArray alldata = reply->readAll();
emit getmessage(alldata);
reply->deleteLater();
});
}

//JOSN
QMap<QString, QVariant> GFun::jsonParse(const QByteArray &jsonData)
{
QJsonParseError jsonError;
QJsonDocument doucment = QJsonDocument::fromJson(jsonData, &jsonError); // 轉化為 JSON 文檔
if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) { // 解析未發生錯誤
if (doucment.isObject()) { // JSON 文檔為對象
QJsonObject object = doucment.object(); // 轉化為對象
return object.toVariantMap();
}
}
QMap<QString, QVariant> data;
return data;
}
TCP/UDP
UDP
void Server::initSocket()
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 7755);

connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(readPendingDatagrams()));
}

void Server::readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpSocket->receiveDatagram();
processTheDatagram(datagram);
}
}
192.168.1.255廣播地址


//服務端
tcpServer = new QTcpServer(this);
if (!tcpServer->listen(QHostAddress::Any, 1883)) {
close();
return;
}

connect(tcpServer, &QTcpServer::newConnection, this, &Server::sendFortune);
connect(tcpServer, &QTcpServer::acceptError, this, [](QAbstractSocket::SocketError socketError){
});

void Server::sendFortune()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_10);

out << fortunes[QRandomGenerator::global()->bounded(fortunes.size())];

QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection, &QAbstractSocket::disconnected,
clientConnection, &QObject::deleteLater);

clientConnection->write(block);
clientConnection->disconnectFromHost();
}
//客戶端

//初始化TCP客戶端
tcpClient = new QTcpSocket(this); //實例化tcpClient
tcpClient->abort(); //取消原有連接
connect(tcpClient, &QTcpSocket::readyRead, this, [tcpClient]{
tcpClient->readAll();
});
connect(tcpClient, &QTcpSocket::connected, this, [tcpClient]{
qDebug()<"連接成功";
});

connect(tcpClient, &QTcpSocket::disconnected, this, [tcpClient]{
qDebug()<"斷開連接";
});

connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), \
this, SLOT(ReadError(QAbstractSocket::SocketError)));

Signals
void connected()
void disconnected()
void error(QAbstractSocket::SocketError socketError)
void hostFound()
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
void stateChanged(QAbstractSocket::SocketState socketState)


disconnectFromHost 斷開連接,等待緩沖區寫入完成
abort 直接斷開,不等待
進程和線程
開啟新的進程
C++
system();
Qt
//!!! Qt5
QString program = "C:/Windows/System32/cmd.exe";
QStringList arguments;
arguments << "/c" << "dir" << "C:\\";
QProcess *cmdProcess = new QProcess; cmdProcess->start(program, arguments);
QObject::connect(cmdProcess, &QProcess::readyRead, [=] () {
QTextCodec *codec = QTextCodec::codecForName("GBK");
QString dir = codec->toUnicode(cmdProcess->readAll());

//線程 moveToThread
class Worker : public QObject
{
Q_OBJECT

public slots:
void doWork(const QString &parameter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}

signals:
void resultReady(const QString &result);
};

class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};

//線程 RUN
class WorkerThread : public QThread
{
Q_OBJECT
void run() override {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};

void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}



QThread::idealThreadCount() //獲取CPU數量

//互斥鎖

QMutex mutex;
int number = 6;

void method1()
{
mutex.lock();
number *= 5;
number /= 4;
mutex.unlock();
}

void method2()
{
mutex.lock();
number *= 3;
number /= 2;
mutex.unlock();
}

//QMutexLocker 析構自動釋放鎖
int complexFunction(int flag)
{
QMutexLocker locker(&mutex);

return 1;
}

//讀寫鎖
QReadWriteLock lock;

void ReaderThread::run()
{
...
lock.lockForRead();
read_file();
lock.unlock();
...
}

void WriterThread::run()
{
...
lock.lockForWrite();
write_file();
lock.unlock();
...
}
//信號量
QSemaphore sem(5); // sem.available() == 5

sem.acquire(3); // sem.available() == 2
sem.acquire(2); // sem.available() == 0
sem.release(5); // sem.available() == 5
sem.release(5); // sem.available() == 10

sem.tryAcquire(1); // sem.available() == 9, returns true
sem.tryAcquire(250); // sem.available() == 9, returns false
//條件變量

forever {
mutex.lock();
keyPressed.wait(&mutex);
do_something();
mutex.unlock();
}

forever {
getchar();
keyPressed.wakeAll();
}

QAtomicInt
QAtomicPointer


資源文件
資源文件以 .qrc結尾
在c++中使用資源文件 路徑 :/image/a.png
qml使用資源文件 qrc:/Button.qml

.pro中執行qmake編譯資源文件
system($$[QT_INSTALL_BINS]/rcc.exe -binary $$PWD/res.qrc -o $$PWD/myresource.rcc)

再main中QResource::registerResource("./myresource.rcc");
c++11 
c++11支持, 在.pro中增加 CONFIG += c++11

constexpr 用於向編譯器指出, 函數或變量在編譯時運算。 QT5中使用 Q_DECL_CONSTEXPR
static_assert 靜態斷言, 編譯時檢測一些條件是否成立 Q_STATIC_ASSERT
override 修飾函數, 函數必須覆蓋父類的函數, Q_DECL_OVERRIDE
void MyWidget::mouseMoveEvent() Q_DECL_OVERRIDE

final 打斷virtual的傳播 如果一個虛函數被final修飾所有的子類都不能覆蓋該函數, Q_DECL_FINAL
delete 顯示禁止c++編譯器生成代碼, 被修飾的函數不能被調用。 Q_DECL_DELETE
Lambad
Lambda 表達式: Lambda表達式就是匿名函數,。

[capture](parameter)mutable -> return-type{state}

capture 是捕捉列表。
parameter 是參數列表,就是函數的那些傳入變量。
mutable 這個后面再介紹。
return-type 返回值的類型,如果返回值明確,也可以省略。
state 是函數體


connect(sender, &StringDialog::stringChanged, [=](QString str)) {
if(str == "qt") {
} else {}
});

Lambad 表達式引入符:

[] 不捕獲任何局部變量
[=] 以傳值的方式捕獲外部變量
[&] 以引用的方式捕獲外部變量
[x, &y] x傳值捕獲, y引用捕獲
[=, &x] x引用捕獲, 其他傳值捕獲
[&, x] x傳值捕獲, 其它引用捕獲
[a, &str]->QString{} 傳值捕獲a, 引用捕獲str, 返回值是QString。

帶默認參數的槽函數:

connect(sender, &sender::signal, [](){ pushButton->anumateClick });
QWidget
setAttribute(Qt::WA_DeleteOnClose); //關閉窗口自動銷毀
setWindowFlags(Qt::Dialog);
setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
setWindowModality(Qt::WindowModal); //模態對話框

//設置窗體透明但是其中的部件不透明
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground, true);
智能指針
QPointer
QSharedPointer
QWeakPointer
QScopedPointer
QScopedArryPointer
QExplicitlyShareDataPointer
std::auto_ptr
std::shared_ptr
std::weak_ptr
std::unique_ptr


//QPointer 弱類型指針 允許外部刪除對象
QPointer<QLabel> label = new QLabel;
label->setText("&Status:");
...
if (label)
label->show();
QLabel被刪除 label值自動為NULL

//QSharedPointer 強引用指針,采用引用計數,當引用計數為0時調用 delete回調函數
static void doDeleteLater(MyObject *obj)
{
obj->deleteLater();
}

void otherFunction()
{
QSharedPointer<MyObject> obj =
QSharedPointer<MyObject>(new MyObject, doDeleteLater);

// continue using obj
obj.clear(); // calls obj->deleteLater();
}

QSharedPointer<MyObject> obj =
QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);

//QWeakPointer 弱類型指針 允許外部刪除對象

QWeakPointer<int> weakref;

// ...

QSharedPointer<int> strong = weakref.toStrongRef();
if (strong)
qDebug() << "The value is:" << *strong;
else
qDebug() << "The value has already been deleted";
提升為 QSharedPointer會檢測對象是否被刪除

//QScopedPointer類存儲指向動態分配對象的指針,並在銷毀時刪除它

void myFunction(bool useSubClass)
{
// assuming that MyClass has a virtual destructor
QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass);
QScopedPointer<QIODevice> device(handsOverOwnership());

if (m_value > 3)
return;

process(device);
}

Custom Cleanup Handlers
Arrays as well as pointers that have been allocated with malloc must not be deleted using delete. QScopedPointer's second template parameter can be used for custom cleanup handlers.
The following custom cleanup handlers exist:
QScopedPointerDeleter - the default, deletes the pointer using delete
QScopedPointerArrayDeleter - deletes the pointer using delete []. Use this handler for pointers that were allocated with new [].
QScopedPointerPodDeleter - deletes the pointer using free(). Use this handler for pointers that were allocated with malloc().
QScopedPointerDeleteLater - deletes a pointer by calling deleteLater() on it. Use this handler for pointers to QObject's that are actively participating in a QEventLoop.
You can pass your own classes as handlers, provided that they have a public static function void cleanup(T *pointer).

// this QScopedPointer deletes its data using the delete[] operator:
QScopedPointer<int, QScopedPointerArrayDeleter<int> > arrayPointer(new int[42]);

// this QScopedPointer frees its data using free():
QScopedPointer<int, QScopedPointerPodDeleter> podPointer(reinterpret_cast<int *>(malloc(42)));

// this struct calls "myCustomDeallocator" to delete the pointer
struct ScopedPointerCustomDeleter
{
static inline void cleanup(MyCustomClass *pointer)
{
myCustomDeallocator(pointer);
}
};

// QScopedPointer using a custom deleter:
QScopedPointer<MyCustomClass, ScopedPointerCustomDeleter> customPointer(new MyCustomClass);

//std::auto_ptr 指針對象析構 指向對象自動釋放
void Function()
{
auto_ptr<Obj> ptr( new Obj(20) );
...
if (error occur)
throw exception...
}
auto_ptr復制構造函數中把真是引用的內存指針進行的轉移 可能產生野指針


//std::shared_ptr
shared_ptr自動銷毀所管理的對象
std::shared_ptr 是一種智能指針,它能夠記錄多少個 shared_ptr 共同指向一個對象,從而消除顯示的調用 delete,當引用計數變為零的時候就會將對象自動刪除。
std::shared_ptr 可以通過 get() 方法來獲取原始指針,通過 reset() 來減少一個引用計數,並通過get_count()來查看一個對象的引用計數。

shared_ptr<int> p1;
//被初始化成為一個空指針

shared_ptr<int> p2 (new int(4));
//指向一個值是4的int類型數據

shared_ptr<int> p3 = new int(4);
//錯誤,必須直接初始化

shared_ptr<T> p;
//空智能指針,可指向類型是T的對象

if(p)
 //如果p指向一個對象,則是true

(*p)
//解引用獲取指針所指向的對象

p -> number == (*p).number;

p.get();
//返回p中保存的指針

swap(p,q);
//交換p q指針

p.swap(q);
//交換p,q指針

make_shared<T>(args) 
//返回一個shared_ptr的對象,指向一個動態類型分配為T的對象,用args初始化這個T對象

shared_ptr<T> p(q)
//p 是q的拷貝,q的計數器++,這個的使用前提是q的類型能夠轉化成是T*

shared_pts<T> p(q,d) 
//p是q的拷貝,p將用可調用對象d代替delete
//上面這個我其實沒懂,也沒有查出來這個的意思

p =q;
//p的引用計數-1,q的+1,p為零釋放所管理的內存

p.unique();
//判斷引用計數是否是1,是,返回true

p.use_count();
//返回和p共享對象的智能指針數量

p.reset();
p.reset(q);
p.reset(q,d);
//reset()重新設置 新的指想對象

//std::weak_ptr

weak_ptr是一種不控制所指向對象生存期的智能指針,指向shared_ptr管理的對象,但是不影響shared_ptr的引用計數。它像shared_ptr的助手,一旦最后一個shared_ptr被銷毀,對象就被釋放,weak_ptr不影響這個過程。

weak_ptr是為配合shared_ptr而引入的一種智能指針來協助shared_ptr工作,它可以從一個shared_ptr或另一個weak_ptr對象構造,它的構造和析構不會引起引用計數的增加或減少。沒有重載 * 和 -> 但我們可以通過lock來獲得一個shared_ptr對象來對資源進行使用,如果引用的資源已經釋放,lock()函數將返回一個存儲空指針的shared_ptr。 expired函數用來判斷資源是否失效。
weak_ptr的使用更為復雜一點,它可以指向shared_ptr指針指向的對象內存,卻並不擁有該內存,而使用weak_ptr成員lock,則可返回其指向內存的一個share_ptr對象,且在所指對象內存已經無效時,返回指針空值nullptr。
注意:weak_ptr並不擁有資源的所有權,所以不能直接使用資源。
可以從一個weak_ptr構造一個shared_ptr以取得共享資源的所有權。
weak_ptr<T> w(sp);
//定義一個和shared_ptr sp指向相同對象的weak_ptr w,T必須能轉化成sp指向的類型

w = p;
//p是shared_ptr或者weak_ptr,w和p共享對象

w.reset();
//w置為空

w.use_count();
//計算與w共享對象的shared_ptr個數

w.expired();
//w.use_count()為0,返回true

w.lock();
//w.expired()為true,返回空shared_ptr,否則返回w指向對象的shared_ptr

//std::unique_ptr
unique_ptr 不共享它的指針。它無法復制到其他 unique_ptr,無法通過值傳遞到函數,也無法用於需要副本的任何標准模板庫 (STL) 算法。只能移動unique_ptr。

可以使用 移動語義轉移所有權
unique_ptr<int> pInt(new int(5));
unique_ptr<int> pInt2 = std::move(pInt); // 轉移所有權 轉換為右值

函數可以返回 unique_ptr 類似移動語義 函數返回值是右值
unique_ptr<int> clone(int p)
{
unique_ptr<int> pInt(new int(p));
return pInt; // 返回unique_ptr
}

int main() {
int p = 5;
unique_ptr<int> ret = clone(p);
cout << *ret << endl;
}

//示例代碼

#include <memory>
#include <iostream>
#include <utility>

class Foo{

public:
Foo() = default;
Foo(int a):_a(a) {}
~Foo() {}
int get_a(){
return _a;
}
void set_a(int a) {
_a = a;
}
private:
int _a;

};

std::unique_ptr<Foo> change_a(std::unique_ptr<Foo> f)
{
f->set_a(10);
return f;
}

int main()
{
// std::make_unique是c++14才有
std::unique_ptr<Foo> pf = std::make_unique<Foo>(10);
// unique_ptr的復制構造函數和拷貝構造函數是刪除了的,這樣保證了對象獨占,如果不是獨占,那么跟shared_ptr
// 就是一樣的功能了。
// std::unique_ptr<Foo> pf1 = pf; // compile error

// 按值傳參,會有拷貝問題,同上
// auto p = change_a(pf); //compile error

auto p = change_a(std::move(pf));
std::cout << "get_a = " << p->get_a() << std::endl;
if(!pf)
{
std::cout << "pf is nullptr" << std::endl;
}
//owner transfer from function
std::unique_ptr<Foo> pf2 = std::make_unique<Foo>(11);
std::unique_ptr<Foo> p2 = change_a(std::move(pf2));
std::cout << "get_a = " << p2->get_a() << std::endl;
if(!pf2)
{
std::cout << "pf2 is nullptr" << std::endl;
}

//使用reset
pf2.reset(new Foo(12));
std::cout << "pf2 is not null: " << pf2->get_a() << std::endl;

//release獲取原始指針
Foo* ff = pf2.release();
if(!pf2)
{
std::cout << "pf2 is nullptr" << std::endl;
}
std::cout << "ff is not null: " << ff->get_a() << std::endl;

return 0;
}
自定義隱士共享
#include <QSharedData>
#include <QString>

class EmployeeData : public QSharedData
{
public:
EmployeeData() : id(-1) { }
EmployeeData(const EmployeeData &other)
: QSharedData(other), id(other.id), name(other.name) { }
~EmployeeData() { }

int id;
QString name;
};

class Employee
{
public:
Employee() { d = new EmployeeData; }
Employee(int id, QString name) {
d = new EmployeeData;
setId(id);
setName(name);
}
Employee(const Employee &other)
: d (other.d)
{
}
void setId(int id) { d->id = id; }
void setName(QString name) { d->name = name; }

int id() const { return d->id; }
QString name() const { return d->name; }

private:
QSharedDataPointer<EmployeeData> d;
};
QT常用功能
各式無關讀取圖片
QByteArray m_photo = vCard.photo();
QBuffer buffer;
buffer.setData(m_photo);
buffer.open(QIODevice::ReadOnly);
QImageReader imageReader(&buffer);
QImage image = imageReader.read();
工程文件參數
TEMPLATE = app / lib app/ .dll

CONFIG += c++11 //支持c++11
CONFIG += link_pkgconfig
DEFINES += LOG_TO_FILE
DESTDIR = $$PWD/ //生成文件路徑
TARGET = file //目標文件名稱

OBJDIR = obj_temp
UI_DIR = $$OBJDIR/ui
RCC_DIR = $$OBJDIR/rcc
MOC_DIR = $$OBJDIR/moc
OBJECTS_DIR = $$OBJDIR/obj

INCLUDEPATH += $$PWD/include //頭文件路徑
DEPENDPATH += $$PWD/include //文件搜索路徑

CONFIG += resources_big //存儲大資源文件

QMAKE_CXXFLAGS += -Wno-unused-parameter -Wno-unused-variable //消除編譯時沒有使用參數和變量的警告

CONFIG(debug, debug|release) {
LIBS += -L$$[QT_INSTALL_BINS] -lQt5Solutions_SingleApplication-headd
} else {
LIBS += -L$$[QT_INSTALL_BINS] -lQt5Solutions_SingleApplication-head
}
//執行系統命令
system($$[QT_INSTALL_BINS]/rcc.exe -binary $$PWD/res.qrc -o $$PWD/myresource.rcc)

RC_ICONS = Image/app.ico //應用程序圖標

//條件編譯
!win32: {

RESOURCES += \
res.qrc
}


//補充
QMAKE_RPATHDIR “運行”的時候,去找的目錄。運行的時候,要找 .so 文件
QMAKE_RPATHLINKDIR 這個也是用於“鏈接”的時候的,例如你顯示指定的需要 FOO.so,但是

FOO.so 本身是需要 BAR.so 的,后者你並沒有指定,而是 FOO.so 引用到它,這個時候,會先從 -rpath-link 給的路徑里找。

//pkg-config使用
CONFIG += link_pkgconfig
PKGCONFIG += ogg dbus-1
應用程序主題
QStyleFactory::keys() 獲取所有的 支持的風格類型
void QApplication::​setStyle(QStyle * style) 應用該風格
QStyle * QApplication::​setStyle(const QString & style)

qss換膚
QString Style::getStylesheet(const QString &filename)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
qWarning() << "Stylesheet " << filename << " not found";
return QString();
}

return resolve(file.readAll());
}
qt加載flash
1.在pro文件中加入 QT += axcontainer
2.加入頭文件
3.加入代碼

QAxWidget object;
object.setControl("{d27cdb6e-ae6d-11cf-96b8-444553540000}");
object.dynamicCall("LoadMovie(long, QString)", 0, "J:\\flash2509.swf");
object.show();
QFileIconProvider 獲取文件圖標
QFileIconProvider iconProvider;
QIcon icon=iconProvider.icon(QFileIconProvider::Folder);
qt 加載外部字體
int fontId=QFontDatabase::addApplicationFont(":/Font/fontawesome-webfont");
QStringList fontFamilies=QFontFatabase::applicationFontFamilies(fontId);
QFont font;
font.setFamily(fontFamilies.at(0));
font.setPointSize(20);
QCryptographicHash  MD5 SHA
QCryptographicHash::hash("AAA", QCryptographicHash::Md5)
處理事件循環
QCoreApplication::processEvents();
全局鼠標
QCursor::pos() //當前鼠標坐標 全局
QApplication::mouseButtons() //當前鼠標按鍵
自定義QDebug
1.重寫輸出函數
```
#include <qapplication.h>
#include <stdio.h>
#include <stdlib.h>

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
abort();
}
}

int main(int argc, char **argv)
{
qInstallMessageHandler(myMessageOutput);
QApplication app(argc, argv);
...
return app.exec();
}
```
2使用qt自帶的函數注冊輸出格式
```
qSetMessagePattern("[%{time h:mm:ss.zzz} %{if-debug}Debug%{endif}%{if-warning}Waring%{endif}%{if-critical}
Critical%{endif}%{if-fatal}Fatal%{endif}] %{file}:%{line} : %{message}");
```

//debug 過濾打印
QLoggingCategory

聲明 : Q_DECLARE_LOGGING_CATEGORY(testLog)
定義 : Q_LOGGING_CATEGORY(testLog, "test.usb")

過濾: QLoggingCategory::setFilterRules("test.usb*=true");
QLoggingCategory::setFilterRules("test.usb.debug=true");

//設置配置文件過濾
~/.config/QtProject/qtlogging.ini
[Rules]
*.debug=false
driver.usb.debug=true
//環境變量過濾
QT_LOGGING_RULES="*.debug=false;driver.usb.debug=true"

//使用
qCDebug(testLog)<<"OK";

//開啟和關閉 源代碼位置
.pro DEFINES QT_MESSAGELOGCONTEXT or QT_NO_MESSAGELOGCONTEXT.
線程池
QtConcurrent::run(QThreadPool::globalInstance(), [this](){ 實現代碼 });
QChar
QChartView *chartView = new QChartView(childWidget);
chartView->setRenderHint(QPainter::Antialiasing);

chartView->resize(childWidget->size());
int index = analysis.indexOf("名稱");

QtCharts::QChart *chart = chartView->chart();
if(chart == nullptr) {
return;
}
chart->setTheme(QtCharts::QChart::ChartThemeDark);
chart->setMargins(QMargins(0, 0, 0, 0));

if(index >= 0) {
chartView->chart()->setTitle(analysis.at(index + 1));
}

chartView->chart()->legend()->hide();


QSplineSeries *series = new QSplineSeries(chartView);
chartView->chart()->addSeries(series);

QValueAxis *axisHorizontal = new QValueAxis();
QValueAxis *axisVertical = new QValueAxis();

chartView->chart()->addAxis(axisHorizontal, Qt::AlignBottom);
chartView->chart()->addAxis(axisVertical, Qt::AlignLeft);

series->attachAxis(axisVertical);
series->attachAxis(axisHorizontal);


axisHorizontal->setTickCount(24);
axisHorizontal->setLabelFormat("%i");
axisHorizontal->setRange(0, 24);


axisVertical->setTickCount(5);
axisVertical->setRange(0, 10);


series->append(0, 23);
series->append(1, 45);
series->append(2, 123);
series->append(3, 23);

axisVertical->setRange(0, 123 + 10);
動態庫和插件
//加載動態庫 .dll .so
QLibrary myLib("mylib");
typedef void (*MyPrototype)();
MyPrototype myFunction = (MyPrototype) myLib.resolve("mysymbol");
if (myFunction)
myFunction();

//2
typedef void (*MyPrototype)();
MyPrototype myFunction = (MyPrototype) QLibrary::resolve("mylib", "mysymbol");
if (myFunction)
myFunction();


//創建插件
//1 通用插件
class GenericPlugin : public QGenericPlugin
{
Q_OBJECT
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "untitled1.json")
#endif // QT_VERSION >= 0x050000

public:
GenericPlugin(QObject *parent = nullptr);
virtual QObject* create(const QString& name, const QString &spec);
};

//插件創建

要創建插件需要如下步驟:
1. 首先聲明一個繼承QObject和 插件接口類
2. 使用Q_INTERFACES() 注冊接口到元對象系統
3. 使用Q_PLUGIN_METADATA()導出數據到元對象系統
4. 對。pro文件編譯
//動態插件
class FilterInterface
{
public:
virtual ~FilterInterface() {}

virtual QStringList filters() const = 0;
virtual QImage filterImage(const QString &filter, const QImage &image,
QWidget *parent) = 0;
};
Q_DECLARE_INTERFACE(FilterInterface, "my.fileplugin")

#include <QObject>
#include <QtPlugin>
#include <QStringList>
#include <QImage>

#include <plugandpaint/interfaces.h>

class ExtraFiltersPlugin : public QObject, public FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface" FILE "extrafilters.json")
Q_INTERFACES(FilterInterface)

public:
QStringList filters() const;
QImage filterImage(const QString &filter, const QImage &image,
QWidget *parent);
};
大小端轉換
T qFromBigEndian(T src)
T qFromBigEndian(const void *src)
void qFromBigEndian(const void *src, qsizetype count, void *dest)
T qFromLittleEndian(T src)
T qFromLittleEndian(const void *src)
void qFromLittleEndian(const void *src, qsizetype count, void *dest)
T qToBigEndian(T src)
void qToBigEndian(T src, void *dest)
void qToBigEndian(const void *src, qsizetype count, void *dest)
T qToLittleEndian(T src)
void qToLittleEndian(T src, void *dest)
void qToLittleEndian(const void *src, qsizetype count, void *dest)
 

Unuutu安裝 qt
ubuntu包地址 https://packages.ubuntu.com/focal/qt5-default

sudo apt install build-essential 編譯器
sudo apt-get install qt5-default qtdeclarative5-dev

QML module not found(QtQuick.Controls)
apt-get install qml qmlscene
apt-get install qtdeclarative5-dev
apt -y install qml-module-qtquick-controls
apt -y install qml-module-qtquick-controls2

 
Qt使用模塊代碼
qt mqtt
1 下載mqtt庫源碼 

git clone git://code.qt.io/qt/qtmqtt.git
2 進入上述文件主目錄,編譯(需要先把qt 5.12的qmake添加到環境變量中去) 

windows下
qmake
mingw32-make
mingw32-make install

linux下
qmake
make
make install

3 成功后,會在qt的 QT_INSTALL_LIBS目錄下看到mqtt的庫

4 qt 工程 pro文件添加 matt,不會報錯了

QT += mqtt

//使用
m_client = new QMqttClient(this);
m_client->setHostname(ui->lineEditHost->text());
m_client->setPort(ui->spinBoxPort->value());
m_client->setClientId("mqtt_1");
m_client->setUsername("275667");
m_client->setPassword("");
m_client->connectToHost();

//接收
connect(this, &QMqttClient::messageReceived, this, [this](const QByteArray &message, const QMqttTopicName &topic){
emit MQTTProtocol::messageReceived(message, topic.name());
});
//發布
QMqttClient::publish(topic, message, qos, retain);
//訂閱
QMqttSubscription *subscription = QMqttClient::subscribe(topic, static_cast<quint8(qos));
connect(this, &QMqttClient::disconnected, subscription, &QObject::deleteLater);


//SSL連接
再main里添加 CA證書
const auto certs = QSslCertificate::fromPath("C:/Users/Administrator/Desktop/*.pem",
QSsl::Pem, QRegExp::Wildcard);
for (const QSslCertificate &cert : certs) {
QSslSocket::addDefaultCaCertificate(cert);
}
sslPeerName就是證書里面的 cert.issuerInfo(QSslCertificate::CommonName);

//連接
connectToHostEncrypted(sslPeerName);
qt xlsx
1 下載xlsx庫源碼 

git clone https://github.com/dbzhang800/QtXlsxWriter.git
2 進入上述文件主目錄,編譯(需要先把qt 5.12的qmake添加到環境變量中去) 

windows下
qmake
mingw32-make
mingw32-make install

linux下
qmake
make
make install

錯誤
C:\QtXlsxWriter\src\xlsx\xlsxzipreader.cpp:51: error: C2440: “初始化”: 無法從“QVector<QZipReader::FileInfo>”轉換為“QList<QZipReader::FileInfo>”
修改 QList為QVector


3 成功后,會在qt的 QT_INSTALL_LIBS目錄下看到xlsx的庫

4 qt 工程 pro文件添加 xlsx,不會報錯了

QT += xlsx

5 使用

QXlsx::Document xlsx;
xlsx.addSheet("在線報表");
xlsx.setColumnWidth(1, 30);
xlsx.setColumnWidth(2, 10);
xlsx.setColumnWidth(3, 30);
xlsx.setColumnWidth(4, 10);
for(int i = 0; i < model->rowCount(); i++)
{
for(int j = 0; j < model->columnCount(); j++)
{
xlsx.write(i, j + 1, model->index(i, j).data());
}
}
QString fileName = QFileDialog::getSaveFileName(this, "導出報表", QString(), "(*.xlsx)");
if(!fileName.isEmpty())
xlsx.saveAs(fileName);
qt-solutions

1 下載qt-solutions庫源碼 

git clone https://github.com/qtproject/qt-solutions.git
2 進入上述文件主目錄,編譯(需要先把qt 5.12的qmake添加到環境變量中去) 

windows下
qmake
mingw32-make
mingw32-make install

linux下
qmake
make
make install


3 成功后,會在qt的 QT_INSTALL_LIBS目錄下看到Qt5Solutions_SingleApplication-headd的庫

4 qt 工程 pro文件添加

CONFIG(debug, debug|release) {
LIBS += -L$$[QT_INSTALL_BINS] -lQt5Solutions_SingleApplication-headd
} else {
LIBS += -L$$[QT_INSTALL_BINS] -lQt5Solutions_SingleApplication-head
}

5 使用
QtSingleApplication a(argc, argv);
if(a.isRunning())
return -1;
qtcreater msvc
1 安裝qt選擇 msvc 相應選項

2 下載msvc 編譯工具
Build Tools for Visual Studio 2017 (version 15.9)

3 在 .pro中添加 msvc:QMAKE_CXXFLAGS += -execution-charset:utf-8
防止亂碼

4 開發
qt openssl支持
1.查看qt使用的 ssl庫版本
qDebug()<<QSslSocket::sslLibraryBuildVersionNumber();
qDebug()<<QSslSocket::sslLibraryBuildVersionString();

2.下載安裝openssl
如果沒有相同版本 選擇相近版本
https://slproweb.com/products/Win32OpenSSL.html
qt mapboxgl插件 linux編譯
sudo apt-get install build-essential
sudo apt-get install libicu-dev
sudo apt-get install zlib1g-dev

sudo apt-get install qt5-default
sudo apt-get install qtdeclarative5-dev
sudo apt-get install qt5-doc
sudo apt-get install qml
sudo apt-get install qtdeclarative5-private-dev
sudo apt-get install qtlocation5-dev
sudo apt-get install qtpositioning5-dev

下載 對應版本 qtlocation-everywhere-src-5.12.2.tar
復制qt頭文件到 /usr/include/x86_64/qt5 下
頭文件安裝run包獲取

解壓:

qtlocation
進入解壓目錄:
qmake
make sub-src -j4 根據自己cpu設置並行數量

完成后在 plugin下有編譯完成插件
qt 打包 Linux
下載:linuxdeployqt-x86_64.AppImage
地址: https://github.com/probonopd/linuxdeployqt/releases
inuxdeployqt-6-x86_64.AppImage

//測試
$ chmod +x linuxdeployqt-x86_64.AppImage
$ mv linuxdeployqt-x86_64.AppImage linuxdeployqt
$ mv linuxdeployqt /usr/local/bin
$ linuxdelpoyqt --version
#輸出的版本信息
linuxdeployqt 5 (commit 37631e5), build 631 built on 2019-01-25 22:47:58 UTC

//配置環境變量
#add QT ENV
export PATH=/home/Qt5.12.6/5.12.6/gcc_64/bin:$PATH
export LD_LIBRARY_PATH=/home/Qt5.12.6/5.12.6/gcc_64/lib:$LD_LIBRARY_PATH
export QT_PLUGIN_PATH=/home/Qt5.12.6/5.12.6/gcc_64/plugins:$QT_PLUGIN_PATH
export QML2_IMPORT_PATH=/home/Qt5.12.6/5.12.6/gcc_64/qml:$QML2_IMPORT_PATH
//打包

創建目錄 拷貝可執行文件到目錄 進入目錄

linuxdeployqt ./app -appimage如果提示libc太新 用下面的
linuxdeployqt ./ExcaMonitor -appimage -unsupported-allow-new-glibc

//拷貝缺少庫
plugins/
├── bearer
├── geoservices
├── imageformats
├── platforminputcontexts
├── platforms
├── position
├── sqldrivers
└── xcbglintegrations

qml
├── Qt
├── QtCanvas3D
├── QtGraphicalEffects
├── QtLocation
├── QtPositioning
├── QtQml
├── QtQuick
└── QtQuick.2

lib
├── libQt5Core.so.5
├── libQt5DBus.so.5
├── libQt5Gui.so.5
├── libQt5Location.so.5
├── libQt5Network.so.5
├── libQt5PositioningQuick.so.5
├── libQt5Positioning.so.5
├── libQt5Qml.so.5
├── libQt5QuickControls2.so.5
├── libQt5Quick.so.5
├── libQt5QuickTemplates2.so.5
├── libQt5QuickWidgets.so.5
├── libQt5SerialPort.so.5
├── libQt5Sql.so.5
├── libQt5Svg.so.5
├── libQt5VirtualKeyboard.so.5
├── libQt5Widgets.so.5
├── libQt5XcbQpa.so.5



//openssl匹配 版本一定要對應
wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1b.tar.gz
./configure
make
cp libcrypto.so* ../lib/
cp libssl.so* ../lib/


添加 run.sh
chmod +x run.sh
//內容
#!/bin/bash
export LD_LIBRARY_PATH=./lib:$LD_LIBRARY_PATH
export QT_PLUGIN_PATH=./plugins:$QT_PLUGIN_PATH
export QML2_IMPORT_PATH=./qml:$QML2_IMPORT_PATH
./AppRun

//或者添加 qt.conf
Prefix = ./
Plugins = plugins
Imports = qml
Qml2Imports = qml

//可選項
桌面圖標
#-- 全局安裝(所有用戶可用),將xxx.desktop 復制到/usr/share/applications
#-- 當前用戶可用, 將xxx.desktop 復制到 ~/.local/share/applications 目錄即可
#--appName.desktop
[Desktop Entry]
Version=1.0 #app的版本
Name=cleanRobot #app的名字
Comment= this app use for xxx #說明信息
Exec=/path/to/your/QtApp/cleanRobot #app的執行路徑,絕對路徑
Icon=/path/to/your/app_icon/cleanRobot.ico #icon 路徑,絕對路徑
Terminal=false #是否在終端啟動,效果自己試一下就知道了
Type=Application
Categories=Utility;Application;


./ExcaMonitor >> my.log 2>&1 重定向輸出到 文件

//開機自啟動
搜索
startup Application 添加啟動命令

//
vi /etc/profile
 
================ End

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM