Qt開發經驗小技巧271-275

  1. 編程的過程中經常遇到需要將QString轉成char *或者const char *的情況,在轉換成QByteArray後調用.data()或者.constData()函數進行轉換,這裏需要注意的是,如果轉換類型是const char *儘管用data()不會出錯,會給你自動轉換,但是還是不建議,因爲深拷貝了一份,理論上增加了內存開銷,如果字符串長度小還好,一旦很長,這個開銷挺大,這是個好的編程習慣。
//查閱代碼得知data函數有兩個重載
inline char *QByteArray::data()
{ detach(); return d->data(); }
inline const char *QByteArray::data() const
{ return d->data(); }
inline const char *QByteArray::constData() const
{ return d->data(); }

QByteArray data = "abc";
//深拷貝
char *d1 = data.data();
//深拷貝
const char *d2 = data.data();
//淺拷貝
const char *d3 = data.constData();

//深拷貝
test(data.data());
//淺拷貝
test(data.constData());
void test(const char *data)
{    
}

//至於什麼時候調用.data()會淺拷貝,酷碼大佬說是當QByteArray被const修飾的時候
const QByteArray data;
//淺拷貝
const char *d = data.data();

//酷碼大佬補充:自Qt 5.7版本以來,引入了qAsConst函數,專用於無腦轉換。
//這個函數實現了C++17標準中的std::as_const()函數的功能,將一個非常量的左值轉爲常量的左值。
//增加qAsConst函數是爲了Qt自己的非const 的容器能實現C++11標準的基於範圍的循環。
//該函數主要用於qt容器在隱式共享中不被detach。
QString s = "abc";
//下面會深拷貝引起性能損失
for (QChar ch : s)
//不會深拷貝
for (QChar ch : qAsConst(s))
//下面也是淺拷貝,但是在編程時、在現實中,聲明爲const往往不容易做到。
const QString s;
for (QChar ch : s)

//總結:對Qt自己實現的容器如:QVector、QMap、 QHash、QLinkedList、QList等,如果一定要用基於for(var : container)範圍的循環,則請用如下形式:
for (var : qAsConst(container))
  1. 新版的Qt6.5在ubuntu上編譯運行程序後會提示 qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. ,無法正常彈出窗體程序,你需要主動安裝xcb的相關庫。sudo apt install libxcb*

  2. 有些場景下我們需要在 QApplication a(argc, argv); 前面執行一些處理,比如 QApplication::setAttribute 就必須在最前面執行,而很多時候這個設置的參數不能改寫死,畢竟現場的環境千差萬別,希望通過配置文件來配置,那麼問題來了,讀取配置文件一般需要指定路徑才能正常讀取到,如果是 ./ 這種,很可能未必是應用程序的當前路徑,如果你是雙擊運行的程序,那肯定是應用程序的當前路徑,不是雙擊運行那就是系統環境中的當前路徑,意味着你開機啓動或者用system、QProcess等方式在開機後調用啓動的話,就未必正確了。爲了保證這個路徑的正確,必須從main函數的 argv 第一個值獲取,通過查閱Qt自身代碼中獲取路徑,也是從這個參數獲取。

//程序最前面獲取應用程序路徑和名稱
static void getCurrentInfo(char *argv[], QString &path, QString &name);
//程序最前面讀取配置文件節點的值
static QString getIniValue(const QString &fileName, const QString &key);
static QString getIniValue(char *argv[], const QString &key, const QString &dir = QString());

void QUIHelper::getCurrentInfo(char *argv[], QString &path, QString &name)
{
    //必須用fromLocal8Bit保證中文路徑正常
    QString argv0 = QString::fromLocal8Bit(argv[0]);
    QFileInfo file(argv0);
    path = file.path();
    name = file.baseName();
}

QString QUIHelper::getIniValue(const QString &fileName, const QString &key)
{
    QString value;
    QFile file(fileName);
    if (file.open(QFile::ReadOnly | QFile::Text)) {
        while (!file.atEnd()) {
            QString line = file.readLine();
            if (line.startsWith(key)) {
                line = line.replace("\n", "");
                line = line.trimmed();
                value = line.split("=").last();
                break;
            }
        }
    }
    return value;
}

QString QUIHelper::getIniValue(char *argv[], const QString &key, const QString &dir)
{
    QString path, name;
    QUIHelper::getCurrentInfo(argv, path, name);
    QString fileName = QString("%1/%2%3.ini").arg(path).arg(dir).arg(name);
    return getIniValue(fileName, key);
}

int main(int argc, char *argv[])
{
    int openGLType = QUIHelper::getIniValue(argv, "OpenGLType").toInt();
    QUIHelper::initOpenGL(openGLType);
    QApplication a(argc, argv);
    ...
}
  1. 當我們對QTableView/QTreeView/QTableWidget/QTreeWidget某行選中後,會發現某些單元格設置的前景色被覆蓋了,比如設置的紅色,一旦選中就變成了白色,這肯定不是我們想要的,需要用自定義委託將其去掉。
class ItemDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit ItemDelegate(QObject *parent = 0);

protected:
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

#include "itemdelegate.h"

ItemDelegate::ItemDelegate(QObject *parent) : QItemDelegate(parent)
{

}

void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem option2 = option;
    QColor color = index.data(Qt::ForegroundRole).value<QColor>();
    if (color.isValid() && color != option.palette.color(QPalette::WindowText)) {
        option2.palette.setColor(QPalette::HighlightedText, color);
    }

    QItemDelegate::paint(painter, option2, index);
}

//對所有單元格設置該委託
ui->tableWidget->setItemDelegate(new ItemDelegate);
  1. 有些時候我們需要在項目文件比如pro/pri中識別當前Qt套件是否存在某個模塊以及是否引入過某個模塊,存在則引入,同時也希望代碼中也能識別是否引入過某個模塊比如sql模塊,判斷後再進行對應的處理。
//項目文件中判斷
//如果當前套件中有multimedia模塊則引入multimedia模塊
qtHaveModule(multimedia) {QT += multimedia}
//在項目文件中已經通過 QT += multimedia 引入過模塊
contains(QT, multimedia) {}

//代碼文件判斷
#ifdef QT_MULTIMEDIA_LIB
    qDebug() << "multimedia module is enabled";
#else
    qDebug() << "multimedia module is not enabled";
#endif

國內站點:https://gitee.com/feiyangqingyun
國際站點:https://github.com/feiyangqingyun

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章