14-利用信号与槽实现交互操作
6.2.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 index=theModel->index(row,column);//获取模型索引
theSelection->clearSelection();
theSelection->setCurrentIndex(index,QItemSelectionModel::Select);
theModel->setData(index,text,Qt::DisplayRole);//设置单元格字符串
}
void MainWindow::setActLocateEnable(bool enable)
{ //设置actTab_Locate的enabled属性
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的对话框,对话框关闭时自动删除
QWDialogLocate *dlgLocate = new QWDialogLocate(this);
dlgLocate->setAttribute(Qt::WA_DeleteOnClose);
Qt::WindowFlags flags=dlgLocate->windowFlags();
dlgLocate->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
dlgLocate->setSpinRange(theModel->rowCount(),theModel->columnCount());
QModelIndex curIndex=theSelection->currentIndex();
if (curIndex.isValid())
dlgLocate->setSpinValue(curIndex.row(),curIndex.column());
//对话框发射信号,设置单元格文字
connect(dlgLocate,SIGNAL(changeCellText(int,int,QString&)),
this,SLOT(setACellText(int,int,QString&)));
//对话框发射信号,设置actTab_Locate的属性
connect(dlgLocate,SIGNAL(changeActionEnable(bool)),
this,SLOT(setActLocateEnable(bool)));
//主窗口发射信号,修改对话框上的spinBox的值
connect(this,SIGNAL(cellIndexChanged(int,int)),
dlgLocate,SLOT(setSpinValue(int,int)));
dlgLocate->show(); //非模态显示对话框
}
在这里,对话框变量声明为了局部变量,不再需要在主窗口类里保存对话框的指针。这段代码的关键是设置了3对信号与槽的关联。
在QWDialogLocate类定义中,与信号和槽相关的定义如下。
class QWDialogLocate : public QDialog
{
private:
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
private slots:
void on_btnSetText_clicked();
public slots:
void setSpinValue(int rowNo, int colNo);
signals:
void changeCellText(int row, int column, QString &text);
void changeActionEnable(bool en);
};
QWDialogLocate自定义了一个槽函数和两个信号,还增加了showEvent()事件的处理,用于对话框显示时发射信号使主窗口的actTab_Locate失效。这些槽函数,以及发射信号的实现代码如下,代码中没有出现对主窗口的引用。
void QWDialogLocate::closeEvent(QCloseEvent *event)
{ //窗口关闭事件, 发射信号使 actTab_Locate 能用
emit changeActionEnable(true);
}
void QWDialogLocate::showEvent(QShowEvent *event)
{//窗口显示事件, 发射信号使 actTab_Locate 不能用
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 row=ui->spinBoxRow->value(); //行号
int col=ui->spinBoxColumn->value();//列号
QString text=ui->edtCaption->text();//文字
emit changeCellText(row,col,text);//发射信号
if (ui->chkBoxRow->isChecked()) //行增
ui->spinBoxRow->setValue(1+ui->spinBoxRow->value());
if (ui->chkBoxColumn->isChecked()) //列增
ui->spinBoxColumn->setValue(1+ui->spinBoxColumn->value());
}
经过这样修改后的程序,能实现与前面的实例完全相同的主窗口与对话框交互的功能,但是与前面互相引用的方式不同,这里使用Qt的信号与槽的机制,无须获取对方的指针,程序结构上更简单一些。