天天看點

從零開始學Qt(68):進階!建立和使用靜态連結庫

作者:未來奇兵

建立一個靜态連結庫項目,設計各種需要導出的類,包括具有UI的窗體類、對話框類,編譯後可以生成一個lib檔案(MSVC編譯器生成字尾為“.lib”的檔案,MinGW編譯器生成字尾為“.a” 的檔案),在另一個應用程式裡使用這個lib檔案和類的頭檔案(不需要cpp源檔案),就可以靜态編譯到應用程式裡。這種方式适合于在小組開發時,每個人負責自己的部分,使用其他人設計的代碼時隻能使用而不能看到或修改源代碼,便于項目代碼的管理。

建立靜态連結庫

建立靜态連結庫項目,單擊Qt Creator的“File” 一 “New File or Project”菜單項,在出現的 “New File or Project”對話框中選擇Projects組裡的Library,在右側的具體類别中再選擇C++ Library,單擊“Choose...”按鈕後出現向導對話框。

從零開始學Qt(68):進階!建立和使用靜态連結庫

在“Location”頁面,設定“Name”給項目命名,例如myStaticLib,再選擇項目儲存目錄。

從零開始學Qt(68):進階!建立和使用靜态連結庫

在“Details”對話框的Type下拉清單框裡選擇“Statically Linked Library”,Qt Module選擇需要包含的 Qt子產品,再下一步是輸入類的名稱。本執行個體将設計的一個QPen屬性設定對話框QDialogPen作為靜态庫的導出類,是以在圖中的類定義界面上輸入的類名稱為QDialogPen,頭檔案和源程式檔案名會自動生成。單擊“Next”按鈕,直至結束即可。

從零開始學Qt(68):進階!建立和使用靜态連結庫

這樣生成的靜态庫項目myStaticLib包括3個檔案:myStaticLib.pro、qdialogpen.h和 qdialogpen.cpp。

導出類QDialogPen的設計實作

如果已經設計好了導出類QDialogPen,可以将QDialogPen 類相關的 3 個檔案 qdialogpen.h、qdialogpen.cpp 和 qdialogpen.ui複制到myStaticLib項目的源檔案目錄下,覆寫自動生成的兩個檔案,并且将qdialogpen.ui添加到項目中。

如果沒有之前沒有設計導出類,也可以現在設計。首先建立UI界面,單擊Qt Creator的“File” 一 “New File or Project”菜單項,在出現的 “New File or Project”對話框中選擇Qt組裡的Qt Designer Form,名稱設定為qdialogpen.ui。其次,完成QDialogPen類的定義和功能實作。QDialogPen類相關的3個檔案内容不是本文重點,在此不做介紹。

從零開始學Qt(68):進階!建立和使用靜态連結庫

項目配置檔案及編譯

項目配置檔案myStaticLib.pro是對本項目的設定,其内容如下:

QT += widgets
TARGET = myStaticLib
TEMPLATE = lib
CONFIG += staticlib
SOURCES += qdialogpen.cpp
HEADERS += qdialogpen.h
unix {
target.path = $[QT_INSTALL_PLUGINS]/generic
}
!isEmpty(target.path): INSTALLS += target
FORMS += qdialogpen.ui           

TEMPLATE=lib定義項目模闆是庫,而不是應用程式。

CONFIG += staticlib配置項目為靜态庫。

TARGET = myStaticLib定義項目編譯後生成的目标檔案名稱是myStaticLib。

注意靜态庫項目可以使用MinGW或MSVC編譯器編譯,但是項目編譯生成的檔案與使用的編譯器有關。若使用MSVC編譯,編譯後會生成一個庫檔案myStaticLib.lib;若使用MinGW編譯,編譯後會生成一個庫檔案 libmyStaticLib.a。

release和debug模式下編譯生成的都是相同的檔案名,并不會為debug版本自動添加一個字母“d”,但是在release和debug模式下編譯應用程式時,需要使用相應版本的庫檔案。

靜态連結庫的使用

建立一個基于QMainWindow的應用程式LibUser,在項目源程式目錄下建立一個include目錄,根據使用的編譯器複制不同的檔案。

  • 若使用MSVC編譯器,将release版本的 myStaticLib.lib複制到這個include目錄下,将debug版本的myStaticLib.lib更名為 myStaticLibd.lib複制到這個include目錄下。
  • 若使用 MinGW 編譯器,就将 libmyStaticLib.a和libmyStaticLibd.a(debug版本)複制到 include目錄裡。
  • 将靜态庫項目myStaticLib下的qdialogpen.h複制到這個include目錄下。

在項目管理目錄樹裡右鍵單擊LibUser項目,在快捷菜單裡單擊“Add Library...”菜單項,在出現的向導對話框裡首先選擇添加的庫類型為“External Library”,在向導第二步設定需要導入的靜态庫檔案(見下圖)。

從零開始學Qt(68):進階!建立和使用靜态連結庫

設定添加的靜态庫資訊

首先選擇需要導入的庫檔案myStaticLib.lib,連接配接類型裡必須選擇Static,因為這是靜态庫, 勾選Add “d” suffix for debug version,使得在debug模式下編譯應用程式時将自動調用debug版本的庫檔案myStaticLibd.lib。

設定完成後,QtCreator将自動更改項目配置檔案LibUser.pro,增加以下的内容,主要是設定 了包含檔案和依賴項的路徑,增加了LIBS設定。

win32:CONFIG(release, debug|release): LIBS += -L$PWD/include/ -lmyStaticLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$PWD/include/ -lmyStaticLibd
INCLUDEPATH += $PWD/include
DEPENDPATH += $PWD/include
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $PWD/include/libmyStaticLib.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $PWD/include/libmyStaticLibd.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $PWD/include/myStaticLib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $PWD/include/myStaticLibd.lib           

編譯應用程式LibUser,使用MSVC或MinGW編譯器,在release或debug模式下都可以編譯,運作程式效果如圖所示。單擊“設定Pen”桉鈕可以設定劃線的Pen屬性,并在主窗體上繪制一個矩形框。

從零開始學Qt(68):進階!建立和使用靜态連結庫

應用程式LibUser運作效果

主窗體程式比較簡單,MainWindow類的定義如下:

class MainWindow : public QMainWindow
{
	Q_OBJECT
private:
	QPen mPen;
public:
  MainWindow(QWidget *parent = nullptr);
  ~MainWindow();
protected:
	void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private slots:
	void on_actionPen_triggered();
private:
	Ui::MainWindow *ui;
};           

paintEvent()事件在窗體上繪制一個矩形,使用了QPen類型的私有變量mPen作為繪圖的畫筆。action_Pen的響應代碼調用靜态庫裡的QDialogPen的靜态函數getPen設定畫筆屬性。

void MainWindow::paintEvent(QPaintEvent *event)
{ // 繪圖
  Q_UNUSED(event);
  QPainter painter(this);
  QRect rect(0,0,width(),height()); // viewport 矩形區
  painter.setViewport(rect);// 設定 Viewport
  painter.setWindow(0, 0, 100,50);// 設定視窗大小,邏輯坐标
  painter.setPen(mPen);
  painter.drawRect(10,10,80,30);
}
void MainWindow::on_actionPen_triggered()
{ // 設定Pen
  bool ok=false;
  QPen pen=QDialogPen::getPen(mPen,ok);
  if(ok){
    mPen=pen;
    this->repaint();
	}
}           

本執行個體将一個可視化設計的對話框QDialogPen封裝到一個靜态庫裡,也可以将任何C++類、函數封裝到靜态庫,其實作方法是一樣的。

繼續閱讀