【Qt设计开发】GUI界面设计开发
文章目錄
- 一、Qt簡介和下載安裝
- 二、Qt入門
- 2.1 創建第一個項目
- 2.2 快捷鍵和命名規范
- 2.3 Qt項目和VS2022項目相互轉換
- 三、Qt基礎
- 3.1 Qt對象樹和窗口坐標系概念
- 3.2 QPushButton
- 3.3 信號和槽(signals and slots)
- 3.3.1 pushbutton關閉窗口
- 3.3.2 自定義信號和槽
- 3.4 Lambda表達式
- 3.5 菜單欄工具欄的創建
- 3.6 資源文件添加和UI界面使用
- 3.7 對話框
- 3.7.1 模態和非模態
- 3.7.2 消息對話框
- 3.8 設計登錄界面
- 3.9 各類控件
- 3.9.1 按鈕組
- 3.9.2 QTreeWidget和QTableWidget控件
- 3.9.3 其他控件
- 3.9.4 自定義控件封裝
- 3.10 鼠標和定時器事件以及事件分發器、過濾器
- 3.11 繪畫
- 3.11.1 繪畫設置
- 3.11.2 繪圖設備
- 3.12 文件讀取
- 四、翻金幣小游戲
- 4.1 出現的問題
- 4.2 源碼下載
- 4.3 NSIS打包程序
??本文是我在學習QT的GUI界面設計過程當中的心得和學習筆記,在學習時已經有C, C++,Python的基礎。文章附上了學習的代碼,僅供大家參考。如果有問題,有錯誤歡迎大家留言。此外,博主還有另外幾篇文章,分別關于 Python基礎知識、 Python的具體應用、 C語言指針結構體的難點、 C++入門和進階知識點和 C++高階知識點,大家點擊即可翻閱。
一、Qt簡介和下載安裝
??Qt是一個1991年由Qt Company開發的跨平臺C++圖形用戶界面(Graphic User Interface, GUI)應用程序開發框架。QT包括但不僅限于GUI的開發,也包含了諸如系統調用、網絡編程、數據庫編程,2D/3D圖形處理等等。QT具有強大的跨平臺運行的性能,幾乎囊括了所有的操作系統,例如Linux、Windows、Mac OS、Android、IOS。我們所熟知的金山WPS、Google Earth谷歌地圖、SKype網絡電話就是用Qt開發的。
??博主使用的版本是Qt 5.14.2, 下載、安裝 參照B站視頻。
二、Qt入門
2.1 創建第一個項目
??第一步,選擇new->Application->Qt Widgets Application->Choose:
??第二步,修改項目名稱和項目路徑,點擊下一步。
??第三步,修改類名稱,其中基類有三種,分別是QMainWindow(菜單類), QWidget, QDialog(對話框類)。表示創建的類繼承于基類。QDialog和QMainWindow是QWidget的子類。QMainWindow是菜單類,左上角有一些菜單選項,右上角有最小化最大化按鈕。QDialog是對話框類,下圖所示就是一個對話框類。
??第四步,選擇MinGW 64-bit 編譯器,32位和64位的區別在于32位能在64位的機器上跑,64位不能在32位的機器上跑,初始項目選擇任意一個就可以,點擊下一步,然后在點擊完成,就可以產生一個名為Qt_test的項目,項目底下有一個Qt_test.pro的項目文件。
??之后的步驟默認就可以,一直點下一步,然后編譯運行,出現一個空白窗口,創建完畢。
??編譯成功后,會在項目目錄底下生成build文件,然后點擊debug文件,里面有生成的.exe可執行文件,點擊即可運行,結果就是一個空白圖窗。博主在運行.exe的時候碰到了錯誤彈窗,顯示程序“無法找到入口”,添加了環境變量之后還需要將環境變量上移,具體解決參考這里。
# QT_hello.pro文件 QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgets# 版本大于4以上的添加widgets模塊CONFIG += c++11 # 用C++11標準來解釋代碼# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mywidget.cppHEADERS += \mywidget.hTARGET = UAV # 生成的.exe文件名稱 TEMPLATE = app # 應用程序模板 Application # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target // mywidget.h文件 #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> class mywidget : public QWidget // 公共繼承 {Q_OBJECT // Q_OBJECT宏,允許類中使用信號和槽的機制public:mywidget(QWidget *parent = nullptr); // 構造函數~mywidget(); // 析構函數 }; #endif // MYWIDGET_H // main.cpp文件 # include <QApplication> # include <QtWidgets> # include <QDebug> // main程序入口 argc命令行變量數量, argv命令行變量的數組 int main(int argc, char *argv[]) {QApplication a(argc, argv); // 應用程序對象, 在QT中,應用程序對象有且僅有一個 mywidget w; // 窗口對象 mywidget是Qwidget的子類w.show(); // show方法, 窗口對象默認不會顯示qDebug()<<"hello world"; // 在控制臺輸出, 用于調試 return a.exec(); // 讓應用程序對象進入消息循環 } // mywidget.cpp文件 #include "mywidget.h" mywidget::mywidget(QWidget *parent): QWidget(parent) { } mywidget::~mywidget() { }2.2 快捷鍵和命名規范
??QT如下,可以提高編碼效率:
/* 快捷鍵* 運行代碼: Ctrl + r* 編譯: Ctrl + b* 注釋: Ctrl + /* 縮放字體:Ctrl + 滾輪* 查找/替換字體: Ctrl + f* 整行移動代碼: Ctrl + Shift + 上/下鍵* 自動對齊:Ctrl + i* 在同名文件和源文件之間切換: F4* 快速添加函數定義:鼠標移到聲明的那一行,按Alt + Enter* 修改變量名,并應用到所有:Ctrl + Shift + r* 快捷打開輸出窗口: Alt + number(1-8)* 書簽功能: 快速跳到代碼* Ctrl + M 添加/刪除標簽* Ctrl + . 查找并移動到下一個標簽處* 查看幫助文檔:* 第一種:Qt Creator 查看 F1* 第二種:獨立的幫助文檔程序查看 *//* 類名: 首字母大寫,單詞和單詞之間首字母大寫 函數名和變量名稱: 首字母小寫,單詞和單詞之間首字母大寫 */??Qt設計師創建的文件后綴為.ui, 無法直接運用到C++中,因此引入一個uic工具,可以將.ui文件轉換為.c文件。rcc moc同樣是這樣類型的工具,將一些qt文件轉換成C++語法格式的文件。
2.3 Qt項目和VS2022項目相互轉換
??博主最近需要使用QT和VS 2022聯合編程,大家有需要也可以參考視頻 VS項目和QT項目相互轉換。
??使用VS2022創建的QT項目,輸出為.pro文件,利用Qt createor打開,需要在.pro文件中加載模塊(添加如下代碼),因為VS2022是在項目配置的時候加載的。如下圖所示。
# ---------------------------------------------------- # This file is generated by the Qt Visual Studio Tools. # ------------------------------------------------------QT += core gui widgets # 模塊加載, 使用VS2022創建的項目,輸出為.pro文件,利用Qt createor打開,需要在.pro文件中加載模塊 # 因為VS2022是在項目配置的時候加載的。TEMPLATE = app TARGET = QtWidgetsTest########################################## # 以下代碼可以不要 DESTDIR = ../x64/Debug CONFIG += debug LIBS += -L"." DEPENDPATH += . MOC_DIR += GeneratedFiles/$(ConfigurationName) OBJECTS_DIR += debug UI_DIR += GeneratedFiles RCC_DIR += GeneratedFiles ########################################### HEADERS += ./qtwidgetstest.h SOURCES += ./qtwidgetstest.cpp \./main.cpp FORMS += ./qtwidgetstest.ui RESOURCES += qtwidgetstest.qrc w.setWindowTitle(u8"VS2022 QT 窗口"); // 不亂碼/* 產生亂碼, 英文不會有亂碼,英文編碼格式都是同意的ASCII,QT中文編碼格式是UTF-8,windows中文編碼格式是GB2312,u8為轉換成UTF-8,QT就可以識別了 */三、Qt基礎
3.1 Qt對象樹和窗口坐標系概念
??當創建的對象在堆區的時候,如果指定的父親是QObject派生下來的類或者QObject子類派生下來的類,可以不用管理釋放操作,QT會對象會放入到對象樹中,會自動釋放內存,一定程度上簡化了內存回收機制。這也是QT的優點之一,因此,我們在構造時候就指定parent對象,就不需要操心內存釋放問題。
??以左上角頂點為原點(0, 0),X向右增加,Y向下增加。對于嵌套窗口,其坐標系是相對于父窗口而言。
3.2 QPushButton
??在編寫這部分代碼時,博主的編輯器竟然沒有代碼補全功能,于是又在網上找了解決辦法,這里給出鏈接。
??在學習QT的各種類的過程中,最重要的是學會如何查找幫助文檔以及看懂幫助文檔。例如QPushButton類,幫助文檔中給出詳細解釋:添加頭文件,同時要在.pro文件中加入widgets模塊,其父類是QAbstractButton,其子類是QCommandLinkButton等等信息。
3.3 信號和槽(signals and slots)
3.3.1 pushbutton關閉窗口
??引入一個連接函數connect( ),將信號發送者和信號接收者鏈接起來。connect( )一共有四個參數:
????參數1:信號發送者;
????參數2:發送的信號(函數地址);
????參數3:信號接收者;
????參數4:處理的槽函數(函數地址)。
??在空白項目的基礎上改寫mywidget.cpp函數,實現點擊按鈕,關閉窗口案例:
3.3.2 自定義信號和槽
??創建一個下課,老師餓了,學生請客的案例。添加自定義的老師類和學生類,選擇C++類,這個兩個類不是窗口類,直接繼承QObject類。分別產生了teacher和student的.cpp .h文件。
??頭文件中定義,變量名稱和函數聲明,在.cpp文件中寫實現。
// mywidget.h #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget> # include "teacher.h" # include "student.h"class mywidget : public QWidget // 公共繼承 {Q_OBJECT // Q_OBJECT宏,允許類中使用信號和槽的機制public:mywidget(QWidget *parent = nullptr); // 構造函數~mywidget(); // 析構函數Teacher *t; // 在頭文件中聲明變量和函數Student *s;void ClassIsOver(); }; #endif // MYWIDGET_H // student.h #ifndef STUDENT_H #define STUDENT_H#include <QObject>class Student : public QObject {Q_OBJECT public:explicit Student(QObject *parent = nullptr);signals:public slots:/* 早期的QT版本必須要寫到,public slots,高級版本可以寫到public或全局下* 返回值void,需要聲明,也需要實現* 可以有參數,可以發生重載*/void treat();void treat(QString foodName); };#endif // STUDENT_H // teacher.h #ifndef TEACHER_H #define TEACHER_H#include <QObject>class Teacher : public QObject {Q_OBJECT public:explicit Teacher(QObject *parent = nullptr);signals:/* 自定義信號類,沒有返回值* 只需要聲明,不需要實現* 可以有參數,可以重載*/void hungry();void hungry(QString foodName); public slots:/* 早期的QT版本必須要寫到,public slots,高級版本可以寫到public或全局下* 返回值void,需要聲明,也需要實現* 可以有參數,可以發生重載*/ };#endif // TEACHER_H // mywidget.cpp # include "mywidget.h" # include <QPushButton> # include <QDebug>mywidget::mywidget(QWidget *parent): QWidget(parent) {// 創建老師和學生對象this->t = new Teacher(this);this->s = new Student(this);// 無參 // //ClassIsOver(); // 調用下課函數 沒有鏈接,沒有任何響應 // connect(t,&Teacher::hungry, s, &Student::treat); // 先鏈接后觸發信號,才能響應 // ClassIsOver(); // 調用下課函數// 鏈接代參數的函數,void (Teacher:: *f1)(QString) = &Teacher::hungry;void (Student:: *f2)(QString) = &Student::treat;// connect(t,f1, s, f2); // 因為發生了函數重載,不能簡單的用取地址符,編譯器判斷不了是哪個函數,用函數指針ClassIsOver(); // 調用下課函數// 點擊一個按鈕, 觸發下課QPushButton *btn = new QPushButton("下課",this);this->resize(800,600); // 重置窗口大小connect(btn,&QPushButton::clicked,this, &mywidget::ClassIsOver);// disconnect(btn,&QPushButton::clicked,this, &mywidget::ClassIsOver); // 斷開鏈接/* 1、信號可以鏈接信號* 2、一個信號可以鏈接到多個槽函數* 3、多個信號可以鏈接到一個槽函數* 4、信號和槽函數的參數必須類型一一對應(槽函數要接收信號的參數)* 5、信號參數個數可以多于槽函數參數個數,但是類型也要一一對應*/// QT5 6 向下兼容 QT4版本以前的信號和槽的鏈接方式connect(t,SIGNAL(hungry()), s, SLOT(treat(QString))); // 優點,直觀,缺點,類型不做檢測 }mywidget::~mywidget() {}void mywidget::ClassIsOver() {// emit t->hungry();emit t->hungry("宮保雞丁"); } // student.cpp #include "student.h" # include <QDebug> Student::Student(QObject *parent) : QObject(parent) {} void Student::treat() {qDebug() << "請老師吃飯"; } void Student::treat(QString foodName) {// qDebug() << "請老師吃 :" << foodName; // 帶引號,用toUtf8()先將它轉成QbyteArray類型,然后用data()在轉成char *類型qDebug() << "請老師吃 :" << foodName.toUtf8().data(); }??main.cpp和teacher.cpp默認即可。信號和槽使用時必須先鏈接后觸發信號,才能響應。
3.4 Lambda表達式
??Lambda表達式是C++11中用來定義并創建匿名的函數對象。實際上是一個匿名方法,用來聲明一個只在此次使用的匿名函數。
[函數對象參數](操作符重載函數參數)mutable->返回值(函數體)
- 1、函數對象參數:[],標識一個lambda的開始,這部分不能省略。函數對象參數是傳遞給編譯器自動生成的函數對象類的構迨函數。函數對象參數只能使用那些到定義Lambda 為止時Lambda所在作用范圍內可見的局部變量(包括Lambda所在類的this)。函數對象參數有以下幾種形式:
| 空 | 沒有使用任何函數對象參數 |
| = | 函數體可以使用lambda所在作用范圍內所有可見的局部變量 |
| this | 函數體可以使用lambda所在類中的成員變量 |
| a | 將a按值進行傳遞 |
| &a | 將a按引用進行傳遞 |
| a, &b | 將a按值傳遞,b按引用傳遞 |
| =, &a, &b | 除a b按引用傳遞外,其余值按值進行傳遞 |
| &, a, b | 除a b按值進行傳遞外,其余值按引用進行傳遞 |
??其中=傳遞了包括Lambda所在類的this,并且是引用傳遞方式,相當于編譯器自動為我們引用傳遞了所有局部變量。按值進行傳遞時,函數體內不能修改傳遞進來的a的拷貝,因為默認情況下函數是const的。要修改傳遞進來的a的拷貝,可以添加mutable修飾符。
- 2、操作符重載函數參數:標識函數重載的()參數,沒有參數時,可以省略。參數可以用過按值傳遞和按引用兩種方式進行傳遞。
- 3、可修改標識符:mutable聲明,這部分可以省略。按值傳遞函數對象參數時,加上mutable修飾符,可以修改按值傳遞進來的拷貝(注意僅僅是能修改拷貝, 而不是修改值本身)
- 4、函數返回值:->返回值類型, 標識函數返回值的類型,當返回值為void,或者函數體中只有溢出return的地方(此時編譯器可以自動推斷出返回值類型)時,這部分可以省略。
- 5、函數體: {},標識函數的實現,這部分不能省略,但函數體可以為空。
??在空項目的基礎之上改變mywidget.cpp函數:
#include "mywidget.h" #include <QPushButton> mywidget::mywidget(QWidget *parent): QWidget(parent) {// 利用lambda表達式,點擊按鈕,關閉窗口QPushButton *btn = new QPushButton("關閉", this);btn->move(100,100);connect(btn,&QPushButton::clicked,this, [=](){this->close();}); }mywidget::~mywidget() { }3.5 菜單欄工具欄的創建
??在空項目的基礎之上改變mywidget.cpp函數:
#include "mainwindow.h" #include <QPushButton> #include <QMenuBar> #include <QToolBar> #include <QStatusBar> #include <QDockWidget> #include <QLabel> #include <QTextEdit>#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {resize(1400,900); // 重置窗口大小/********** 菜單欄創建 **********/QMenuBar *bar = menuBar();setMenuBar(bar); // 將菜單欄放置到窗口中QMenu *fileMenu = bar->addMenu("文件"); // 創建菜單QMenu *editMenu = bar->addMenu("編輯"); // 創建菜單QAction *newAction = fileMenu->addAction("新建");fileMenu->addSeparator(); // 添加分隔線QAction *openAction = fileMenu->addAction("打開");/********** 工具欄創建 **********/QToolBar *toolBar = new QToolBar(this); // 工具欄,可以有多個addToolBar(Qt::LeftToolBarArea, toolBar);toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);// 后期設置只允許左右停靠toolBar->setFloatable(false);// 設置浮動toolBar->setMovable(false); // 允許移動(總開關)toolBar->addAction(newAction);toolBar->addSeparator();toolBar->addAction(openAction);QPushButton *btn = new QPushButton("aaa",this);toolBar->addWidget(btn);/********** 狀態欄創建,最多一個 **********/QStatusBar *stBar = statusBar();setStatusBar(stBar);QLabel *label = new QLabel("提示信息",this);stBar->addWidget(label);QLabel *label2 = new QLabel("右側提示信息",this);stBar->addPermanentWidget(label2);/********** 鉚接部件(浮動窗口,可以有多個)**********/QDockWidget *dockWidget = new QDockWidget("浮動窗口",this);addDockWidget(Qt::BottomDockWidgetArea,dockWidget);dockWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); // 設置停靠區域,只允許上下/********** 設置中心部件,只能有一個 **********/QTextEdit *edit = new QTextEdit(this);setCentralWidget(edit);/*總結: 使用set加入窗口的部件智能有一個,而add加入的能有多個*/ }MainWindow::~MainWindow() { }3.6 資源文件添加和UI界面使用
??在新建空白項目的第三步點擊generate form,生成項目后就會產生一個.ui文件。UI界面可以直接拖拽控件,輸入文本,我們開發窗口應用就變得很方便。
??在此界面的基礎上,創建文件,編輯,工具,幫助等菜單,菜單的一級目錄是無法鍵入中文的,只能輸入英文,然后在創建好的對象中將文本改成中文,建立完成后的文件如下。點擊項目添加文件,add new file -> Qt -> Qt resource file -> choose,然后更改文件名稱,一般設置為res,然后會在Resources底下生成一個res.qrc的文件。
??將圖片復制到項目目錄底下的Image文件(所有圖片文件都放進去),以資源編輯器的方式打開res.qrc,添加前綴(可以直接使用默認或者“/”),添加文件,使用“ : + 前綴名 + 文件名稱” 。mainwindow.cpp文件如下所示:
// mainwindow.cpp文件 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this); // ui->actionnew->setIcon(QIcon("C:/Users/19080/Pictures/Camera Roll/文件圖標.JPEG") ); // 絕對路徑// 使用添加Qt資源文件ui->actionnew->setIcon(QIcon(":Image\\fileIcon.JPEG") ); ui->actionopen->setIcon(QIcon(":Image\\Luffy.jpg") ); }MainWindow::~MainWindow() {delete ui; }3.7 對話框
3.7.1 模態和非模態
??mainwindow.cpp文件如下所示:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDialog> #include <QDebug> MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// 點擊新建按鈕 彈出一個對話框connect(ui->actionnew,&QAction::triggered,[=](){/* 對話框 分類* 模態對話框(不可以對其他窗口進行操作) 非模態對話框則相反*//* 模態創建 阻塞 */ // QDialog dig(this); // dig.resize(200,100); // dig.exec(); // qDebug() <<"模態對話框彈出";/* 非模態創建 */QDialog *dig2 = new QDialog(this);dig2->resize(200,100);dig2->show();dig2->setAttribute(Qt::WA_DeleteOnClose); // 55號屬性qDebug() << "非模態對話框彈出";});}MainWindow::~MainWindow() {delete ui; }3.7.2 消息對話框
??目前Qt內置對話框有:
| QColorDialog | 選擇顏色 |
| QFileDialog | 選擇文件或者目錄 |
| QFontDialog | 選擇字體 |
| QInputDialog | 允許用戶輸入一個值,并將值返回 |
| QMessageBox | 模態對話框,用于顯示信息、詢問信息等等 |
| QPageSetupDialog | 為打印機提供紙張相關的選項 |
| QPrintDialog | 打印機配置 |
| QPrintPreviewDialog | 打印預覽 |
| QProgressDialog | 顯示操作過程 |
??mainwindow.cpp文件如下所示,其中QMessageBox::question的返回值是QMessageBox::StandardButton類型,我們就可以利用if語句去判斷返回值是否為QMessageBox::Save,從而進一步做其他操作。
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDialog> #include <QMessageBox> #include <QDebug> #include <QColorDialog> #include <QFileDialog> #include <QFontDialog> MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);connect(ui->actionnew,&QAction::triggered,[=](){// 錯誤對話框 // QMessageBox::critical(this, "critical", "錯誤");// 信息對話框 // QMessageBox::information(this, "info", "信息");// 提問對話框 參數1:父類,參數2:title, 參數3:提示信息, 參數4:按鍵選項, 參數5: 默認選項(關聯回車選項) // if(QMessageBox::Save == QMessageBox::question(this, "ques", "提問",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Save)) // { // qDebug() << "選擇的是保存"; // } // else // { // qDebug() << "選擇的是取消"; // }// 警告對話框//QMessageBox::warning(this,"warning","警告");// 其他標準對話框// 顏色對話框 // QColor color = QColorDialog::getColor(QColor(255, 0, 0)); // qDebug() << " r = " << color.red() << " g = "<< color.green() << " b = " << color.blue();// 文件對話框 參數1: 父類, 參數2: 對話框標題 參數3:默認打開路徑,參數4:過濾器(僅能選取該類型文件) 返回值是選取文件路徑 // QString str= QFileDialog::getOpenFileName(this, "打開文件", "C:\\Users\\19080\\Desktop", "(*.txt)"); // qDebug() << str;// 字體對話框bool flag;QFont font = QFontDialog::getFont(&flag, QFont("華文云彩", 36) );qDebug() <<" 字體: "<< font.family() <<" 大小:"<< font.pointSize()<< "是否加粗:"<< font.bold() << "是否傾斜:"<< font.italic();});}MainWindow::~MainWindow() {delete ui; }3.8 設計登錄界面
??首先我們現在UI界面創建如下控件,用戶名和密碼用Label控件,輸入框用Line Edit控件,登錄和退出用PushButton控件。
??然后在左側工具欄Containers中選擇Widget控件,將用戶名、密碼和輸入框拖入Widget中選擇,在上方工具欄中選擇柵格布局(適用于多行多列的,如果是單行或單列可以選擇水平布局或垂直布局),布局之后就變得更整齊。登錄和退出就選擇水平布局。為了在窗口縮放是保持各個空間的相對位置不變,可以加入Spacers控件(也可以不加),其效果于彈簧。
??登錄界面一般開發時就確定大小,我們找到MainWindow->sizePolicy->水平和垂直策略都選擇Fixed,然后將minnumSize和maxiumSize都選擇固定的尺寸(具體數值任意,大小合適即可)。操作完畢后窗口大小就固定下來。
??最后修改窗口名稱,選中密碼對應的編輯框,QLineEdit->echoMode->Password(輸入密碼的編程一個個黑圈圈),到目前為止我們將登錄窗口的UI界面設計完畢,但是具體的功能還需要底層代碼才能實現。
3.9 各類控件
3.9.1 按鈕組
??Qt的UI設計界面的按鈕組有:PushButton,ToolButton, Radio Button, Check Box等等。
??ToolButton建立后,可以添加圖片和修改文本,選擇Icon->選擇資源文件(前面部分有介紹),然后選擇QToolButton->autoRaise,其效果是當光標移動到該按鈕時,按鈕自動高光亮起。
??依次創建4個Radio Button,分別命名為男 女, 已婚, 未婚。然后添加Group Box, 將男女添加今一個Group Box, 修改文本為性別。同理,已婚和未婚這兩個Radio Button為另外一組。
??創建4個Check Box依次修改文本,放入Group Box中,設置垂直布局。然后在添加一個ListWidget,在預覽圖中顯示為白色框。
??在mainwindow.cpp中輸入如下代碼,形成代碼和界面的聯動:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// 設置單選按鈕 默認男選中ui->radioButton->setChecked(true);// 選中女后打印信息connect(ui->radioButton_2, &QRadioButton::clicked,[=](){qDebug() << "選中了女性按鈕";});// 多選按鈕 2:選中 1:半選中 0:未選中// 信號為stateChanged, 槽函數為lambda表達式, 信號的參數會自動傳給槽函數connect(ui->checkBox_4, &QCheckBox::stateChanged,[=](int state){qDebug() << state;});// 利用listWidget寫詩QListWidgetItem *item = new QListWidgetItem("窗前明月光");// 將一行詩放到listWidget控件中ui->listWidget->addItem(item);item->setTextAlignment(Qt::AlignHCenter); // 設置為水平居中// QStringList QList<QString>QStringList list;list << "疑是地上霜"<< "舉頭望明月"<<"低頭思故鄉"; // 將這幾句詩加入鏈表類中ui->listWidget->addItems(list); // 這種方法無法設置對齊格式 }MainWindow::~MainWindow() {delete ui; }3.9.2 QTreeWidget和QTableWidget控件
??QTreeWidget控件代碼如下:
#include "widget.h" #include "ui_widget.h" #include <QDebug> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// treeWidget樹控件使用// 設置水平頭// 從下面兩行代碼可以看出,str相當于一個string類型的列表(例如,vector<string>) <<操作符相當于 append()函數的作用 // QStringList str = QStringList()<<"英雄"<<"英雄介紹"; // qDebug() << str;ui->treeWidget->setHeaderLabels (QStringList()<<"卡牌類型"<<"卡牌介紹");QTreeWidgetItem *monster = new QTreeWidgetItem(QStringList()<< " 怪獸");QTreeWidgetItem *magic = new QTreeWidgetItem(QStringList()<< " 魔法");QTreeWidgetItem *trap = new QTreeWidgetItem(QStringList()<< " 陷阱");// 加載頂層節點ui->treeWidget->addTopLevelItem(monster);ui->treeWidget->addTopLevelItem(magic);ui->treeWidget->addTopLevelItem(trap);// 加載子節點QStringList m1 = QStringList()<< "增殖的G"<< "效果怪獸,每次對方對怪獸的特殊召喚成功,自己從卡組抽1張";QTreeWidgetItem *monster1 = new QTreeWidgetItem(m1);monster->addChild(monster1);QStringList m2 = QStringList()<< "效果遮蒙者"<< "效果怪獸,以對方場上1只效果怪獸為對象,其效果直到回合結束時無效。";QTreeWidgetItem *monster2 = new QTreeWidgetItem(m2);monster->addChild(monster2);QStringList ma1 = QStringList()<< "強欲之壺"<< "通常魔法,從卡組抽兩張牌";QTreeWidgetItem *magic1 = new QTreeWidgetItem(ma1);magic->addChild(magic1);QStringList ma2 = QStringList()<< "天使的施舍"<< "通常魔法,從卡組抽三張,然后丟棄兩張手牌";QTreeWidgetItem *magic2 = new QTreeWidgetItem(ma2);magic->addChild(magic2);QStringList t1 = QStringList()<< "技能抽取"<< "永續陷阱,能夠使場上表側表示的怪獸卡效果無效";QTreeWidgetItem *trap1 = new QTreeWidgetItem(t1);trap->addChild(trap1);QStringList t2 = QStringList()<< "王宮的敕命"<< "永續陷阱,能夠使場上的魔法卡效果無效";QTreeWidgetItem *trap2 = new QTreeWidgetItem(t2);trap->addChild(trap2); }Widget::~Widget() {delete ui; }??效果圖:
??QTableWidget控件
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// TableWidget控件// 設置列數,一定要設置,不然會出現未知錯誤ui->tableWidget->setColumnCount(3);// 設置水平表頭ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性別"<<"年齡");// 設置行數ui->tableWidget->setRowCount(5);// 設置正文//ui->tableWidget->setItem(0,0,new QTableWidgetItem("張三"));QStringList nameList = QStringList()<<"李大"<<"柳二"<<"張三"<<"劉四"<<"王五";QStringList sexList = QStringList()<<"男"<<"男"<<"女"<<"女"<<"女";for(int i=0;i<5;i++){int col = 0;ui->tableWidget->setItem(i,col++,new QTableWidgetItem(nameList[i]));ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sexList.at(i)));ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(i+18)));} }Widget::~Widget() {delete ui; }??效果圖:
3.9.3 其他控件
??主要包括了scroll area、 tool box、tab widget、stacked widget等控件。其中scroll area 是滾動條控件,toolbox是列表頁面(例如QQ的聯系人列表),tab widget是類似網頁頁面的控件。stacked widget是棧控件,可以將以上三個頁面全部放到棧控件中,然后實現多個頁面的切換。代碼中還包括了combo box下拉框,QLabel的簡單使用。其中,QLabel可以用作顯示圖片,播放動態圖,視頻等等。
#include "widget.h" #include "ui_widget.h" #include <QPushButton> #include <QMovie> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// stacked Widget棧控件的使用// 默認定位ui->stackedWidget->setCurrentIndex(0);// scroll area 按鈕connect(ui->btn_scroll,&QPushButton::clicked, [=](){ui->stackedWidget->setCurrentIndex(0);});// toolBox 按鈕connect(ui->btn_toolBox,&QPushButton::clicked, [=](){ui->stackedWidget->setCurrentIndex(1);});// tabWidge 按鈕connect(ui->btn_tabWidget,&QPushButton::clicked, [=](){ui->stackedWidget->setCurrentIndex(2);});// combo box 下拉框ui->comboBox->addItem("奔馳");ui->comboBox->addItem("寶馬");ui->comboBox->addItem("拖拉機");// 點擊按鈕選中拖拉機connect(ui->pushButton_16,&QPushButton::clicked, [=](){// ui->comboBox->setCurrentIndex(2);ui->comboBox->setCurrentText("拖拉機"); // 兩句代碼效果一樣});// 利用QLabel顯示圖片ui->imaLabel->setPixmap(QPixmap(":/Image/fileIcon.JPEG").scaled(ui->imaLabel->size()));//利用QLabel顯示gif動態圖片QMovie *movie = new QMovie(":/Image/picaqu.gif");movie->setScaledSize(ui->movieLabel->size());ui->movieLabel->setMovie(movie);// 播放動圖movie->start(); }Widget::~Widget() {delete ui; }??效果圖:
3.9.4 自定義控件封裝
??建立一個自定義的控件,將QSpinBox和QSlider聯動起來:QSpinBox移動,QSlider跟著移動,QSlider跟著移動,QSpinBox也跟著移動。
??項目文件點擊->新建->Qt->設計師界面->widget,然后修改文件名(SmallWidget)。在smallwidget.up界面中添加,QSpinBox和QSlider兩個控件:
??右鍵SmallWidget窗口->提升為->添加->提升,成功以后,widget類底下就會包含SmallWidget類。
??修改smallwidget.cpp文件:
3.10 鼠標和定時器事件以及事件分發器、過濾器
??添加myLabel類->C+±>C++Class,父類選擇為QWidget,因為新建項目窗口能夠選擇父類有限,這里我們就選擇QWidget類,項目文件建好后,修改mylabel.h文件中include頭文件和父類,mylabel.cpp中構造函數的父類,全部修改為QLabel。
??進入UI界面,拖拽一個Label控件,修改為合適大小,文字刪除,此時控件消失,為了方便觀察,我們設置控件的邊框為Box類型,屬性頁面QFrame->frameShape->Box,如下圖所示。
??UI界面的設置創建兩個label控件,用來顯示定時器數字。定時器主要使用到timerEvent(QTimerEvent *ev)函數,多個定時器之間用timeId來區分。
??多個事件之間通過bool event(QEvent *ev)來進行事件分發,返回值是bool類型,如果返回值是true代表用戶要處理這個事件,不向下分發事件。
// mylabel.h文件 #ifndef MYLABEL_H #define MYLABEL_H #include <QLabel> class myLabel : public QLabel { public:explicit myLabel(QWidget *parent = nullptr);// 聲明// 鼠標進入事件void enterEvent(QEvent *event);// 鼠標離開事件void leaveEvent(QEvent *);// 鼠標按下事件void mousePressEvent(QMouseEvent *event);// 鼠標釋放事件void mouseReleaseEvent(QMouseEvent *event);// 鼠標移動事件void mouseMoveEvent(QMouseEvent *event);// 通過event事件分發器攔截 鼠標按下事件bool event(QEvent *e); signals:}; #endif // MYLABEL_H // widget.h文件 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget {Q_OBJECT public:Widget(QWidget *parent = nullptr);~Widget();// 定時器事件void timerEvent(QTimerEvent *);int id1; // 定時器1的唯一標識int id2; // 定時器2的唯一標識// 重寫事件過濾器的時間bool eventFilter(QObject *obj, QEvent *e); private:Ui::Widget *ui; }; #endif // WIDGET_H // mylabe.cpp文件 #include "mylabel.h" #include <QDebug> #include <QMouseEvent> myLabel::myLabel(QWidget *parent) : QLabel(parent) {// 設置鼠標追蹤setMouseTracking (true); // 原來是點擊后鼠標移動才能觸發,現在只要鼠標移動就能觸發鼠標移動事件。 } // 鼠標進入事件 void myLabel::enterEvent(QEvent *event) {qDebug() << "鼠標進入"; } // 鼠標離開事件 void myLabel::leaveEvent(QEvent *) {qDebug()<< "鼠標離開"; } // 鼠標按下事件 void myLabel::mousePressEvent(QMouseEvent *event) {// 要求:當鼠標左鍵按下時,打印信息,右鍵按下不打印if(event->button() == Qt::LeftButton){QString str = QString("鼠標按下了 x = %1, y = %2, globalx = %3, globaly = %4").arg(event->x()).arg (event->y()).arg (event->globalX()).arg (event->globalY());qDebug()<< str;} } // 鼠標釋放事件 void myLabel::mouseReleaseEvent(QMouseEvent *event) {if(event->button() == Qt::LeftButton){qDebug()<< "鼠標釋放";} } // 鼠標移動事件 void myLabel::mouseMoveEvent(QMouseEvent *event) {qDebug()<< "鼠標移動"; // if(event->buttons() & Qt::LeftButton) // &位與操作,buttons用于同時按下多個按鈕,只要按下的按鈕中包含左鍵,執行下面的操作。 // { // qDebug()<< "鼠標移動"; // } } // 通過event事件分發器攔截 鼠標按下事件 bool myLabel::event(QEvent *e) {// 如果是鼠標按下,在event中做攔截操作,也就是說在這一層做處理,后面的 鼠標按下 相關代碼就不會觸發if(e->type() == QEvent::MouseButtonPress){QMouseEvent *ev = static_cast<QMouseEvent *>(e); // static_cast是C++的強制類型轉換,大精度類型轉小精度類型,有損QString str = QString("Event函數中,鼠標按下了 x = %1, y = %2, globalx = %3, globaly = %4").arg(ev->x()).arg (ev->y()).arg (ev->globalX()).arg (ev->globalY());qDebug() << str;return true; // true代表用戶自己處理這個事件,不向下分發}// 其他事件交給父類處理, 其余事件都正常傳給后面的代碼處理return QLabel::event(e); } // widget.cpp文件 #include "widget.h" #include "ui_widget.h" #include <QTimer> #include <QMouseEvent> #include <QDebug> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);id1 = startTimer(1000); // 啟動計時器,參數1:間隔,單位毫秒id2 = startTimer(2000);// 定時器的第二種方式QTimer *timer = new QTimer(this);// 啟動定時器timer->start(500);connect(timer, &QTimer::timeout, [=](){static int num3 = 1;// label4 每隔0.5秒+1ui->label_4->setText(QString::number(num3++));});// 點擊按鈕暫停定時器,第三個暫停connect(ui->btn1, &QPushButton::clicked, [=](){timer->stop();});// 給label 安裝事件過濾器, 實際上是一個比event攔截器更高級的攔截器// 第一步ui->label->installEventFilter(this); } // 第二步 重寫 eventfiler事件 bool Widget::eventFilter(QObject *obj, QEvent *e) {if(obj == ui->label){if(e->type() == QEvent::MouseButtonPress){QMouseEvent *ev = static_cast<QMouseEvent * >(e);QString str = QString("事件過濾器中,鼠標按下了 x = %1, y = %2, globalx = %3, globaly = %4").arg(ev->x()).arg (ev->y()).arg (ev->globalX()).arg (ev->globalY());qDebug() << str;return true; // true代表用戶自己處理這個事件,不向下分發}}// 其他事件交給父類處理, 其余事件都正常傳給后面的代碼處理return QWidget::eventFilter(obj, e); }// 定時器事件 void Widget::timerEvent(QTimerEvent *ev) {if(ev->timerId() == id1){static int num1 = 1;ui->label_2->setText(QString::number(num1++));}if(ev->timerId() == id2){static int num2 = 1;ui->label_3->setText(QString::number(num2++));} } Widget::~Widget() {delete ui; }3.11 繪畫
3.11.1 繪畫設置
??這里主要介紹的是畫類操作,畫直線,畫圓,畫矩形等等,畫筆,毛刷等等設置,widget.cpp文件如下,此外,還需要在widget.h文件聲明函數void paintEvent(QPaintEvent *event)。
// widget.cpp文件 #include "widget.h" #include "ui_widget.h" #include <QPainter> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 點擊移動按鈕,移動圖片 ,paintEvent函數默認會調用一次,然后就是調用repaint函數,即重新繪畫函數connect (ui->pushButton, &QPushButton::clicked, [=](){// 手動調用繪圖事件函數,實際上是調用repaint函數PosX += 20; // 需要在widget.h中聲明, int PosX = 150;update();});} // 繪圖事件 void Widget::paintEvent(QPaintEvent *event) { // // 實例化畫家對象, this制定繪圖設備 // QPainter painter(this); // // 設置畫筆 // QPen pen(QColor(255,0,0)); // 設置顏色 // pen.setWidth (5); // 設置寬度 // pen.setStyle (Qt::DotLine); // 設置風格 // painter.setPen (pen); // // 設置畫刷 // QBrush brush(QColor(0,255,0)); // brush.setStyle (Qt::Dense1Pattern); // painter.setBrush (brush); // // 畫了一條線(兩個點確定) // painter.drawLine(QPoint(0,0),QPoint(100,100)); // // 畫橢圓圓,圓心和長短軸焦點a,b確定 a=b就是圓 // painter.drawEllipse (QPoint(100,100),50,50); // // 畫矩形 // painter.drawRect (QRect(20,20,50,50)); // // 畫文字 // painter.drawText (QRect(10,200,150,50),"好好學習,天天向上");****高級設置*******/ // QPainter painter(this); // painter.drawEllipse (QPoint(200,200),100,100); // // 設置 抗鋸齒能力,即畫的仔細一點,毛邊少一點,但是效率低一點 // painter.setRenderHint (QPainter::Antialiasing); // painter.drawEllipse (QPoint(400,200),100,100); // // 畫矩形 // painter.drawRect (QRect(20,20,50,50)); // painter.translate (100,0); // 畫家從0,0開始作畫,變成從100,0開始作畫 // // 保存畫家狀態 // painter.save(); // painter.drawRect (QRect(20,20,50,50)); // // 還原畫家保存狀態 // painter.restore (); // painter.drawRect (QRect(20,20,50,50));/ ******* 利用畫家調用圖片資源 **** //QPainter painter(this);// 如果超過屏幕寬度 ,從0開始if(PosX > this->width()){PosX = 0;}painter.drawPixmap(PosX,20,QPixmap(":/Image/Luffy.jpg")); }Widget::~Widget() {delete ui; }3.11.2 繪圖設備
??主要有QPixmap,QPicture,QImage三種,需要在widget.h文件聲明函數void paintEvent(QPaintEvent *event)
#include "widget.h" #include "ui_widget.h" #include <QPixmap> #include <QPainter> #include <QPicture> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); // // // // Pixmap繪圖設備,專門為平臺做了顯示的優化 // QPixmap pix(300,300); // 說明畫紙大小// // 填充背景色 // pix.fill(Qt::white); // // 聲明畫家 // QPainter painter(&pix); // painter.setPen(QPen(Qt::green)); // painter.drawEllipse(QPoint(150,150),100,100);// // 保存 // pix.save("D:\\software\\QT\\QT_Project\\qtDemo10\\pix.png");// /// // // QImage 繪圖設備 可以對每個像素進行訪問 // QImage img(300,300, QImage::Format_RGB32); // img.fill(Qt::white);// QPainter painter(&img); // painter.setPen(QPen(Qt::blue)); // painter.drawEllipse(QPoint(150,150),100,100);// // 保存 // img.save("D:\\software\\QT\\QT_Project\\qtDemo10\\img.png");// QPicture 繪圖設備,可以記錄和重現繪圖指令QPainter painter;QPicture pic;painter.begin(&pic); // 開始往pic上畫畫painter.setPen(QPen(Qt::blue));painter.drawEllipse (QPoint(150,150),100,100);painter.end(); // 結束畫畫// 保存到磁盤pic.save("D:\\software\\QT\\QT_Project\\qtDemo10\\pic.hyf");// hyf是博主的姓名縮寫,在文件資源管理器中是無法打開這個圖片的// 我們在繪圖事件中使用load函數可以打開,準確來說是重新繪制,因此pic保存的不是圖片本身而是繪制圖片的指令 } // 繪圖事件 void Widget::paintEvent(QPaintEvent *event) { // // 利用QImage 對像素進行修改 // QPainter painter(this); // QImage img; // img.load(":/Image/fileIcon.JPEG");// // 修改像素點 // for(int i=50; i<100; i++) // { // for (int j=50;j<100;j++) // { // QRgb value = qRgb(255,0,0); // img.setPixel(i,j,value); // } // } // painter.drawImage(0,0,img);// 重現QPicture繪圖指令QPainter painter(this);QPicture pic;pic.load("D:\\software\\QT\\QT_Project\\qtDemo10\\pic.hyf");painter.drawPicture(0,0,pic); } Widget::~Widget() {delete ui; }3.12 文件讀取
??文件讀取是主要注意打開文件,也要關閉文件,此外,QFile默認是UTF-8格式類型。widget.cpp文件如下所示:
#include "widget.h" #include "ui_widget.h" #include <QFileDialog> #include <QFile> #include <QTextCodec> #include <QFileInfo> #include <QDebug> #include <QDateTime> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);connect (ui->pushButton, &QPushButton::clicked, [=](){QString path = QFileDialog::getOpenFileName (this,"打開文件","C:/Users/19080/Desktop");// 將路徑放到lineEdit中ui->lineEdit->setText(path);// 編碼格式類QTextCodec *codec = QTextCodec::codecForName("gbk");// 讀取內容,放入到textEdit中// QFile默認支持的格式是UTF-8QFile file(path); // 參數就是file pathfile.open(QIODevice::ReadOnly); // 設置打開方式//QByteArray array = file.readAll();QByteArray array;while( !file.atEnd() ){array += file.readLine();}// 將讀取的數據放入到text Edit中ui->textEdit->setText(array);//ui->textEdit->setText(codec->toUnicode(array));file.close(); // 對文件對象進行關閉 文件寫入操作file.open(QIODevice::Append); // 追加的方式寫入file.write("123456789");file.close(); QFileInfo ///// QFileInfo 文件信息類QFileInfo info(path);qDebug() << "大小(字節):" << info.size()<< "后綴名:"<< info.suffix()<< "文件名稱:"<< info.fileName() <<"文件路徑:"<< info.filePath();qDebug() << "文件創建日期: "<< info.created().toString ("yyyy/MM/dd hh:mm:ss"); // 按格式輸出 yyyy/MM/dd hh:mm:ssqDebug() << "文件創建日期: "<< info.lastModified().toString ("yyyy/MM/dd hh:mm:ss");}); } Widget::~Widget() {delete ui; }四、翻金幣小游戲
4.1 出現的問題
??如果沒有素材可以從網上找,圖片資源都可以根據實際變化,不是唯一的。資源網站這里推薦阿里的圖標庫。
??博主在寫這個代碼的過程中出現了一些錯誤,第一個錯誤博主沒有解決,將第二個錯誤解決后,第一個就沒有出現了。第二個和第三個錯誤在頭文件前面加上Q_OBJECT成員變量,加在public前面,問題解決參考自博客No Q_OBJECT in the class with the signal錯誤解決辦法,然后在.pro文件末尾加上空格重新編譯。
4.2 源碼下載
??這里直接給大家分享一下成品,用百度網盤給出,步驟博主就不在一一介紹,需要源碼的可以評論。
鏈接:https://pan.baidu.com/s/1QGdOGuyTYMGfSgi81O71vw?pwd=zajg
提取碼:zajg
4.3 NSIS打包程序
??當我們寫好程序后將編譯運行按鈕中的debug輸出改為release輸出,然后得到一個發布版本的.exe程序,如圖所示:
??我們將他單獨拎出來放到桌面的release文件夾(自己命名的空文件夾都可以)中,然后找到對應編譯器的命令行窗口,如下圖所示,博主這里有兩個編譯器,博主的是MinGW 64-bit的。然后輸入windeployqt.exe CoinFlip.exe,按回車鍵,程序打包成功,之前的release文件就多了一些生成的打包文件。
windeployqt.exe CoinFlip.exe
??windeployqt.exe文件實際上是Qt編譯器提供的打包成window程序的可執行文件,可以在對應編譯器的bin文件中找到。
??這里需要注意不能使用普通的命令行窗口執行這個命令,會出現無法找到入口的問題。
??然后我們使用HM NIS Edit軟件進行Setup.exe文件的打包,需要配合NSIS軟件一起使用。
??NSIS是"Nullsoft 腳本安裝系統"(Nullsoft scriptable Installation System)的縮寫,它是是一個免費的win32安裝、卸載系統,可以很方便的打包windows應用程序。它的特點:腳本簡潔高效;系統開銷少;支持安裝、卸載、系統設置、解壓文件等功能。這里博主直接給出NSIS下載地址和HM NIS Edit下載地址,嫌麻煩的也可以用博主的百度網盤地址下載,鏈接:https://pan.baidu.com/s/1FrLENkVtB-B2lGslqw33bw?pwd=wybc
提取碼:wybc。
??參考博客 手把手教NIS Edit安裝向導的使用。當順著教程做到這一步的時候,點擊樹形圖,選擇release文件,將release文件中的所有文件添加進來。其他部分按照教程或者默認即可。最終會在項目目錄中生成Setup.exe文件。將Setup.exe安裝之后,就會在桌面生成快捷方式,點擊即可進行游戲。
總結
以上是生活随笔為你收集整理的【Qt设计开发】GUI界面设计开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 錦匯行商業管理公司对于西昌商铺一条街公开
- 下一篇: [附源码]计算机毕业设计springbo