中文静态网站下载,哈尔滨网页制作人才招聘,江西网站优化,郑州哪里做网站最好本篇介绍到的对话框及其调用实例较为复杂但十分详细#xff0c;如果做了解可以先参考#xff1a;QT从入门到实战x篇_13_模态和非模态对话框创建。 文章目录 1. 对话框的不同调用方式2. 对话框QWDialogSize 的创建和使用2.1 创建对话框QWDialogSize2.2 对话框的调用和返回值 …本篇介绍到的对话框及其调用实例较为复杂但十分详细如果做了解可以先参考QT从入门到实战x篇_13_模态和非模态对话框创建。 文章目录 1. 对话框的不同调用方式2. 对话框QWDialogSize 的创建和使用2.1 创建对话框QWDialogSize2.2 对话框的调用和返回值 3. 对话框QWDialogHeaders 的创建和使用3.1 对话框的生存期3.2 QWDialogHeaders 的定义和实现3.3 QWDialogHeaders 对话框的使用 4. 对话框QWDialogLocate 的创建与使用4.1 非模态对话框4.2 对话框的创建与调用对话框与主窗口的交互4.3 对话框中操作主窗口4.4 主窗口中操作对话框4.5 窗口的CloseEvent事件及事件简介 5. 利用信号与槽实现对话框及主窗口交互操作6. 源码6.1 程序框架6.2 可视化UI设计6.2.1 qwdialogsize.ui6.2.2 qwdialogheaders.ui6.2.3 qwdialoglocate.ui6.2.4 mainwindow.ui 6.3 代码6.3.1 qwdialogsize6.3.2 qwdialogheaders6.3.3 qwdialoglocate6.3.4 mainwindow 1. 对话框的不同调用方式
在一个应用程序设计中为了实现一些特定的功能必须设计自定义对话框。自定义对话框的设计一般从QDialog 继承并且可以采用 UI 设计器可视化地设计对话框。对话框的调用一般包括创建对话框、传递数据给对话框、显示对话框获取输入、判断对话框单击按钮的返回类型、获取对话框输入数据等过程。
本节将通过实例 samp6_2 来详细介绍这些原理。图6-5是实例 samp6_2 的主窗口及其设置表格行列数的对话框。 主窗口采用 QTableView 和 QStandardItemModel、QItemSelectionModel 构成一个通用的数据表格编辑器设计了3 个对话框分别具有不同的功能并且展示对话框不同调用方式的特点。
设置表格行列数对话框QWDialogSize
该对话框每次动态创建以模态方式显示(必须关闭此对话框才可以返回主窗口操作)对话框关闭后获取返回值用于设置主窗口的表格行数和列数并且删除对话框对象释放内存。
这种对话框创建和调用方式适用于比较简单不需要从主窗口传递大量数据做初始化的对话框调用后删除对话框对象可以节约内存。 设置表头标题对话框QWDialogHeaders
图 6-6 是设置表格表头标题的对话框该对话框在父窗口(本例中就是主窗口)存续期间只创建一次创建时传递表格表头字符串列表给对话框在对话框里编辑表头标题后主窗口获取编辑之后的表头标题。对话框以模态方式显示关闭后只是隐藏并不删除对象下次再调用时只是打开已创建的对话框对象。 这种创建和调用方式适用于比较复杂的对话框需要从父窗口传递大量数据做对话框初始化。下次调用时不需要重复初始化能提高对话框调用速度但是会一直占用内存直到父窗口删除时对话框才从内存中删除。
单元格定位与文字设置对话框QWDialogLocate
图 6-7 是单元格定位和文字设置对话框该对话框以非模态方式调用显示对话框时还可以对主窗口进行操作对话框只是浮动在窗口上方。在对话框里可以定位主窗口表格的某个单元格并设置其文字内容在主窗口上的表格中单击鼠标时单元格的行号、列号也会更新在对话框中。对话框关闭后将自动删除释放内存。 这种对话框适用于主窗口与对话框需要交互操作的情况例如用于查找和替换操作的对话框。 2. 对话框QWDialogSize 的创建和使用
2.1 创建对话框QWDialogSize
实例主窗口从QMainWindow 继承主窗口用一个QTableView 组件作为界面中心组件设计几个 Action 用于创建主工具栏按钮。主窗口采用 QStandardItemModel 作为数据模型QItemSelectionModel 作为选择模型界面和主窗口 Model/View 结构的设计可参考 5.4 节的实例本节不再详述。
在项目主窗口建立后要创建如图 6-5 所示的设置表格行列数的对话框单击 Qt Creator 的菜单项“File”-“New File or Project”选择Qt类别下的“Qt Designer Form Class”创建可视化设计的对话框类。在随后出现的向导里选择窗口模板为 Dialog without Buttons并设置自定义对话框的类名。
设置创建的对话框类名称为 QWDialogSize系统自动生成 qwdialogsize.h、qwdialogsize.cpp和qwdialogsizeui3个文件。
QWDialogSize 对话框的界面设计在 UI 设计器里进行放置界面组件并设置好布局
2.2 对话框的调用和返回值
设计 QWDialogSize 对话框的界面时在上面放置了两个 QPushButton 按钮并分别命名为btnOK 和 btnCancel分别是“确定”和“取消”按钮用于获取对话框运行时用户的选择。那么如何获得用户操作的返回值呢
在信号与槽编辑器里将 btnOK的clicked()信号与对话框的 accept()槽关联,将 btnCancel 的 clicked()信号与对话框的 reject()槽关联即可如图 6-8 所示 单击“确定”按钮会执行 accept()槽(或在代码里调用 accept()槽函数也是一样的)这会关闭对话框(默认情况下对话框只是被隐藏并不被删除)并返回 QDialog::Accepted 作为 exec()函数的返回值。
单击“取消”按钮会执行 reject()槽函数也会关闭对话框并返回QDialog::Rejected 作为 exec()函数的返回值。
完成后的QWDialogSize的类完整定义如下
#ifndef QWDIALOGSIZE_H
#define QWDIALOGSIZE_H#include QDialognamespace Ui {
class QWDialogSize;
}class QWDialogSize : public QDialog
{Q_OBJECTpublic:explicit QWDialogSize(QWidget *parent 0);~QWDialogSize();int rowCount();//获取对话框输入的行数int columnCount();//获取对话框输入的列数void setRowColumn(int row, int column); //初始对话框上两个SpinBox的值private slots:private:Ui::QWDialogSize *ui;
};#endif // QWDIALOGSIZE_H
在QWDialogSize 的类定义中定义3 个 public 函数用于与对话框调用者的数据交互。因为窗体上的组件都是私有成员外界不能直接访问界面组件只能通过接口函数访问。
下面是类的接口函数实现代码。在析构函数中弹出一个消息提示对话框以便观察对话框是何时被删除的。
#include qwdialogsize.h
#include ui_qwdialogsize.h#include QMessageBoxQWDialogSize::QWDialogSize(QWidget *parent) :QDialog(parent),ui(new Ui::QWDialogSize)
{ui-setupUi(this);
}QWDialogSize::~QWDialogSize()
{QMessageBox::information(this,info,Setting dialog object is deleted );delete ui;
}int QWDialogSize::rowCount()
{ //用于主窗口调用获得行数的输入值return ui-spinBoxRow-value();
}int QWDialogSize::columnCount()
{//用于主窗口调用获得列数的输入值return ui-spinBoxColumn-value();
}void QWDialogSize::setRowColumn(int row, int column)
{ //初始化数据显示ui-spinBoxRow-setValue(row);ui-spinBoxColumn-setValue(column);
}
下面是主窗口中的“设置行数列数”工具栏按钮的响应代码用于创建、显示对话框并读取对话框上设置的行数、列数。
void MainWindow::on_actTab_SetSize_triggered()
{ //模态对话框动态创建用过后删除QWDialogSize *dlgTableSizenew QWDialogSize(this); //创建对话框
// dlgTableSize-setAttribute(Qt::WA_DeleteOnClose);
//对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框
//如果需要获取对话框的返回值不能设置该属性可以在调用完对话框后删除对话框Qt::WindowFlags flagsdlgTableSize-windowFlags();dlgTableSize-setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小dlgTableSize-setRowColumn(theModel-rowCount(),theModel-columnCount()); //对话框数据初始化int retdlgTableSize-exec();// 以模态方式显示对话框用户关闭对话框时返回 DialogCode值if (retQDialog::Accepted) //OK键被按下,对话框关闭若设置了setAttribute(Qt::WA_DeleteOnClose)对话框被释放无法获得返回值{ //OK键被按下获取对话框上的输入设置行数和列数int colsdlgTableSize-columnCount();theModel-setColumnCount(cols);int rowsdlgTableSize-rowCount();theModel-setRowCount(rows);}delete dlgTableSize; //删除对话框
}从代码中可以看到每次单击此工具栏按钮时对话框都被重新创建。创建后用 QDialog 的setWindowFlags()函数将对话框设置为固定大小然后调用对话框的自定义函数setRowColumn(),将主窗口数据模型 theModel 的现有的行数和列数显示到对话框上的两个 SpinBox 组件里。
调用对话框的 exec()函数以模态显示的方式显示对话框。模态显示方式下用户只能在对话框上操作不能操作主窗口主程序也在此处等待 exec()函数的返回结果。
当用户单击“确定”按钮关闭对话框后exec()返回结果为 QDialog::Accepted主程序获得此返回结果后通过对话框的自定义函数 columnCount()和rowCount()获得对话框上新输入的列数和行数然后设置为数据模型的列数和行数。 最后使用 delete 删除创建的对话框对象释放内存。所以关闭对话框时,会出现 QWDialogSize析构函数里的消息提示对话框。
注意在对话框上单击按钮或关闭对话框时对话框只是隐藏(缺省的)而并没有从内存中删除如果对话框一关闭就自动删除则在后面调用对话框的自定义函数获得输入的行数和列数时会出现严重错误
3. 对话框QWDialogHeaders 的创建和使用
3.1 对话框的生存期
对话框的生存期是指它从创建到删除的存续区间。前面介绍的设置表格行数和列数的对话框的生存期只在调用它的按钮的槽函数里因为对话框是动态创建的调用结束后就会被删除。
而对于图 6-6 所示的设置表头标题对话框我们希望在主窗口里首次调用时创建它对话框关闭时并不删除只是隐藏下次调用时再次显示此对话框。
只有在主窗口释放时该对话框才释放所以这个对话框的生存期在主窗口存续期间。
3.2 QWDialogHeaders 的定义和实现
设置表头标题的对话框类是 QWDialogHeaders它也是从 QDialog 继承的可视对话框类。其界面显示使用 QListView 组件用 QStringListModel 变量管理字符串列表数据构成 Model/View结构。对话框上同样有“确定”和“取消”两个按钮设置与对话框的 accept()和 reject()槽关联。
QWDialogHeaders 类的定义如下:
#include qwdialogheaders.h
#include ui_qwdialogheaders.h#include QMessageBoxQWDialogHeaders::QWDialogHeaders(QWidget *parent) :QDialog(parent),ui(new Ui::QWDialogHeaders)
{ui-setupUi(this);model new QStringListModel;ui-listView-setModel(model);
}QWDialogHeaders::~QWDialogHeaders()
{QMessageBox::information(this,info,Setting dialog object is deleted );delete ui;
}void QWDialogHeaders::setHeaderList(QStringList headers)
{model-setStringList(headers);
}QStringList QWDialogHeaders::headerList()
{return model-stringList();
}3.3 QWDialogHeaders 对话框的使用
因为要在主窗口中重复调用此对话框所以在 MainWindow 的 private 部分定义一个QWDialogHeaders 类型的指针变量并且将此指针初始化设置为NULL用于判断对话框是否已经被创建。在MainWindow中的定义如下:
QWDialogHeaders *dlgSetHeadersNULL;//设置表头文字对话框, 一次创建exec()重复调用
下面是主窗口工具栏上的“设置表头标题”按钮的响应代码
void MainWindow::on_actTab_SetHeader_triggered()
{//一次创建多次调用对话框关闭时只是隐藏if (dlgSetHeadersNULL) //如果对象没有被创建过就创建对象dlgSetHeaders new QWDialogHeaders(this);if (dlgSetHeaders-headerList().count()!theModel-columnCount()){//如果表头列数变化重新初始化QStringList strList;for (int i0;itheModel-columnCount();i)//获取现有的表头标题strList.append(theModel-headerData(i,Qt::Horizontal,Qt::DisplayRole).toString());dlgSetHeaders-setHeaderList(strList);//用于对话框初始化显示}int retdlgSetHeaders-exec();// 以模态方式显示对话框if (retQDialog::Accepted) //OK键被按下{QStringList strListdlgSetHeaders-headerList();//获取对话框上修改后的StringListtheModel-setHorizontalHeaderLabels(strList);// 设置模型的表头标题}
}在这段代码中首先判断主窗口的成员变量 dlgSetHeaders 是否为 NULL如果为 NULL(初始化为NULL)说明对话框还没有被创建就创建对话框。 初始化的工作是获取主窗口数据模型现有的表头标题然后调用对话框的自定义函数setHeaderList()设置其为对话框的数据源。 使用 exec()函数模态显示对话框然后在“确定”按钮被单击时获取对话框上输入的字符串列表设置为主窗口数据模型的表头标题。
注意这里在结束对话框操作后并没有使用 delele 操作删除对话框对象这样对话框就只是隐藏它还在内存中。关闭对话框时不会出现析构函数里的消息提示对话框。
对话框创建时传递主窗口的指针作为对话框的父对象即:
dlgSetHeaders new QWDialogHeaders(this);
所以主窗口释放时才会自动删除此对话框对象也就是程序退出时才删除此对话框才会出现QWDialogHeaders 析构函数里的消息提示对话框。(此处涉及到了对象树的知识可以参考QT从入门到实战x篇_04_对象树及坐标系)进行了解和学习。
4. 对话框QWDialogLocate 的创建与使用
4.1 非模态对话框
前面设计的两个对话框是以模态 (Modal) 方式显示的即用 QDialog::exec()函数显示。模态显示的对话框不允许鼠标再去单击其他窗口直到对话框退出。 若使用 QDialog::show()则能以非模态 (Modeless)方式显示对话框。非模态显示的对话框在显示后继续运行主程序还可以在主窗口上操作主窗口和非模态对话框之间可以交互控制。典型的例子是文字编辑软件里的“查找/替换”对话框。 图6-7 中的单元格定位与文字设置对话框以非模态方式显示对话框类是 QWDialogLocate,它有如下的一些功能。
主窗口每次调用此对话框时就会创建此对话框对象并以 StayOnTop 的方式显示对话框关闭时自动删除。在对话框中可以定位主窗口上 TableView 组件的单元格并设置单元格的文字。在主窗口的 TableView 组件中单击鼠标时如果对话框已创建则自动更新对话框上单元格的行号和列号 SpinBox 组件的值。主窗口上的 actTab_Locate 用于调用对话框调用时actTab_Locate 设置为禁用当对话框关闭时自动使能actTab_Locate。这样避免对话框显示时在主窗口上再次单击“定位单元格”按钮而在对话框关闭和释放后按钮又恢复为可用。
对话框QWDialogLocate 的类定义代码如下各接口函数的意义和实现在后面介绍。
#ifndef QWDIALOGLOCATE_H
#define QWDIALOGLOCATE_H#include QDialognamespace Ui {
class QWDialogLocate;
}class QWDialogLocate : public QDialog
{Q_OBJECTprivate:void closeEvent(QCloseEvent *event);void showEvent(QShowEvent *event);public:explicit QWDialogLocate(QWidget *parent 0);~QWDialogLocate();void setSpinRange(int rowCount, int colCount); //设置最大值void setSpinValue(int rowNo, int colNo);//设置初始值private slots:void on_btnSetText_clicked();private:Ui::QWDialogLocate *ui;
};#endif // QWDIALOGLOCATE_H4.2 对话框的创建与调用对话框与主窗口的交互
对话框QWDialogLocate 是从QDialog 继承而来的可视化设计的对话框类其界面设计不再详述。为了在主窗口中也能操作对话框需要保留对话框实例对象名所以在 MainWindow 定义对话框QWDialogLocate 的一个指针 dlgLocate并初始化为NULL。
QWDialogLocate *dlgLocateNULL;
主窗口上的 actTab_Locate 用于调用此对话框其 triggered()信号槽函数代码如下
void MainWindow::on_actTab_Locate_triggered()
{//创建 StayOnTop的对话框对话框关闭时自动删除//通过控制actTab_Locate的enable属性避免重复点击ui-actTab_Locate-setEnabled(false);dlgLocate new QWDialogLocate(this); //创建对话框传递指针dlgLocate-setAttribute(Qt::WA_DeleteOnClose); //对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框Qt::WindowFlags flagsdlgLocate-windowFlags(); //获取已有flags
//对话框设置为固定大小和StayOnTop
// dlgLocate-setWindowFlags(flags |Qt::MSWindowsFixedSizeDialogHint |Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTopdlgLocate-setWindowFlags(flags | Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTop
//对话框初始化设置dlgLocate-setSpinRange(theModel-rowCount(),theModel-columnCount());QModelIndex curIndextheSelection-currentIndex();if (curIndex.isValid())dlgLocate-setSpinValue(curIndex.row(),curIndex.column());dlgLocate-show(); //非模态显示对话框
}在这段代码中使用QWidget::setAttribute()函数将对话框设置为关闭时自动删除
dlgLocate-setAttribute(Qt::WA_DeleteOnClose);
setAttribute()用于对窗体的一些属性进行设置当设置为 Qt::WA_DeleteOnClose 时窗口关闭时会自动删除以释放内存。这与前面两个对话框是不同的前面两个对话框在关闭时缺省是隐藏自己除非显式地使用 delete 进行删除。 程序还调用QWidget::setWindowFlags()将对话框设置为StayOnTop 显示
dlgLocate-setWindowFlags(flags | Qt::WindowStaysOnTopHint);
对话框窗口效果设置后再设置其初始数据然后调用 show()显示对话框。显示对话框后主程序继续运行不会等待对话框的返回结果。鼠标可以操作主窗口上的界面但是因为actTab_Locate 被禁用了不能再重复单击“定位单元格”按钮。
4.3 对话框中操作主窗口
在对话框上单击“设定文字”按钮会在主窗口中定位到指定的单元格并设定为输入的文字按钮的代码如下
void QWDialogLocate::on_btnSetText_clicked()
{//定位到单元格并设置字符串int rowui-spinBoxRow-value(); //行号int colui-spinBoxColumn-value();//列号MainWindow *parWind (MainWindow*)parentWidget(); //获取主窗口parWind-setACellText(row,col,ui-edtCaption-text()); //设置单元格文字if (ui-chkBoxRow-isChecked()) //行增ui-spinBoxRow-setValue(1ui-spinBoxRow-value());if (ui-chkBoxColumn-isChecked()) //列增ui-spinBoxColumn-setValue(1ui-spinBoxColumn-value());
}想要在对话框中操作主窗口就需要获取主窗口对象调用主窗口的函数并传递参数。在上面的代码中通过下面一行语句获得主窗口对象
MainWindow *parWind (MainWindow*)parentWidget(); //获取主窗口
parentWidget()是QWidget 类的一个函数指向父窗口。在创建此对话框时将主窗口的指针传递给对话框的构造函数即:
dlgLocate new QWDialogLocate(this);
所以对话框的 parentWidget 指向主窗口。
然后调用主窗口的一个自定义的 public 函数 setACellText()传递行号、列号和字符串由主窗口更新指定单元格的文字。下面是主窗口的setACellText()函数的代码。
void MainWindow::setACellText(int row, int column, QString text)
{//定位到单元格并设置字符串QModelIndex indextheModel-index(row,column);//获取模型索引theSelection-clearSelection(); //清除现有选择theSelection-setCurrentIndex(index,QItemSelectionModel::Select); //定位到单元格theModel-setData(index,text,Qt::DisplayRole);//设置单元格字符串
}这样就实现了在对话框里对主窗口进行的操作主要是获取主窗口对象然后调用相应的函数。
4.4 主窗口中操作对话框
在主窗口上用鼠标单击 TableView 组件的某个单元格时如果单元格定位对话框 dlgLocate 已经存在就将单元格的行号、列号更新到对话框上实现代码如下:
void MainWindow::on_tableView_clicked(const QModelIndex index)
{//单击单元格时将单元格的行号、列号设置到对话框上if (dlgLocate!NULL) //对话框存在dlgLocate-setSpinValue(index.row(),index.column());
}因为主窗口中定义了对话框的指针只要它不为 NULL就说明对话框存在调用对话框的-个自定义函数 setSpinValue()刷新对话框显示界面。QWDialogLocate 的 setSpinValue()函数实现如下:
void QWDialogLocate::setSpinValue(int rowNo, int colNo)
{//设置SpinBox数值ui-spinBoxRow-setValue(rowNo);ui-spinBoxColumn-setValue(colNo);
}4.5 窗口的CloseEvent事件及事件简介
对话框和主窗口之间互相操作的关键是要有对方对象的指针然后才能传递参数并调用对方的函数。在对话框关闭时还需要做一些处理: 将主窗口的 actTab_Locate 重新设置为使能将主窗口的指向对话框的指针 dlgLocate 重新设置为NULL。 由于对话框 dlgLocate 是以非模态方式运行的程序无法等待对话框结束后作出响应但是可以利用窗口的 CloseEvent 事件。
事件(event)是由窗口系统产生的由某些操作触发的特殊函数例如鼠标操作、键盘操作的一些事件还有窗口显示、关闭、绘制等相关的事件。从QWidget 继承的窗口部件常用的事件函数有如下几种。
closeEvent(): 窗口关闭时触发的事件通常在此事件做窗口关闭时的一些处理例如显示 一个对话框询问是否关闭窗口。showEvent():窗口显示时触发的事件。paintEvent():窗口绘制事件第8章介绍绘图时会用到。mouseMoveEvent(): 鼠标移动事件。mousePressEvent():鼠标键按下事件mouseReleaseEvent(): 鼠标键释放事件。keyPressEvent():键盘按键按下事件。keyReleaseEvent():键盘按键释放事件
要利用某个事件进行一些处理需要在窗口类里重定义事件函数并编写响应代码。在后面的例子中将逐渐演示一些事件的用法。
在本例中要利用对话框的 closeEvent()事件在类定义中声明了此事件的函数其实现代码如下
void QWDialogLocate::closeEvent(QCloseEvent *event)
{ //窗口关闭事件关闭时释放本窗口MainWindow *parWind (MainWindow*)parentWidget(); //获取父窗口指针parWind-setActLocateEnable(true);//使能 actTab_LocateparWind-setDlgLocateNull(); //将窗口指针设置为NULL
}在 closeEvent()事件里调用主窗口的两个函数将 actTab_Locate 重新使能将主窗口内指向对话框的指针设置为NULL。主窗口中这两个函数的实现代码如下:
void MainWindow::setActLocateEnable(bool enable)
{ui-actTab_Locate-setEnabled(enable);
}
void MainWindow::setDlgLocateNull()
{dlgLocateNULL;
}利用 closeEvent()事件可以询问窗口是否退出例如为主窗口添加 closeEvent()事件的处理代码如下:
void MainWindow::closeEvent(QCloseEvent *event)
{ //窗口关闭时询问是否退出QMessageBox::StandardButton resultQMessageBox::question(this, 确认, 确定要退出本程序吗,QMessageBox::Yes|QMessageBox::No |QMessageBox::Cancel,QMessageBox::No);if (resultQMessageBox::Yes)event-accept();elseevent-ignore();
}这样主窗口关闭时就会出现一个询问对话框如果不单击“Yes”按钮程序就不关闭;否则应用程序结束。
5. 利用信号与槽实现对话框及主窗口交互操作
前面设计的 QWDialogLocate 对话框与主窗口之间的交互采用互相引用的方式实现起来比较复杂。另外一种实现方式就是利用 Qt 的信号与槽机制设计相应的信号和槽将信号与槽关联起来在进行某个操作时发射信号槽函数自动响应。 对MainWindow和QWDialogLocate 稍作修改采用信号与槽机制实现交互操作下面是MainWindow 类定义中与此相关的定义包括两个槽函数和一个信号。 class MainWindow : public QMainWindow
{public slots:void setACellText(int row, int column, QString text);//设置一个单元格的内容void setActLocateEnable(bool enable);//设置actTab_Locate的enabled属性signals:void cellIndexChanged(int rowNo, int colNo);//当前单元格发生变化};两个槽函数是对话框操作主窗口时主窗口作出的响应。信号是主窗口上 tableView 的当前单元格发生变化时发射的一个信号以便对话框作出响应。 下面是两个槽函数的实现以及 tableView 的 clicked()信号的槽函数里发射自定义信号的代码代码中都无须引用对话框对象。
void MainWindow::setACellText(int row, int column, QString text)
{//定位到单元格并设置字符串QModelIndex indextheModel-index(row,column);//获取模型索引theSelection-clearSelection(); //清除现有选择theSelection-setCurrentIndex(index,QItemSelectionModel::Select); //定位到单元格theModel-setData(index,text,Qt::DisplayRole);//设置单元格字符串
}void MainWindow::setActLocateEnable(bool enable)
{ //设置actTab_Locate的enable属性ui-actTab_Locate-setEnabled(enable);
}void MainWindow::on_tableView_clicked(const QModelIndex index)
{//单击单元格时将单元格的行号、列号设置到对话框上emit cellIndexChanged(index.row(),index.column());
}
在主窗口上“定位单元格”按钮的响应代码与前面有较大的差别。
void MainWindow::on_actTab_Locate_triggered()
{//创建 StayOnTop的对话框对话框关闭时自动删除//通过控制actTab_Locate的enable属性避免重复点击
// ui-actTab_Locate-setEnabled(false);QWDialogLocate *dlgLocate;//定位单元格对话框show()调用关闭时自己删除dlgLocate new QWDialogLocate(this); //创建对话框传递指针dlgLocate-setAttribute(Qt::WA_DeleteOnClose); //对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框Qt::WindowFlags flagsdlgLocate-windowFlags(); //获取已有flags
//对话框设置为固定大小和StayOnTop
// dlgLocate-setWindowFlags(flags |Qt::MSWindowsFixedSizeDialogHint |Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTopdlgLocate-setWindowFlags(flags | Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTop
//对话框初始化设置dlgLocate-setSpinRange(theModel-rowCount(),theModel-columnCount());QModelIndex curIndextheSelection-currentIndex();if (curIndex.isValid())dlgLocate-setSpinValue(curIndex.row(),curIndex.column());//对话框释放信号设置单元格文字connect(dlgLocate,SIGNAL(changeCellText(int,int,QString)),this,SLOT(setACellText(int,int,QString)));//对话框是否信号设置action的属性connect(dlgLocate,SIGNAL(changeActionEnable(bool)),this,SLOT(setActLocateEnable(bool)));//主窗口是否信号修改对话框上的spinBox的值connect(this,SIGNAL(cellIndexChanged(int,int)),dlgLocate,SLOT(setSpinValue(int,int)));dlgLocate-show(); //非模态显示对话框
// this-show();
}在这里对话框变量声明为了局部变量不再需要在主窗口类里保存对话框的指针。这段代码的关键是设置了3 对信号与槽的关联。 在QWDialogLocate 类定义中与信号和槽相关的定义如下。
class QWDialogLocate : public QDialog
{
private:void closeEvent(QCloseEvent *event);void showEvent(QShowEvent *event);public slots:void setSpinValue(int rowNo, int colNo);//响应主窗口信号设置spinBox的值signals:void changeCellText(int row, int column, QString text); //释放信号定位单元格并设置文字void changeActionEnable(bool en); //是否信号改变action的enable
};QWDialogLocate 自定义了一个槽函数和两个信号还增加了 showEvent()事件的处理用于对话框显示时发射信号使主窗口的 actTab_Locate 失效。这些槽函数以及发射信号的实现代码如下代码中没有出现对主窗口的引用。
void QWDialogLocate::closeEvent(QCloseEvent *event)
{ //窗口关闭 event,释放信号使 actTab_Locate 能用Q_UNUSED(event)emit changeActionEnable(true);
}void QWDialogLocate::showEvent(QShowEvent *event)
{//窗口显示 event,释放信号使 actTab_Locate 不能用Q_UNUSED(event)emit changeActionEnable(false);
}
void QWDialogLocate::setSpinValue(int rowNo, int colNo)
{//响应主窗口信号更新spinBox的值ui-spinBoxRow-setValue(rowNo);ui-spinBoxColumn-setValue(colNo);
}void QWDialogLocate::on_btnSetText_clicked()
{//定位到单元格并设置字符串int rowui-spinBoxRow-value(); //行号int colui-spinBoxColumn-value();//列号QString textui-edtCaption-text();//文字emit changeCellText(row,col,text);//释放信号if (ui-chkBoxRow-isChecked()) //行增ui-spinBoxRow-setValue(1ui-spinBoxRow-value());if (ui-chkBoxColumn-isChecked()) //列增ui-spinBoxColumn-setValue(1ui-spinBoxColumn-value());
}经过这样修改后的程序能实现与前面的实例完全相同的主窗口与对话框交互的功能但是与前面互相引用的方式不同这里使用 Qt 的信号与槽的机制无须获取对方的指针程序结构上更简单一些。
大家是不是看到这里就有些懵逼了没事后期真正涉及到主窗口与自定义对话框的交互那就用信号槽的方式整个源码及结构我放在底下。
6. 源码
6.1 程序框架 6.2 可视化UI设计
6.2.1 qwdialogsize.ui 6.2.2 qwdialogheaders.ui 6.2.3 qwdialoglocate.ui 6.2.4 mainwindow.ui 6.3 代码
6.3.1 qwdialogsize
1qwdialogsize.h
#ifndef QWDIALOGSIZE_H
#define QWDIALOGSIZE_H#include QDialognamespace Ui {
class QWDialogSize;
}class QWDialogSize : public QDialog
{Q_OBJECTpublic:explicit QWDialogSize(QWidget *parent 0);~QWDialogSize();int rowCount();//获取对话框输入的行数int columnCount();//获取对话框输入的列数void setRowColumn(int row, int column); //初始对话框上两个SpinBox的值private slots:private:Ui::QWDialogSize *ui;
};#endif // QWDIALOGSIZE_H
2qwdialogsize.cpp
#include qwdialogsize.h
#include ui_qwdialogsize.h#include QMessageBoxQWDialogSize::QWDialogSize(QWidget *parent) :QDialog(parent),ui(new Ui::QWDialogSize)
{ui-setupUi(this);
}QWDialogSize::~QWDialogSize()
{
// QMessageBox::information(this,提示,设置表格行列数对话框被删除);delete ui;
}int QWDialogSize::rowCount()
{ //用于主窗口调用获得行数的输入值return ui-spinBoxRow-value();
}int QWDialogSize::columnCount()
{//用于主窗口调用获得列数的输入值return ui-spinBoxColumn-value();
}void QWDialogSize::setRowColumn(int row, int column)
{ //初始化数据显示ui-spinBoxRow-setValue(row);ui-spinBoxColumn-setValue(column);
}6.3.2 qwdialogheaders
1qwdialogheaders.h
#ifndef QWDIALOGHEADERS_H
#define QWDIALOGHEADERS_H#include QDialog#include QStringListModelnamespace Ui {
class QWDialogHeaders;
}class QWDialogHeaders : public QDialog
{Q_OBJECTprivate:QStringListModel *model;public:explicit QWDialogHeaders(QWidget *parent 0);~QWDialogHeaders();void setHeaderList(QStringList headers);QStringList headerList();
private:Ui::QWDialogHeaders *ui;
};#endif // QWDIALOGHEADERS_H2qwdialogheaders.cpp
#include qwdialogheaders.h
#include ui_qwdialogheaders.hQWDialogHeaders::QWDialogHeaders(QWidget *parent) :QDialog(parent),ui(new Ui::QWDialogHeaders)
{ui-setupUi(this);model new QStringListModel;ui-listView-setModel(model);
}QWDialogHeaders::~QWDialogHeaders()
{delete ui;
}void QWDialogHeaders::setHeaderList(QStringList headers)
{model-setStringList(headers);
}QStringList QWDialogHeaders::headerList()
{return model-stringList();
}6.3.3 qwdialoglocate
1qwdialoglocate.h
#ifndef QWDIALOGLOCATE_H
#define QWDIALOGLOCATE_H#include QDialog
namespace Ui {
class QWDialogLocate;
}class QWDialogLocate : public QDialog
{Q_OBJECTprivate:void closeEvent(QCloseEvent *event);void showEvent(QShowEvent *event);public:explicit QWDialogLocate(QWidget *parent 0);~QWDialogLocate();void setSpinRange(int rowCount, int colCount); //设置最大值,用于初始化private slots:void on_btnSetText_clicked();public slots:void setSpinValue(int rowNo, int colNo);//响应主窗口信号设置spinBox的值signals:void changeCellText(int row, int column, QString text); //释放信号定位单元格并设置文字void changeActionEnable(bool en); //是否信号改变action的enableprivate:Ui::QWDialogLocate *ui;
};#endif // QWDIALOGLOCATE_H
2qwdialoglocate.cpp
#include qwdialoglocate.h
#include ui_qwdialoglocate.h#include QCloseEvent
#include mainwindow.hvoid QWDialogLocate::closeEvent(QCloseEvent *event)
{ //窗口关闭 event,释放信号使 actTab_Locate 能用Q_UNUSED(event)emit changeActionEnable(true);
}void QWDialogLocate::showEvent(QShowEvent *event)
{//窗口显示 event,释放信号使 actTab_Locate 不能用Q_UNUSED(event)emit changeActionEnable(false);
}QWDialogLocate::QWDialogLocate(QWidget *parent) :QDialog(parent),ui(new Ui::QWDialogLocate)
{ui-setupUi(this);
}QWDialogLocate::~QWDialogLocate()
{delete ui;
}void QWDialogLocate::setSpinRange(int rowCount, int colCount)
{//设置SpinBox输入最大值ui-spinBoxRow-setMaximum(rowCount-1);ui-spinBoxColumn-setMaximum(colCount-1);
}void QWDialogLocate::setSpinValue(int rowNo, int colNo)
{//响应主窗口信号更新spinBox的值ui-spinBoxRow-setValue(rowNo);ui-spinBoxColumn-setValue(colNo);
}void QWDialogLocate::on_btnSetText_clicked()
{//定位到单元格并设置字符串int rowui-spinBoxRow-value(); //行号int colui-spinBoxColumn-value();//列号QString textui-edtCaption-text();//文字emit changeCellText(row,col,text);//释放信号if (ui-chkBoxRow-isChecked()) //行增ui-spinBoxRow-setValue(1ui-spinBoxRow-value());if (ui-chkBoxColumn-isChecked()) //列增ui-spinBoxColumn-setValue(1ui-spinBoxColumn-value());
}
6.3.4 mainwindow
1mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include QMainWindow#include QLabel
#include QStandardItemModel
#include QItemSelectionModel
#include QModelIndex#include qwdialogheaders.h
#include qwdialoglocate.hclass QWDialogLocate;namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTprivate://用于状态栏的信息显示QLabel *LabCellPos; //当前单元格行列号QLabel *LabCellText; //当前单元格内容QStandardItemModel *theModel;//数据模型QItemSelectionModel *theSelection;//Item选择模型QWDialogHeaders *dlgSetHeadersNULL;//设置表头文字对话框, 一次创建exec()重复调用void closeEvent(QCloseEvent *event);//关闭窗口时间可以询问是否退出public:explicit MainWindow(QWidget *parent 0);~MainWindow();void selectACell(int row,int column);//选择一个单元格,由dlgLocate调用
private slots:void on_currentChanged(const QModelIndex current, const QModelIndex previous);void on_actTab_SetSize_triggered();void on_actTab_SetHeader_triggered();void on_actTab_Locate_triggered();void on_tableView_clicked(const QModelIndex index);public slots:void setACellText(int row, int column, QString text);//设置一个单元格的内容void setActLocateEnable(bool enable);//设置actTab_Locate的enabled属性signals:void cellIndexChanged(int rowNo, int colNo);//当前单元格发生变化private:Ui::MainWindow *ui;};#endif // MAINWINDOW_H
2mainwindow.cpp
#include mainwindow.h
#include ui_mainwindow.h#include QMessageBox
#include QCloseEvent#include qwdialogsize.hvoid MainWindow::closeEvent(QCloseEvent *event)
{ //窗口关闭时询问是否退出QMessageBox::StandardButton resultQMessageBox::question(this, 确认, 确定要退出本程序吗,QMessageBox::Yes|QMessageBox::No |QMessageBox::Cancel,QMessageBox::No);if (resultQMessageBox::Yes)event-accept();elseevent-ignore();
}MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui-setupUi(this);theModel new QStandardItemModel(10,5,this); //创建数据模型theSelection new QItemSelectionModel(theModel);//Item选择模型connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));//为tableView设置数据模型ui-tableView-setModel(theModel); //设置数据模型ui-tableView-setSelectionModel(theSelection);//设置选择模型setCentralWidget(ui-tableView); ////创建状态栏组件LabCellPos new QLabel(当前单元格,this);LabCellPos-setMinimumWidth(180);LabCellPos-setAlignment(Qt::AlignHCenter);LabCellText new QLabel(单元格内容,this);LabCellText-setMinimumWidth(200);ui-statusBar-addWidget(LabCellPos);ui-statusBar-addWidget(LabCellText);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::setActLocateEnable(bool enable)
{ //设置actTab_Locate的enable属性ui-actTab_Locate-setEnabled(enable);
}void MainWindow::selectACell(int row, int column)
{QModelIndex indextheModel-index(row,column);theSelection-clearSelection();theSelection-setCurrentIndex(index,QItemSelectionModel::Select);
}void MainWindow::setACellText(int row, int column, QString text)
{//定位到单元格并设置字符串QModelIndex indextheModel-index(row,column);//获取模型索引theSelection-clearSelection(); //清除现有选择theSelection-setCurrentIndex(index,QItemSelectionModel::Select); //定位到单元格theModel-setData(index,text,Qt::DisplayRole);//设置单元格字符串
}void MainWindow::on_currentChanged(const QModelIndex current, const QModelIndex previous)
{Q_UNUSED(previous)if (current.isValid()) //当前模型索引有效{LabCellPos-setText(QString::asprintf(当前单元格%d行%d列,current.row(),current.column())); //显示模型索引的行和列号QStandardItem *aItem;aItemtheModel-itemFromIndex(current); //从模型索引获得Itemthis-LabCellText-setText(单元格内容aItem-text()); //显示item的文字内容}
}void MainWindow::on_actTab_SetSize_triggered()
{ //模态对话框动态创建用过后删除QWDialogSize *dlgTableSizenew QWDialogSize(this); //创建对话框
// dlgTableSize-setAttribute(Qt::WA_DeleteOnClose);
//对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框
//如果需要获取对话框的返回值不能设置该属性可以在调用完对话框后删除对话框Qt::WindowFlags flagsdlgTableSize-windowFlags();dlgTableSize-setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小dlgTableSize-setRowColumn(theModel-rowCount(),theModel-columnCount()); //对话框数据初始化int retdlgTableSize-exec();// 以模态方式显示对话框用户关闭对话框时返回 DialogCode值if (retQDialog::Accepted) //OK键被按下,对话框关闭若设置了setAttribute(Qt::WA_DeleteOnClose)对话框被释放无法获得返回值{ //OK键被按下获取对话框上的输入设置行数和列数int colsdlgTableSize-columnCount();theModel-setColumnCount(cols);int rowsdlgTableSize-rowCount();theModel-setRowCount(rows);}delete dlgTableSize; //删除对话框
}void MainWindow::on_actTab_SetHeader_triggered()
{//一次创建多次调用对话框关闭时只是隐藏if (dlgSetHeadersNULL) //如果对象没有被创建过就创建对象dlgSetHeaders new QWDialogHeaders(this);if (dlgSetHeaders-headerList().count()!theModel-columnCount()){
//只需在创建时传递参数给对话框,由于对话框只是隐藏界面内容保存QStringList strList;for (int i0;itheModel-columnCount();i)//获取现有的表头标题strList.append(theModel-headerData(i,Qt::Horizontal,Qt::DisplayRole).toString());dlgSetHeaders-setHeaderList(strList);//用于对话框初始化显示}int retdlgSetHeaders-exec();// 以模态方式显示对话框if (retQDialog::Accepted) //OK键被按下{QStringList strListdlgSetHeaders-headerList();//获取对话框上修改后的StringListtheModel-setHorizontalHeaderLabels(strList);// 设置模型的表头标题}
}void MainWindow::on_actTab_Locate_triggered()
{//创建 StayOnTop的对话框对话框关闭时自动删除//通过控制actTab_Locate的enable属性避免重复点击
// ui-actTab_Locate-setEnabled(false);QWDialogLocate *dlgLocate;//定位单元格对话框show()调用关闭时自己删除dlgLocate new QWDialogLocate(this); //创建对话框传递指针dlgLocate-setAttribute(Qt::WA_DeleteOnClose); //对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框Qt::WindowFlags flagsdlgLocate-windowFlags(); //获取已有flags
//对话框设置为固定大小和StayOnTop
// dlgLocate-setWindowFlags(flags |Qt::MSWindowsFixedSizeDialogHint |Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTopdlgLocate-setWindowFlags(flags | Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTop
//对话框初始化设置dlgLocate-setSpinRange(theModel-rowCount(),theModel-columnCount());QModelIndex curIndextheSelection-currentIndex();if (curIndex.isValid())dlgLocate-setSpinValue(curIndex.row(),curIndex.column());//对话框释放信号设置单元格文字connect(dlgLocate,SIGNAL(changeCellText(int,int,QString)),this,SLOT(setACellText(int,int,QString)));//对话框是否信号设置action的属性connect(dlgLocate,SIGNAL(changeActionEnable(bool)),this,SLOT(setActLocateEnable(bool)));//主窗口是否信号修改对话框上的spinBox的值connect(this,SIGNAL(cellIndexChanged(int,int)),dlgLocate,SLOT(setSpinValue(int,int)));dlgLocate-show(); //非模态显示对话框
// this-show();
}void MainWindow::on_tableView_clicked(const QModelIndex index)
{//单击单元格时将单元格的行号、列号设置到对话框上emit cellIndexChanged(index.row(),index.column());
}