一、模态显示自定义对话框(TDialogSize对话框)
1、创建对话框
新建一个文件,选择Qt-qt Widgets Designer Form Class
选择Dialog without Buttons,下一步
编辑类名称,点击下一步可在Project中找到UI文件
2、编辑ui界面
QPushButton关联accept()和reject()
TDialogSize::~TDialogSize()
{
delete ui;
connect(ui->btnOk,SIGNAL(clicked()),this,SLOT(accept()));//关联accept
connect(ui->btnCancel,SIGNAL(clicked()),this,SLOT(reject()));//关联reject
}
3、 TDIalogSize类的头文件定义
对话框组件都是私有成员,外部不能直接访问数据,所以读取和设置初始值函数设置为公有。
namespace Ui {
class TDialogSize;
}
class TDialogSize : public QDialog
{
Q_OBJECT
public:
explicit TDialogSize(QWidget *parent = nullptr);
~TDialogSize();//析构函数
int rowCount();//返回行spinBox
int columnCount();//返回列spinBox
void setRowColumn(int row,int col);//读取主函数行列,初始化spinBox的value值
private:
Ui::TDialogSize *ui;
};
4、TDialogSize类成员函数实现
int TDialogSize::rowCount()
{
return ui->spin_row->value();//用于主窗口调用,来获得value值
}
int TDialogSize::columnCount()
{
return ui->spin_col->value();//用于主窗口调用,来获得value值
}
void TDialogSize::setRowColumn(int row, int col)
{
//主窗口调用,传入row col
//初始化spinBox value值
ui->spin_row->setValue(row);
ui->spin_col->setValue(col);
}
5、主函数使用
头文件引用:#include "tdialogsize.h",exec()运行窗口,对话框以模态方式显示,点击Ok按钮exec()返回QDialog::Accepted()
void MainWindow::on_act_setRC_triggered()
{
TDialogSize *dlgTableSize=new TDialogSize(this);//创建对话框
dlgTableSize->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint);//设置固定大小
dlgTableSize->setRowColumn(m_model->rowCount(),m_model->columnCount());//传入行列数据
int ret=dlgTableSize->exec();//以模态方式显示对话框,返回值返回对话框的操作结果
if(ret==QDialog::Accepted)//如果选择的接受
{
int clos=dlgTableSize->columnCount();
int rows=dlgTableSize->rowCount();
m_model->setColumnCount(clos);
m_model->setRowCount(rows);
}
delete dlgTableSize;
}
最后使用delete删除创建的对话框对象,释放内存。
二、模态显示自定义对话框(TDialogHeaders对话框)
1、ui界面、信号和槽
2、头文件与cpp文件
头文件定义:
//头文件
class TDialogHeaders : public QDialog
{
Q_OBJECT
private:
QStringListModel *m_model;//定义数据模型
public:
explicit TDialogHeaders(QWidget *parent = nullptr);
~TDialogHeaders();
void setHeaderList(QStringList& headers);//设置字符串列表
QStringList headerList();//返回字符串列表
private:
Ui::TDialogHeaders *ui;
};
成员函数的实现:
//CPP文件
TDialogHeaders::TDialogHeaders(QWidget *parent)
: QDialog(parent)
, ui(new Ui::TDialogHeaders)
{
ui->setupUi(this);
m_model=new QStringListModel(this);//创建数据模型
ui->listView->setModel(m_model);//设置数据模型
}
TDialogHeaders::~TDialogHeaders()
{
delete ui;
}
void TDialogHeaders::setHeaderList(QStringList &headers)
{
m_model->setStringList(headers);
}
QStringList TDialogHeaders::headerList()
{
return m_model->stringList();
}
3、主函数引用
在主函数中定义此类的指针变量,指向空。在最开始判断当前指针变量是否创建过。
TDialogHeaders* dlgSetHeaders=nullptr;//定义TDialogHeaders指针类型变量
变量m_model为QStandardItemModel(表格模型)类,读取一行数据可用headerData(),
headerData(int ,Qt::orentation ,int role=Qt::DisPlayRole);
参数1:索引开始位置。
参数2:数据的方向(水平或垂直)
参数3:可选参数,指定数据角色
if(dlgSetHeaders==nullptr)//若未创建
dlgSetHeaders=new TDialogHeaders(this);
dlgSetHeaders->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint);//设置固定大小
if(dlgSetHeaders->headerList().size()!=m_model->columnCount())
{
QStringList readHeaderList;
for(int i=0;i<m_model->columnCount();i++)//获取现有的表头标题
readHeaderList.append(m_model->headerData(i,Qt::Horizontal,Qt::DisplayRole).toString());
//从0列开始,水平读取显示的数据
dlgSetHeaders->setHeaderList(readHeaderList);
}
int ret=dlgSetHeaders->exec();
if(ret==QDialog::Accepted)
{
QStringList list=dlgSetHeaders->headerList();
m_model->setHorizontalHeaderLabels(list);
}
在最后并没有释放 dlgSetHeaders ,在下次调用时再次显示此对话框,直到主窗口关闭。
三、非模态对话框(TDialogLocate对话框设计)
设置对话框的modal属性为false,使用函数QWidget::show()显示对话框,对话框以非模态方式显示。函数show()显示非模态对话框后就立刻退出,系统继续运行后面的程序,可以继续操作主窗口界面。功能如下:
- 点击定位单元格打开窗口,点击主窗口单元格,tdialoglocate窗口更新状态(列号、行号、文字内容)
- tdialoglocate窗口spinBox->value值变化时,主窗口单元格定位改变。在超出主窗口行列数后,主窗口不再更新定位。
- 在未勾选增列/行时,spinBox容器有最大值限制,不超过主窗口行列。勾选后最大值设置到999。
- 增列/行勾选时,可超出主窗口tableview的count值,取消勾选时,若spinBox值大于主窗口tableview的count值,设置spinBox->value为主窗口最大column、row值。
1、功能实现
1)点击定位单元格Action打开窗口,初始化数据
void TDialogLcoate::setSpinAndText(QStandardItem &item)
{
ui->spinCol->setValue(item.column());//设置行
ui->spinRow->setValue(item.row());//设置列
ui->lineEdit->setText(item.text());//设置内容
qDebug()<<QString("row=%1,col=%2,text=%3").arg(item.column()).arg(item.row()).arg(item.data(Qt::DisplayRole).toString());
}
2)QSpinbox值设置
设置QSpinBox->value()范围,当增行/列勾选时,重新设置最大值(999),也可使用setMaximun()设置最大值,这里使用setRange()设置QSpinBox容器范围。
void TDialogLcoate::setSpinBoxMinAndMaxValue(int rowMax, int colMax)//初始化最大值
{
qDebug()<<QString("行最大值=%1,列最大值=%2").arg(rowMax).arg(colMax);
//保存传入值,在取消增行/列时恢复
rowvalueIni=rowMax;
colvalueIni=colMax;
ui->spinRow->setRange(0,rowMax);//设置0~rowMax范围
ui->spinCol->setRange(0,colMax);
}
void TDialogLcoate::on_chk_addCol_toggled(bool checked)
{
//关闭spinbox范围限制
if(checked)
ui->spinCol->setRange(0,999);//改变范围
else
{
if(ui->spinCol->value()>colvalueIni)
ui->spinCol->setValue(0);
ui->spinCol->setRange(0,colvalueIni);//改变范围
}
}
void TDialogLcoate::on_chk_addRow_toggled(bool checked)
{
if(checked)
ui->spinRow->setRange(0,999);//改变范围
else
{
if(ui->spinRow->value()>colvalueIni)
ui->spinRow->setValue(0);
ui->spinRow->setRange(0,rowvalueIni);//改变范围
}
}
3)根据spinBox值变化定位单元格位置
TDialogLcoate类中自定义了三个信号:
signals://对话框发射的信号
void changeActionEnable(bool en);//设置主窗口Action状态信号
void changeCellText(int row,int col,QString text);//文字修改信号
void changedSpinBoxValue(int row,int col);//value值变化信号
spinBox容器值变化时TDialogLcoate发射信号,主窗口再去判断是否需要定位单元格。
connect(
ui->spinRow,SIGNAL(valueChanged(int)),
this,SLOT(emitSpinBoxValueChangedToMainwindows(int))
);//spinRow值变化,发射信号
connect(
ui->spinCol,SIGNAL(valueChanged(int)),
this,SLOT(emitSpinBoxValueChangedToMainwindows(int))
);//spinCol值变化,发射信号
void TDialogLcoate::emitSpinBoxValueChangedToMainwindows(int n)//发送spinBox容器数据被修改信号,主窗口单元格定位
{
Q_UNUSED(n)
qDebug()<<"emit changedSpinBoxValue";
emit changedSpinBoxValue(ui->spinRow->value(),ui->spinCol->value());//发射自定义信号
}
另一个类的信号连接主函数的槽函数,连接与槽函数实现如下:
//主窗口函数
connect(dlaLocate,SIGNAL(changedSpinBoxValue(int,int)),this,SLOT(spinBoxValueChanged_tdialoglcoate(int, int)));//定位单元格
void MainWindow::spinBoxValueChanged_tdialoglcoate(int row, int col)//根据spinbox变化更新主窗口定位
{
if(dlaLocate->read_chkAddRow_static()||dlaLocate->read_chkAddCol_static())
{
//dlaLocate选择了行增或者列增
qDebug()<<"chkadd is set allow exceed";
int spinboxRowV=dlaLocate->read_spinboxRowValue();
int spinboxColV=dlaLocate->read_spinboxColValue();
int modelSetMaxRowV=m_model->rowCount();
int modelSetMaxColV=m_model->columnCount();
qDebug()<<QString("spinBoxV(%1,%2) m_model set v=(%3,%4)").arg(spinboxRowV).arg(spinboxColV).arg(modelSetMaxRowV).arg(modelSetMaxColV);
//若选择了行增或列增,且数据超出,不再更新主窗口定位
if(spinboxRowV>=modelSetMaxRowV || spinboxColV>=modelSetMaxColV)
{
qDebug()<<"超出";
return;
}
}
qDebug()<<"更新定位";
qDebug()<<"spinBoxValueChanged_tdialoglcoate";
QModelIndex index=m_model->index(row,col);//获取模型索引
m_selection->clearSelection();//清除现有模型索引
m_selection->setCurrentIndex(index,QItemSelectionModel::Select);//定位到单元格
}
4)设置主窗口单元格内容
当设置文字按钮(btn_setText)被点击时发射信号,信号由主窗口接收。
void TDialogLcoate::on_btn_setText_clicked()
{
qDebug()<<"btn_setText_clicked";
int row=ui->spinRow->value();
int col=ui->spinCol->value();
QString text=ui->lineEdit->text();
emit changeCellText(row,col,text);//返回界面内容
}
主函数的槽函数,接收到信号后,设置单元格内容
//主函数代码
connect(dlaLocate,SIGNAL(changeCellText(int,int,QString)),this,SLOT(changeCellText_tdialoglcoate_setCell(int,int,QString)));//点击设置文字后
//主函数代码
void MainWindow::changeCellText_tdialoglcoate_setCell(int row, int col, QString text)
{
QStandardItem *item=new QStandardItem(row,col);//定位单元格
QString oldText=item->text();//获取单元格文字
if(item->text()==text)//对比文字
{
qDebug()<<"单元格内容未改变";
return;
}
item->setData(text,Qt::DisplayRole);//设置单元格文字
m_model->setItem(row,col,item);
qDebug()<<"单元格内容在\"定位单元格设置文字\"窗口被修改";
qDebug()<<QString("old Data=%1,new data=%2").arg(oldText).arg(text);
}
5)设置主窗口定位单元格Action状态
重定义showEvent()与closeEvent()函数,在TDialogLcoate窗口被打开和关闭时发射信号,主窗口接收返回的信号设置Action的状态。
void TDialogLcoate::showEvent(QShowEvent *event)
{
event->accept();//接受事件
emit changeActionEnable(false);//发射信号
}
void TDialogLcoate::closeEvent(QCloseEvent *event)
{
event->accept();//接受事件
emit changeActionEnable(true);
}
设置主窗口接收到信后执行修改Action状态的函数
//主函数代码
connect(dlaLocate,SIGNAL(changeActionEnable(bool)),this,SLOT(showAndcolse_tdialoglcoate_setAction(bool)));//窗口打开/关闭
void MainWindow::showAndcolse_tdialoglcoate_setAction(bool en)
{
if(en==false)
qDebug()<<"定位单元格设置文字窗口被打开";
else
qDebug()<<"定位单元格设置文字窗口被关闭";
ui->act_locateTheCell->setEnabled(en);
}
6)TDialogLocate其它成员函数
//public 供外部访问
bool TDialogLcoate::read_chkAddCol_static()//返回列增状态
{
return ui->chk_addCol->isChecked();
}
bool TDialogLcoate::read_chkAddRow_static()//返回行增状态
{
return ui->chk_addRow->isChecked();
}
int TDialogLcoate::read_spinboxColValue()//返回容器值
{
return ui->spinCol->value();
}
int TDialogLcoate::read_spinboxRowValue()//返回容器值
{
return ui->spinRow->value();
}
7)TDialogLcoate 类头文件定义
class TDialogLcoate : public QDialog
{
Q_OBJECT
public:
explicit TDialogLcoate(QWidget *parent = nullptr);
~TDialogLcoate();
void setSpinAndText(QStandardItem &item);//接收数据
void setSpinBoxMinAndMaxValue(int rowMax,int colMax);//设置spinBox最大值最小值
bool read_chkAddCol_static();//返回列增状态
bool read_chkAddRow_static();//返回行增状态
int read_spinboxColValue();//读取容器值
int read_spinboxRowValue();
protected:
void showEvent(QShowEvent *event);
void closeEvent(QCloseEvent* event);
int colvalueIni;
int rowvalueIni;
signals://对话框发射的信号
void changeActionEnable(bool en);//设置主窗口Action状态信号
void changeCellText(int row,int col,QString text);//文字修改信号
void changedSpinBoxValue(int row,int col);//value值变化信号
private slots:
void on_btn_setText_clicked();
void emitSpinBoxValueChangedToMainwindows(int n);
void on_chk_addCol_toggled(bool checked);
void on_chk_addRow_toggled(bool checked);
private:
Ui::TDialogLcoate *ui;
};
2、主函数使用
主窗口Action点击后,设置非模态显示窗口。
void MainWindow::on_act_locateTheCell_triggered()
{
if(dlaLocate==nullptr)
dlaLocate=new TDialogLcoate(this);
dlaLocate->setAttribute(Qt::WA_DeleteOnClose);//对话框关闭时自动删除
dlaLocate->setWindowFlag(Qt::WindowStaysOnTopHint);//设置对话框特性StayOnTop
QModelIndex index=m_selection->currentIndex();
QStandardItem* item;
item=m_model->itemFromIndex(index);
dlaLocate->setSpinAndText(*item);//初始化spinBox容器和lineEdit容器数据
dlaLocate->setSpinBoxMinAndMaxValue(m_model->rowCount()-1,m_model->columnCount()-1);//设置容器最大值
connect(dlaLocate,SIGNAL(changeActionEnable(bool)),this,SLOT(showAndcolse_tdialoglcoate_setAction(bool)));//窗口打开/关闭
connect(dlaLocate,SIGNAL(changeCellText(int,int,QString)),this,SLOT(changeCellText_tdialoglcoate_setCell(int,int,QString)));//点击设置文字后
connect(dlaLocate,SIGNAL(changedSpinBoxValue(int,int)),this,SLOT(spinBoxValueChanged_tdialoglcoate(int, int)));//定位单元格
connect(m_selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(updata_tdialoglcoate_value(const QModelIndex, const QModelIndex)));
//非模态方式显示对话框
dlaLocate->setModal(false);
dlaLocate->show();
}
上面setAttribute(Qt::WA_DeleteOnClose)函数,在对话框关闭时,自动删除对象。不使用此函数,在关闭对话框后,对话框只是隐藏,只有在关闭主窗口时才会被自动删除。
setWindowFlag()函数就是设置窗口属性,参数Qt::WindowStaysOnTopHint告知窗口系统,该窗口应该停留在所有其他窗口的上面。
下面为点击主窗口单元格更新dlaLocate窗口的行列坐标:
void MainWindow::updata_tdialoglcoate_value(const QModelIndex ¤t, const QModelIndex &previous)
{
qDebug()<<"updata_tdialoglcoate_value";
//主窗口选择变化,更新数据
Q_UNUSED(previous);
QStandardItem* item;
item=m_model->itemFromIndex(current);
dlaLocate->setSpinAndText(*item);
}
四、QMainWindow头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "tdialogheaders.h"
#include "tdialoglcoate.h"
#define COLUMNCOUNT 4
#define ROWCOUNT 6
class QStandardItemModel;
class QItemSelectionModel;
class QLabel;
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_act_exit_triggered();
private:
int col=COLUMNCOUNT;
int row=ROWCOUNT;
QStandardItemModel *m_model;//数据模型
QItemSelectionModel *m_selection;//选择模型
TDialogHeaders* dlgSetHeaders=nullptr;//定义TDialogHeaders指针类型变量
TDialogLcoate* dlaLocate=nullptr;
private:
void uiIni();
void tableViewIni();
QLabel *selectXy;
QLabel *data_xy;
QLabel *cellContent;
QLabel *data_content;
private slots:
void do_model_currentChanged(const QModelIndex ¤t,const QModelIndex &previous);
void on_act_setRC_triggered();
void on_act_setHeader_triggered();
void on_act_locateTheCell_triggered();
void updata_tdialoglcoate_value(const QModelIndex ¤t,const QModelIndex &previous);
void showAndcolse_tdialoglcoate_setAction(bool en);
void changeCellText_tdialoglcoate_setCell(int row,int col,QString text);
void spinBoxValueChanged_tdialoglcoate(int row,int col);
protected:
void closeEvent(QCloseEvent* event);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H