目錄
一,關于窗口
二,菜單欄
2.1 菜單介紹
2.2 添加菜單
2.3 添加快捷鍵
2.4 添加其子菜單
2.5 添加分割線和圖標
三,工具欄
3.1 添加和使用工具欄
3.2 設置位置屬性
四,狀態欄
五,浮動窗口
六,對話框
6.1 介紹
6.2 自定義對話框
6.3 模態對話框
6.4?內置對話框
6.4.1?QMessageBox
6.4.2 QColorDialog
6.4.3 QFileDialog
6.4.4 QfontDialog
6.4.5 QInputDialog
一,關于窗口
我們前面學習的所有控件的代碼,都是基于 QWidget 的,但是 QWidget 更多的是作為別的窗口的一個部分
在創建項目時,選擇 QMainWindow,這個才是 Qt 窗口的完全體:
一個 QMainWindow 包含了下列內容:
從上往下依次是:
- 標題:操作系統加的,與Qt關系不大,可以修改名稱
- 菜單欄:與標題緊挨,只能置于最上面
- 工具欄:類似于菜單欄,本質上是把菜單欄一些常用選項直接放到工具欄,目的是方便使用,上圖的粉色區域四個方向都有,表示可以置于四個方向上
- 子窗口:一個程序里可能包含多個窗口,比如 Qt 界面就同時包含了:“文件管理窗口”,“代碼編輯窗口”,“輸出窗口”等等
- 中央控件:窗口最核心的部分
- 狀態欄:顯示一些信息,和上面所有內容一樣,都可以在 Qt 的界面找到對應的內容?
二,菜單欄
2.1 菜單介紹
Qt 中的菜單欄通過 QMenuBar 這個類來實現,并且一個主窗口最多只能有一個菜單欄,下面是Qt的菜單欄:
工具欄里的選項也叫做 QAction,因為前面說過,工具欄本質是菜單欄一些功能的快捷選項
2.2 添加菜單
以后我們創建項目時,選擇 QMainWindow,而不是 QWidget 了:
生成的代碼和 QWidget 的很相似,也是在 mainwindow.cpp 里編寫代碼,在 .h 里聲明函數
唯一的區別也就是 ui 界面了,如下圖:
添加菜單欄和添加菜單項都可以通過上面的圖形化界面來創建,下面是通過代碼創建的演示:
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//1,創建并設置菜單欄QMenuBar* menuBar = new QMenuBar(); this->setMenuBar(menuBar); //設置進窗口里,其實是掛到對象樹里去//2,創建菜單QMenu* m1 = new QMenu("文件");QMenu* m2 = new QMenu("編輯");QMenu* m3 = new QMenu("構建");menuBar->addMenu(m1);menuBar->addMenu(m2);menuBar->addMenu(m3);//3,給菜單添加菜單項QAction* a1 = new QAction("新建");QAction* a2 = new QAction("打開");QAction* a3 = new QAction("保存");QAction* a4 = new QAction("另存為");QAction* a5 = new QAction("退出");m1->addAction(a1);m1->addAction(a2);m1->addAction(a3);m1->addAction(a4);m1->addAction(a5);//4,給 action 添加信號槽,上面的菜單項被點擊后會產生一個 triggered 信號connect(a1, &QAction::triggered, this, &MainWindow::handle); //a1發信號,發triggered信號,this接收,執行handle函數
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::handle()
{qDebug() << "觸發操作";
}
效果如下:
2.3 添加快捷鍵
直接在創建項目時,添加下列內容即可:
但是默認是 alt + 隨機鍵,如果是要用 Ctrl + 隨機鍵,就需要用到 setShortcuts,如下給菜單項添加 Ctrl 的快捷鍵:
2.4 添加其子菜單
有時候菜單欄下面是菜單,但是往下還有一層或多層子菜單,如下:
QMenu 也提供了 addMenu 功能給某個菜單項添加子菜單,QMenuBar 也可以, 如下代碼:
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);QMenu* menuParent = new QMenu("父菜單");QMenu* menuChild = new QMenu("子菜單");menuBar->addMenu(menuParent);menuParent->addMenu(menuChild); //直接在對應的父菜單調用 addMenu函數添加QAction* a1 = new QAction("菜單項1");QAction* a2 = new QAction("菜單項2");menuChild->addAction(a1);menuChild->addAction(a2);
}
如果還想添加子菜單,直接繼續直接用菜單對象調用 addMenu 函數即可?
2.5 添加分割線和圖標
如標題,當菜單里的菜單項特別多時,可以通過 QMenu 提供的 addSeparator 方法添加分割線進行分組;同時也可以通過 setIcon 來進行設置,如下代碼:
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);QMenu* m = new QMenu("你好");menuBar->addMenu(m);QAction* a1 = new QAction("菜單項1");a1->setIcon(QIcon(":/deepseek.png")); //設置圖標QAction* a2 = new QAction("菜單項2");QAction* a3 = new QAction("菜單項3");m->addAction(a1);m->addSeparator(); //添加分割線m->addAction(a2);m->addSeparator();m->addAction(a3);
}
如果給主菜單的 QMune 設置圖標,由于 QMenu是直接覆蓋在 MenuBar 上的,那么圖標就會覆蓋文本,可以根據需要自行設置
三,工具欄
3.1 添加和使用工具欄
使用 QToolBar 表示工具欄對象,一個窗口可以有多個工具欄也可以沒有,而且工具欄也可以手動移動位置,如下代碼:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QDebug>
#include<QToolBar>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//創建菜單欄QMenuBar* menuBar = this->menuBar();this->setMenuBar(menuBar);QMenu* menu = new QMenu("文件");menuBar->addMenu(menu);//創建并添加工具欄QToolBar* toolBar = new QToolBar();this->addToolBar(toolBar);QAction* a1 = new QAction("保存");QAction* a2 = new QAction("新建");a1->setToolTip("點擊以保存文件"); //鼠標放在對應選項時的提示信息,默認是上面創建時的a2->setToolTip("點擊新建文件");a1->setIcon(QIcon(":/deepseek.png")); //工具欄一般也是用圖標代替,這里暫時用 老圖片代替a2->setIcon(QIcon(":/deepseek.png"));//菜單項可以放在菜單和工具欄中menu->addAction(a1);menu->addAction(a2);toolBar->addAction(a1);toolBar->addAction(a2);connect(a1, &QAction::triggered, this, &MainWindow::handle);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::handle()
{qDebug() << "觸發操作";
}
3.2 設置位置屬性
工具欄的位置并不是固定的:
- 很多工具欄并不是指放置于菜單欄下面,也可以放置在靠左靠右和靠下位置
- 而且鼠標長按工具欄本體,可以直接將工具欄分離出來,以浮動窗口的形式顯示在屏幕上
- 所以我們也可以將我們上面的工具欄添加一些屬性,讓其也有類似的效果
①設置位置?
可以設置初始位置和停靠位置,如下:
有四種參數可以設置:
- Qt::LeftToolBarArea:停靠在左側
- Qt::RightToolBarArea:停靠在右側
- Qt::TopToolBarArea:停靠在頂部
- Qt::BottomToolBarArea:停靠在底部
- Qt::AllToolBarArea:四個位置都可以
也可以使用 selAllowedAreas 方法設置工具欄允許停靠的位置,如下:
②設置浮動屬性?
工具欄的浮動可以通過 setFloatable 方法來設置,就是可以將工具欄以浮動小窗口的形式顯示在屏幕上,如下:
設置不能浮動后,工具欄也是可以移動到允許停靠的位置的?
③設置移動屬性?
設置工具欄移動屬性可以通過 setMovable 方法來設置,并且若工具欄設置了不移動狀態,則停靠位置和浮動的操作都會禁用,相當于固定死了位置,只能在初始化的時候指定位置,所以這個方法類似于總開關的效果,如下:
四,狀態欄
狀態欄是應用程序輸出簡要信息的區域,一般位于窗口最底層,且一個窗口只能有一個狀態欄
由 QStatusBar 來實現,可以顯示三種信息:
- 實時消息:比如當前程序狀態
- 永久消息:比如版本號,機構名稱等
- 進度消息:入進度條顯示,百分百提示等
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QStatusBar* s = this->statusBar(); //直接獲取this->setStatusBar(s);//1,顯示臨時消息//s->showMessage("你好", 2000); //設置顯示大約2秒的信息//2,設置永久消息,需要通過 label 控件來顯示s->addWidget(new QLabel("這是一條永久消息"));//3,調整顯示消息的位置s->addPermanentWidget(new QLabel("右側提示消息"));
}
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QStatusBar* s = this->statusBar(); //直接獲取this->setStatusBar(s);//1,顯示臨時消息//s->showMessage("你好", 2000); //設置顯示大約2秒的信息//2,設置永久消息,需要通過 label 控件來顯示s->addWidget(new QLabel("你好111"), 1); //第二個參數表示拉伸系數s->addWidget(new QLabel("你好222"), 2);//3,在右下角顯示進度條QProgressBar* p = new QProgressBar();p->setValue(50);s->addPermanentWidget(p); //表示從右往左設置
}
五,浮動窗口
上面我們也講到了,一個程序里可能包含多個窗口,比如 Qt 界面就同時包含了:“文件管理窗口”,“代碼編輯窗口”,“輸出窗口”等等
我們可以使用 QDockWidget 類來實現浮動的功能,可以有多個,并且部分操作和工具欄的操作類似,如下演示:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QDebug>
#include<QLabel>
#include<QDockWidget>
#include<QVBoxLayout>
#include<QPushButton>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QDockWidget* dockWidget = new QDockWidget();this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget); //將浮動窗口添加到左邊子窗口中dockWidget->setWindowTitle("這是浮動窗口"); //給浮動窗口設置標題//也可以給浮動窗口添加控件,但是需要先創建出一個單獨的 QWidget,把控件假如其中,然后再將 QWidget 設置進 dockWidget 才行QWidget* w = new QWidget();dockWidget->setWidget(w);//創建布局遍歷器,并設置進 QWidget 中QVBoxLayout* l = new QVBoxLayout;w->setLayout(l);//再創建其它控件,添加到 layout 中l->addWidget(new QLabel("這是一個 QLabel"));l->addWidget(new QPushButton("這是按鈕"));
}MainWindow::~MainWindow()
{delete ui;
}
六,對話框
6.1 介紹
對話框是 GUI 程序中不可或缺的部分,往往是程序與用戶之間進行“短平快” 的操作
Qt 中使用 QDialog 類表示對話框,通常是一個頂層窗口,出現在程序最上層,用于實現短期熱內或者簡潔的用戶交互
Qt 常用的內置對話框有:QFiledialog(文件對話框)、QColorDialog(顏色對話框)、QFontDialog (字體對話框)、QInputDialog(輸入對話框)和QMessageBox(消息框)
創建項目時選擇 QDialog :
直接運行程序會顯示:
總體來說,基于 QDialog 作為父類創建出來的程序窗口和之前通過 QWidget 創建出來的非常相似,就是部分屬性不一樣,后面我們會詳細介紹
實際開發中,更多的情況不是在創建項目時繼承自 QDialog,而是在代碼中創建額外的類,讓這個類繼承自 QDialog,從而讓主窗口產出一些其他的對話框
我們也可以在 QMainWindow 項目里用按鈕生成一個對話框,如下槽函數:
void MainWindow::on_pushButton_clicked()
{QDialog* d = new QDialog();d->setWindowTitle("你好"); //設置對話框標題d->resize(400, 300); //設置對話框的大小d->show(); //顯示對話框
}
問題:我們按下按鈕彈出彈窗,關閉后再次點擊按鈕,此時彈出的彈窗和第一此彈出的是同一個對象嗎?
解答:每次按下按鈕都是創建一個新的 QDialog 對象,并進行顯示
追問:那么多次甚至無數次點擊按鈕創建對象,內存泄漏問題如何解決?
解答:將 delete 釋放邏輯和關閉按鈕的點擊信號關聯起來,在用戶點擊關閉的時候,觸發 delete;并且 Qt 也給QDialog 設置了一個屬性,可以通過屬性來完成上述操作,如下:
6.2 自定義對話框
?上面我們通過按鈕彈出一個對話框,但是目前這個對話框是空白的,如何在里面添加控件呢?
要自定義對話框,就需要繼承自 QDialog 創建類,然后有兩種繼承方式,下面分別演示一下:
①純代碼方式來自定義 QDialog 界面
先新鍵一個類:
?
?然后就會創建出一個頭文件和一個 .cpp 文件,然后我們就可以把這兩個文件當初是我們之前用的另一個 QWidget 的頭文件和 .cpp 文件去編寫控件代碼了,如下:
dialog.h內容如下:
#ifndef DIALOG_H
#define DIALOG_H#include <QWidget>
#include <QDialog>class Dialog : public QDialog
{Q_OBJECT
public:Dialog(QWidget* parent); //添加進 QWidget 的對象樹中void handle();
};#endif // DIALOG_H
dialog.cpp 內容如下:
#include "dialog.h"
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>Dialog::Dialog(QWidget* parent) : QDialog(parent)
{//創建出一些控件,加入到 Dialog 中QVBoxLayout* layout = new QVBoxLayout();this->setLayout(layout);QLabel* label = new QLabel("你好");QPushButton* b = new QPushButton("關閉", this);layout->addWidget(label);layout->addWidget(b);connect(b, &QPushButton::clicked, this, &Dialog::handle);
}void Dialog::handle()
{this->close();
}
?mainwindow.cpp 里將原來的 QDialog 替換為我們的 Dialog,效果如下:
②通過圖形化的方式
?我們上面的按鈕保存,但是按下按鈕后顯示的對話框不再是純代碼的了,所以先刪除槽函數內容
而通過圖形化界面創建,重要的就是先創建一個新的 .ui 文件出來,如下:
這個操作是創建一個 ui 文件和對應的類,也可以指定創建的模板,選定好類名后直接下一步即可
然后雙擊這個 ui 文件,就可以和前面一樣創建控件了,同時右鍵按鈕轉到槽,就可以像前面那樣編寫槽函數了,如下:
然后就可以直接在 mainwindow.cpp 的槽函數里創建 Dialog 對象然后顯示了:
效果和上面純代碼的一致
6.3 模態對話框
在上面 6.1 我們直接創建的對話框項目的 ui 界面,右下角屬性有一個這個:
表示 模態 / 非模態(true / false),這個我們也很常見,就是如果為 true,表示模態,此時用戶無法操作父窗口,必須先完成對話框內容并關閉對話框之后,我們才可以繼續操作;非模態就是是相反
這個模態用于非常關鍵的,必須要讓用戶做出決策的場合;非模態就是用于不受特別關鍵的場景
要使我們的對話框變成模態對話框也很簡單,只要把我們前面的 .show 方法換成 .exec 方法即可:
6.4?內置對話框
6.4.1?QMessageBox
消息對話框是應用程序中最常見的界面元素,我們還是通過一個按鈕顯示對話框,槽函數如下:
void MainWindow::on_pushButton_clicked()
{// 創建消息對話框QMessageBox* m = new QMessageBox(this);m->setWindowTitle("你好");m->setText("這是對話框文本");m->setIcon(QMessageBox::Warning); //設置圖標m->setAttribute(Qt::WA_DeleteOnClose);m->setStandardButtons(QMessageBox::Ok | QMessageBox::Save); //添加內置按鈕//我們也可以使用自定義按鈕//QPushButton* b = new QPushButton("按鈕", m); /也可以使用 connect 連接信號槽//m->addButton(b, QMessageBox::AcceptRole); //第一個參數是 QAbstractButton,第二個是 ButtonRole,負責返回點擊按鈕的一些情況int result = m->exec();if(result == QMessageBox::Ok) qDebug() << "ok";else if(result == QMessageBox::Save) qDebug() << "Save";//上面的內置按鈕,沒辦法進行信號槽的連接,因為按鈕是 QMessageBox 自己生成的//所以為了解決這個問題,用戶點擊按鈕使對話框關閉之后,能通過 exec 的返回值,來獲取用戶點擊的是哪個按鈕了
}
除了上面的方式,QMessageBox 類定義了靜態成員函數,可以直接調用并創建不同內容的消息對話框,包括:
?
void MainWindow::on_pushButton_clicked()
{// 創建消息對話框int result = QMessageBox::warning(this, "對話框標題", "對話框文本", QMessageBox::Ok | QMessageBox::Cancel);if(result == QMessageBox::Ok) qDebug() << "Ok";else if(result == QMessageBox::Cancel) qDebug() << "Cancel";
}
?
6.4.2 QColorDialog
這個是顏色對話框,繼承自 QDialog 類, 可以讓用戶來選擇一個顏色,而且 QColorDialog 內置了“調色板”,常用函數如下:
函數 | 說明 |
---|---|
QColorDialog(QWidget*parent=nullptr) | 創建對象的同時設置父對象 |
QColorDialog(const QColor &initial, QWidget *parent = nullptr) | 創建對象的同時通過QColor 對象設置默認顏色和父對象 |
voidsetCurrentColor(const QColor &color) | 設置當前顏色對話框 |
QColorcurrentColor() const | 獲取當前顏色對話框 |
QColorgetColor(const QColor &initial = Qt::white, QWidget *parent = nullptr, const QString &title = QString(), QColorDialog::ColorDialogOptions options = ColorDialogOptions()) | 打開顏色 選擇對話框,并返回?個QColor對象 |
voidopen(QObject* receiver, constchar* member) | 打開顏色對話框 |
部分參數:?
- initial:設置默認顏色
- parent:設置父對象
- title:設置對話框標題
- options:設置選項
下面直接用代碼演示一下:
void MainWindow::on_pushButton_clicked()
{//getColor 能彈出一個模態的對話框,用戶選擇顏色后,確定關閉,getColor 就可以返回一個QColor 對象,包含一些顏色信息//并且是一個靜態的,不需要創建對象就能使用QColor c = QColorDialog::getColor(QColor(255, 0, 0), this, "選擇顏色");qDebug() << c; //打印QColor(ARGB 1, 1, 0, 0) 第一個數表示不透明度,后面三個就是顏色的RGB數值,1表示255,0 就是 整數0,是百分比的形式//可以基于顏色,修改其它控件的顏色,比如下面是設置背景顏色//QString s = "background-color: rgb(" + QString::number(c.red()) + ", " + QString::number(c.green()) + ", " + QString::number(c.blue()) + ")";char s[1024] = { 0 };sprintf(s, "background-color: rgb(%d, %d, %d)", c.red(), c.green(), c.blue()); //上面的太長,也可以這樣搞,以格式化方式設置this->setStyleSheet(s); //可以通過 QSS 的方式設置背景色
};
6.4.3 QFileDialog
通過 QFileDialog 可以選擇一個文件,能夠獲取到這個文件的路徑,然后對指定文件進行一些操作,常用函數如下:
函數 | 說明 |
---|---|
QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options()) | 打開文件(一次只能打開一個) |
QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options()) | 打開文件(能打開多個) |
QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options()) | 保存文件 |
參數說明:
- parent:父控件
- caption:對話框標題
- dir:默認打開的路徑
- filter:文件過濾器
下面我們來演示一下,我們搞兩個按鈕,左邊的用來彈出打開文件,右邊的用來彈出保存文件,如下代碼:
//注意這里僅僅只是獲取文件路徑,真正打開/保存文件的操作需要我們實現額外的邏輯,后面會詳細介紹
void MainWindow::on_pushButton_clicked()
{QString filePath = QFileDialog::getOpenFileName(this); //返回文件路徑,此時右下角顯示“打開”qDebug() << filePath; //打印文件路徑
};void MainWindow::on_pushButton_2_clicked()
{QString filePath = QFileDialog::getSaveFileName(this); //此時右下角顯示“返回”,并且需要輸入文件名qDebug() << filePath; //打印文件路徑
}
6.4.4 QfontDialog
這個表示字體對話框,用于提供選擇字體的對話框部件,如下代碼:
void MainWindow::on_pushButton_clicked()
{bool ok = false; //作為輸出型參數,當用戶選擇確定時設置為true,選擇取消時設置為falseQFont font = QFontDialog::getFont(&ok); //返回字體信息ui->pushButton->setFont(font); //設置按鈕字體
};
6.4.5 QInputDialog
表示一個輸入對話框,用于進行臨時數據輸入的場合,常用函數如下:
函數 | 說明 |
---|---|
double getDouble(QWidget*parent,constQString&title, const QString&label, double value =0,doublemin=-2147483647,doublemax=2147483647,intdecimals=1,bool*ok =nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); | 雙精度浮點型輸入數據對話框 |
int getInt (QWidget *parent, const QString &title, const QString &label, int value = 0, int min=-2147483647,intmax=2147483647,intstep=1,bool*ok=nullptr,Qt::WindowFlags flags = Qt::WindowFlags()); | 整型輸入數據對話框 |
QString getItem (QWidget*parent, const QString&title, const QString &label, const QStringList &items, int current = 0, bool editable = true, bool *ok =nullptr, Qt::WindowFlags flags = Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints = Qt::ImhNone) ; | 選擇條目輸入數據框 |
下面是輸入數字的代碼:
void MainWindow::on_pushButton_clicked()
{double result = QInputDialog::getDouble(this, "這是標題", "浮點數");//getInt就是輸入整數qDebug() << result;
};
可以看到他是自帶微調框的,我們也可以自己去設置
第三個是條目框,顧名思義就是將上面的輸入框換成了條目按鈕輸入,如下代碼:
void MainWindow::on_pushButton_clicked()
{QStringList items; //可以當成是 QList<QString>,字符串數組items << tr("你好") << tr("hello world") <<tr("Qt Creator");QString s = QInputDialog::getItem(this, "條目輸入對話框", "請輸入條目", items);qDebug() << s;
};
效果如下: