C/C++ QT自定義對話方塊與MID窗體
對話方塊分為多種,常見的有通用對話方塊,自定義對話方塊,模態對話方塊,非模態對話方塊等,其中通用對話方塊包括了,QFileDialog檔案對話方塊,QColorDialog顏色對話方塊,QFontDialog字型對話方塊,QInputDialog輸入對話方塊等,自定義對話方塊則主要是實現自己佈局的簡單頁面,區別於窗體對話方塊則顯得更加簡單一些,除對話方塊外,多窗體設計也是最常用的,例如多窗體嵌入,MID窗體等,下面則是每種窗體的程式碼總結。
建立自定義窗體
1.首先使用兩個控制元件,TableView主要是表格處理,TreeView主要是樹形框,這兩者可以通過 QItemSelectionModel 模型繫結起來從而可實現選單聯動。
# mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <iostream> #include <QStandardItem> #include <QItemSelectionModel> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; QStandardItemModel *model; // 定義資料模型 QItemSelectionModel *selection; // 定義Item選擇模型 }; #endif // MAINWINDOW_H
# mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); model = new QStandardItemModel(4,5,this); selection = new QItemSelectionModel(model); // 關聯到tableView ui->tableView->setModel(model); ui->tableView->setSelectionModel(selection); // 關聯到treeView ui->treeView->setModel(model); ui->treeView->setSelectionModel(selection); // 新增表頭 QStringList HeaderList; HeaderList << "序號" << "姓名" << "年齡" << "性別" << "婚否"; model->setHorizontalHeaderLabels(HeaderList); // 批量新增資料 QStringList DataList[3]; QStandardItem *Item; DataList[0] << "1001" << "admin" << "24" << "男" << "是"; DataList[1] << "1002" << "lyshark" << "23" << "男" << "否"; DataList[2] << "1003" << "lucy" << "37" << "女" << "是"; int Array_Length = DataList->length(); // 獲取每個陣列中元素數 int Array_Count = sizeof(DataList) / sizeof(DataList[0]); // 獲取陣列個數 for(int x=0; x<Array_Count; x++) { for(int y=0; y<Array_Length; y++) { Item = new QStandardItem(DataList[x][y]); model->setItem(x,y,Item); } } } MainWindow::~MainWindow() { delete ui; }
2.首先來建立一個自定義對話方塊,建立對話方塊先要在專案上右鍵,選項【addNew】選擇【QT】點選【QT設計師】,我們這裡選擇最後一個最為介面框架。
3.預設情況下,QT會生成三個檔案【.ui 介面庫】【.h 標頭檔案】【.cpp 原始檔】名字相同的三個檔案,對應一個介面。
4.設計好介面佈局,然後開始寫程式碼。
dialogsize.h
#ifndef DIALOGSIZE_H
#define DIALOGSIZE_H
#include <QDialog>
namespace Ui {
class DialogSize;
}
class DialogSize : public QDialog
{
Q_OBJECT
public:
explicit DialogSize(QWidget *parent = nullptr);
~DialogSize();
int rowCount(); // 獲取對話方塊輸入的行數
int columnCount(); // 獲取對話方塊輸入的列數
void etRowColumn(int row, int column); // 初始對話方塊上兩個SpinBox的值
private:
Ui::DialogSize *ui;
};
#endif // DIALOGSIZE_H
dialogsize.cpp
#include "dialogsize.h"
#include "ui_dialogsize.h"
DialogSize::DialogSize(QWidget *parent) :QDialog(parent),ui(new Ui::DialogSize)
{
ui->setupUi(this);
}
DialogSize::~DialogSize()
{
delete ui;
}
// 主窗體呼叫獲取當前行數
int DialogSize::rowCount()
{
return ui->spinBoxRow->value();
}
// 主窗體呼叫獲取當前列數
int DialogSize::columnCount()
{
return ui->spinBoxColumn->value();
}
// 設定主窗體中的TableView行數與列數
void DialogSize::setRowColumn(int row, int column)
{
ui->spinBoxRow->setValue(row);
ui->spinBoxColumn->setValue(column);
}
mainwindow.cpp 主窗體中按鈕一被點選時執行。
// 當按鈕1被點選觸發
void MainWindow::on_pushButton_clicked()
{
DialogSize *ptr = new DialogSize(this); // 建立一個對話方塊
Qt::WindowFlags flags = ptr->windowFlags(); // 需要獲取返回值
ptr->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); // 設定對話方塊固定大小
ptr->setRowColumn(model->rowCount(),model->columnCount()); // 對話方塊資料初始化
int ref = ptr->exec(); // 以模態方式顯示對話方塊
if (ref==QDialog::Accepted) // OK鍵被按下,對話方塊關閉
{
// 當BtnOk被按下時,則設定對話方塊中的資料
int cols=ptr->columnCount();
model->setColumnCount(cols);
int rows=ptr->rowCount();
model->setRowCount(rows);
}
// 最後刪除釋放對話方塊控制代碼
delete ptr;
}
配置完後,我們還需要繫結兩個槽函式,首先來到dialog窗體上,手動新增兩條槽函式,當按鈕被點選後,後傳送一個訊號,主窗體接收到後處理即可。
執行效果如下,這是一個模態對話方塊,所謂模態就是說,當開啟時不能再次操作主窗體,只有模態對話方塊關閉時才能繼續操作主窗體。
接著來寫一個非模態對話方塊,這次建立一個Dialog名字就叫做DialogHead並繪製好介面。
dialoghead.h
#ifndef DIALOGHEAD_H
#define DIALOGHEAD_H
#include <QDialog>
#include <QStringListModel>
namespace Ui {
class DialogHead;
}
class DialogHead : public QDialog
{
Q_OBJECT
public:
explicit DialogHead(QWidget *parent = nullptr);
~DialogHead();
void setHeaderList(QStringList& headers); // 設定表頭資料
QStringList headerList(); // 返回表頭資料
private:
QStringListModel *model; // 定義資料模型
Ui::DialogHead *ui;
};
#endif // DIALOGHEAD_H
dialoghead.cpp
#include "dialoghead.h"
#include "ui_dialoghead.h"
DialogHead::DialogHead(QWidget *parent) :QDialog(parent),ui(new Ui::DialogHead)
{
ui->setupUi(this);
model = new QStringListModel;
ui->listView->setModel(model);
}
DialogHead::~DialogHead()
{
delete ui;
}
// 設定當前listView中的資料
void DialogHead::setHeaderList(QStringList &headers)
{
model->setStringList(headers);
}
// 返回當前的表頭
QStringList DialogHead::headerList()
{
return model->stringList();
}
mainwindow.cpp
// 對話方塊設定表頭資料
void MainWindow::on_pushButton_2_clicked()
{
DialogHead *ptr = new DialogHead(this);
Qt::WindowFlags flags = ptr->windowFlags();
ptr->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint);
// 如果表頭列數變化,則從新初始化
if(ptr->headerList().count() != model->columnCount())
{
QStringList strList;
// 獲取現有的表頭標題
for (int i=0;i<model->columnCount();i++)
{
strList.append(model->headerData(i,Qt::Horizontal,Qt::DisplayRole).toString());
}
// 用於對話方塊初始化顯示
ptr->setHeaderList(strList);
}
int ref = ptr->exec(); // 呼叫彈窗
if(ref==QDialog::Accepted)
{
QStringList strList=ptr->headerList();//獲取對話方塊上修改後的StringList
model->setHorizontalHeaderLabels(strList);// 設定模型的表頭標題
}
delete ptr;
}
最後在Dialog上繫結訊號與曹。
前面的互動都是使用傳統的相互引用實現的,實現起來較複雜,同樣可以使用訊號與曹來實現,將訊號與曹關聯起來,在進行操作時傳送訊號,槽函式接受並相應。
實現多窗體設計
多窗體分為窗體卡和MID窗體,這兩種窗體也最常用。
1.首先是窗體卡片,這裡在建立是應該選擇Widget窗體,這個窗體最乾淨沒啥控制元件,所以我們選擇它。
formdoc.h
#ifndef FORMDOC_H
#define FORMDOC_H
#include <QWidget>
namespace Ui {
class FormDoc;
}
class FormDoc : public QWidget
{
Q_OBJECT
public:
explicit FormDoc(QWidget *parent = nullptr);
~FormDoc();
private:
Ui::FormDoc *ui;
};
#endif // FORMDOC_H
formdoc.cpp
#include "formdoc.h"
#include "ui_formdoc.h"
#include "mainwindow.h"
#include <QVBoxLayout>
#include <iostream>
FormDoc::FormDoc(QWidget *parent) :
QWidget(parent),
ui(new Ui::FormDoc)
{
ui->setupUi(this);
QVBoxLayout *Layout = new QVBoxLayout();
Layout->setContentsMargins(2,2,2,2);
Layout->setSpacing(2);
this->setLayout(Layout);
MainWindow *parWind = (MainWindow*)parentWidget(); //獲取父視窗指標
QString ref = parWind->GetTableNumber(); // 獲取選中標籤索引
std::cout << ref.toStdString().data() << std::endl;
}
FormDoc::~FormDoc()
{
delete ui;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "formdoc.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QString GetTableNumber();
private slots:
void on_pushButton_clicked();
void on_tabWidget_tabCloseRequested(int index);
void on_tabWidget_currentChanged(int index);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tabWidget->setVisible(false);
ui->tabWidget->clear();//清除所有頁面
ui->tabWidget->tabsClosable(); //Page有關閉按鈕,可被關閉
}
MainWindow::~MainWindow()
{
delete ui;
}
// 定義函式來獲取當前Table名字
QString MainWindow::GetTableNumber()
{
QString ref = QString(ui->tabWidget->currentIndex());
return ref;
}
void MainWindow::on_pushButton_clicked()
{
FormDoc *ptr = new FormDoc(this); // 新建選項卡
ptr->setAttribute(Qt::WA_DeleteOnClose); // 關閉時自動銷燬
int cur = ui->tabWidget->addTab(ptr,QString::asprintf(" 192.168.1.%d",ui->tabWidget->count()));
ui->tabWidget->setTabIcon(cur,QIcon(":/image/1.ico"));
ui->tabWidget->setCurrentIndex(cur);
ui->tabWidget->setVisible(true);
}
// 關閉Tab時執行
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
if (index<0)
return;
QWidget* aForm=ui->tabWidget->widget(index);
aForm->close();
}
// 在無Tab頁面是預設禁用
void MainWindow::on_tabWidget_currentChanged(int index)
{
Q_UNUSED(index);
bool en=ui->tabWidget->count()>0;
ui->tabWidget->setVisible(en);
}