【QT】自定义对话框及其调用

news2024/11/19 16:49:28

目录

1 对话框的不同调用方式

2 对话框QWDialogSize的创建和使用

3 对话框QWDialogHeaders的创建和使用

4 对话框QWDialogLocate的创建与使用

5 利用信号与槽实现交互操作

1 对话框的不同调用方式

         在一个应用程序设计中,为了实现一些特定的功能,必须设计自定义对话框。自定义对话框 的设计一般从 QDialog 继承,并且可以采用 UI 设计器可视化地设计对话框。对话框的调用一般包 括创建对话框、传递数据给对话框、显示对话框获取输入、判断对话框单击按钮的返回类型、获 取对话框输入数据等过程。
        本节将通过实例samp6_2来详细介绍这些原理。图6-5是实例samp6_2的主窗口,及其设置 表格行列数的对话框。
        主窗口采用QTableView和QStandardItemModel、QItemSelectionModel构成一个通用的数据 表格编辑器,设计了 3 个对话框,分别具有不同的功能,并且展示对话框不同调用方式的特点。
  • 设置表格行列数对话框QWDialogSize
        该对话框每次动态创建,以模态方式显示(必须关闭此对话框才可以返回主窗口操作),对话 框关闭后获取返回值,用于设置主窗口的表格行数和列数,并且删除对话框对象,释放内存。 这种对话框创建和调用方式适用于比较简单,不需要从主窗口传递大量数据做初始化的对话 框,调用后删除对话框对象可以节约内存。
  • 设置表头标题对话框QWDialogHeaders
        图6-6是设置表格表头标题的对话框,该对话框在父窗口(本例中就是主窗口)存续期间只 创建一次,创建时传递表格表头字符串列表给对话框,在对话框里编辑表头标题后,主窗口获取 编辑之后的表头标题。对话框以模态方式显示,关闭后只是隐藏,并不删除对象,下次再调用时 只是打开己创建的对话框对象。
图6-5 实例samp6_2主窗口及其设置表格行列数的对话框
图6-6  设置表格表头标题对话框
        这种创建和调用方式适用于比较复杂的对话框,需要从父窗口传递大量数据做对话框初始化。 下次调用时不需要重复初始化,能提高对话框调用速度,但是会一直占用内存,直到父窗口删除 时,对话框才从内存中删除。
  • 单元格定位与文字设置对话框QWDialogLocate
        图6-7是单元格定位和文字设置对话框,该对话框以非模态方式调用,显示对话框时还可以 对主窗口进行操作,对话框只是浮动在窗口上方。在对话框里可以定位主窗口表格的某个单元格 并设置其文字内容,在主窗口上的表格中单击鼠标时,单元格的行号、列号也会更新在对话框中。 对话框关闭后将自动删除,释放内存。
        这种对话框适用于主窗口与对话框需要交互操作的情况,例如用于查找和替换操作的对话框。
图6-7  浮动于主窗囗上方的对话框,可交互操作

2 对话框QWDialogSize的创建和使用

1 创建对话框QWDialogSize

        实例主窗口从QMainWindow继承,主窗口用一个QTableView组件作为界面中心组件,设计 几个Action用于创建主工具栏按钮。主窗口采用QStandardltemModel作为数据模型, QItemSelectionModel作为选择模型 。
        在项目主窗口建立后,要创建如图6-5所示的设置表格行列数的对话框,单击Qt Creator的菜 单项"File”-> “New File or Project",选择Qt类别下的“Qt Designer Form Class”,创建可视化设 计的对话框类。在随后出现的向导里,选择窗口模板为Dialog without Buttons,并设置自定义对话 框的类名。
        设置创建的对话框类名称为QWDialogSize,系统自动生成qwdialogsize.h、qwdialogsize.cpp 和qwdialogsize.ui3个文件。
        QWDialogSize对话框的界面设计在UI设计器里进行,放置界面组件并设置好布局。

2 对话框的调用和返回值

        设计QWDialogSize对话框的界面时,在上面放置了两个QPushButton按钮,并分别命名为 btnOK和btncancel,分别是“确定”和“取消”按钮,用于获取对话框运行时用户的选择。那么, 如何获得用户操作的返回值呢?
        在信号与槽编辑器里,将btnOK的clicked()信号与 对话框的accept()槽关联,将btnCancel的clicked()信号与 对话框的reject()槽关联即可,如图6-8所示。
图6-8 对话框设计时“确定”和 “取消”按钮的信号与槽关联
        单击“确定”按钮会执行accept()槽(或在代码里调 用accept()槽函数也是一样的),这会关闭对话框(默认情况下,对话框只是被隐藏,并不被删除), 并返回QDialog::Accepted作为exec()函数的返回值。
        单击“取消”按钮会执行reject()槽函数,也会关闭对话框,并返回QDialog::Rejected作为exec() 函数的返回值。
        完成后的QWDialogSize的类完整定义如下:
class QWDialogSize : public QDialog
{
    Q_OBJECT

public:
    explicit QWDialogSize(QWidget *parent = 0);
    ~QWDialogSize();

    int     rowCount();//获取对话框输入的行数
    int     columnCount();//获取对话框输入的列数
    void    setRowColumn(int row, int column); //初始对话框上两个SpinBox的值

private slots:

private:
    Ui::QWDialogSize *ui;
};

    在QWDialogSize的类定义中定义3个public函数,用于与对话框调用者的数据交互。因为窗体上的组件都是私有成员,外界不能直接访问界面组件,只能通过接口函数访问。

        下面是类的接口函数实现代码。在析构函数中弹出一个消息提示对话框,以便观察对话框是何时被删除的。

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);
}

   下面是主窗口中的“设置行数列数”工具栏按钮的响应代码,用于创建、显示对话框,并读框上设置的行数、列数。

void MainWindow::on_actTab_SetSize_triggered()
{ //模态对话框,动态创建,用过后删除
    QWDialogSize    *dlgTableSize=new QWDialogSize(this); //创建对话框
//对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框
//如果需要获取对话框的返回值,不能设置该属性,可以在调用完对话框后删除对话框
    Qt::WindowFlags    flags=dlgTableSize->windowFlags();
    dlgTableSize->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小

    dlgTableSize->setRowColumn(theModel->rowCount(),theModel->columnCount()); //对话框数据初始化

    int ret=dlgTableSize->exec();// 以模态方式显示对话框,用户关闭对话框时返回 DialogCode值
    if (ret==QDialog::Accepted) //OK键被按下,对话框关闭,若设置了setAttribute(Qt::WA_DeleteOnClose),对话框被释放,无法获得返回值
    { //OK键被按下,获取对话框上的输入,设置行数和列数
        int cols=dlgTableSize->columnCount();
        theModel->setColumnCount(cols);

        int rows=dlgTableSize->rowCount();
        theModel->setRowCount(rows);
    }
    delete dlgTableSize; //删除对话框
}

   从代码中可以看到,每次单击此工具栏按钮时,对话框都被重新创建。创建后用QDialog的setWindowFlags()函数将对话框设置为固定大小,然后调用对话框的自定义函数setRowColumn(),将主窗口数据模型theModel的现有的行数和列数显示到对话框上的两个SpinBox组件里。

        调用对话框的exec()函数,以模态显示的方式显示对话框。模态显示方式下,用户只能在对话框上操作,不能操作主窗口,主程序也在此处等待exec()函数的返回结果。

        当用户单击“确定”按钮关闭对话框后,exec()返回结果为QDialog::Accepted,主程序获得此返回结果后,通过对话框的自定义函数columnCount()和rowCount()获得对话框上新输入的列数和行数,然后设置为数据模型的列数和行数。

        最后使用delete删除创建的对话框对象,释放内存。所以,关闭对话框时,会出现QWDialogSize析构函数里的消息提示对话框。

        注意:在对话框上单击按钮或关闭对话框时,对话框只是隐藏(缺省的),而并没有从内存中删除。如果对话框一关闭就自动删除,则在后面调用对话框的自定义函数获得输入的行数和列数时会出现严重错误。

3 对话框QWDialogHeaders的创建和使用

1.对话框的生存期

        对话框的生存期是指它从创建到删除的存续区间。前面介绍的设置表格行数和列数的对话框的生存期只在调用它的按钮的槽函数里,因为对话框是动态创建的,调用结束后就会被删除。

        而对于图6-6所示的设置表头标题对话框,我们希望在主窗口里首次调用时创建它,对话框关闭时并不删除,只是隐藏,下次调用时再次显示此对话框。只有在主窗口释放时该对话框才释放,所以这个对话框的生存期在主窗口存续期间。

2.QWDialogHeaders的定义和实现

        设置表头标题的对话框类是QWDialogHeaders,它也是从QDialog继承的可视对话框类。其界面显示使用QListView组件,用QStringListModel变量管理字符串列表数据,构成Model/View

结构。对话框上同样有“确定”和“取消”两个按钮,设置与对话框的accept()和reject()槽关联。

        QWDialogHeaders类的定义如下:

class QWDialogHeaders : public QDialog
{
    Q_OBJECT

private:
    QStringListModel  *model;

public:
    explicit QWDialogHeaders(QWidget *parent = 0);
    ~QWDialogHeaders();

    void    setHeaderList(QStringList& headers);
    QStringList headerList();
private:
    Ui::QWDialogHeaders *ui;
};

 QWDialogSize类接口函数实现的代码如下:

QWDialogHeaders::QWDialogHeaders(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::QWDialogHeaders)
{
    ui->setupUi(this);
    model= new QStringListModel;
    ui->listView->setModel(model);
}

QWDialogHeaders::~QWDialogHeaders()
{
    QMessageBox::information(this,"提示","设置表头标题对话框被删除");
    delete ui;
}

void QWDialogHeaders::setHeaderList(QStringList &headers)
{
    model->setStringList(headers);
}

QStringList QWDialogHeaders::headerList()
{
    return  model->stringList();
}

3.QWDialogHeaders对话框的使用

        因为要在主窗口中重复调用此对话框,所以在MainWindow的private部分定义一个QWDialogHeaders类型的指针变量,并且将此指针初始化设置为NULL,用于判断对话框是否己经被创建。

        在MainWindow中的定义如下:

private:

    QWDiaIogHeaders *dlgSetHeaders=NULL;

        下面是主窗口工具栏上的“设置表头标题”按钮的响应代码。

void MainWindow::on_actTab_SetHeader_triggered()
{//一次创建,多次调用,对话框关闭时只是隐藏
    if (dlgSetHeaders==NULL) //如果对象没有被创建过,就创建对象
        dlgSetHeaders = new QWDialogHeaders(this);

    if (dlgSetHeaders->headerList().count()!=theModel->columnCount())
    {//如果表头列数变化,重新初始化
        QStringList strList;
        for (int i=0;i<theModel->columnCount();i++)//获取现有的表头标题
            strList.append(theModel->headerData(i,Qt::Horizontal,Qt::DisplayRole).toString());
        dlgSetHeaders->setHeaderList(strList);//用于对话框初始化显示
    }

    int ret=dlgSetHeaders->exec();// 以模态方式显示对话框
    if (ret==QDialog::Accepted) //OK键被按下
    {
        QStringList strList=dlgSetHeaders->headerList();//获取对话框上修改后的StringList
        theModel->setHorizontalHeaderLabels(strList);// 设置模型的表头标题
    }
}
   在这段代码中,首先判断主窗口的成员变量digsetHeaders是否为NULL,如果为NULL(初 始化为NULL),说明对话框还没有被创建,就创建对话框。
        初始化的工作是获取主窗口数据模型现有的表头标题,然后调用对话框的自定义函数 setHeaderList(),设置其为对话框的数据源。
        使用exec()函数模态显示对话框,然后在“确定”按钮被单击时获取对话框上输入的字符串 列表,设置为主窗口数据模型的表头标题。
        注意:这里在结束对话框操作后,并没有使用delete操作删除对话框对象,这样对话框就只是隐藏,它还在 内存中。关闭对话框时不会出现析构函数里的消息提示对话框。
        对话框创建时,传递主窗口的指针作为对话框的父对象,即:
dlgSetHeaders = new QWDialogHeaders(this);
        所以,主窗口释放时才会自动删除此对话框对象,也就是程序退出时才删除此对话框,才会 出现QWDialogHeaders析构函数里的消息提示对话框。

4 对话框QWDialogLocate的创建与使用

1.非模态对话框
        前面设计的两个对话框是以模态(Modal)方式显示的,即用QDialog::exec()函数显示。模态 显示的对话框不允许鼠标再去单击其他窗口,直到对话框退出。
        若使用QDialog::show(),则能以非模态(Modeless)方式显示对话框。非模态显示的对话框 在显示后继续运行主程序,还可以在主窗口上操作,主窗口和非模态对话框之间可以交互控制, 典型的例子是文字编辑软件里的“查找/替换”对话框。
        图6-7中的单元格定位与文字设置对话框以非模态方式显示,对话框类是QWDialogLocate, 它有如下的一些功能。
  • 主窗口每次调用此对话框时,就会创建此对话框对象,并以StayOnTop的方式显示,对话 框关闭时自动删除。
  • 在对话框中可以定位主窗口上TableView组件的单元格,并设置单元格的文字。
  • 在主窗口的组件中单击鼠标时,如果对话框己创建,则自动更新对话框上单元 格的行号和列号SpinBox组件的值。
  • 主窗口上的actTab_Locate用于调用对话框,调用时actTab_Locate设置为禁用,当对话框 关闭时自动使能actTab_Locate。这样避免对话框显示时,在主窗口上再次单击“定位单元 格”按钮,而在对话框关闭和释放后,按钮又恢复为可用。
        对话框QWDialogLocate的类定义代码如下,各接口函数的意义和实现在后面介绍。
class QWDialogLocate : public QDialog
{
    Q_OBJECT

private:
    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;
};
2.对话框的创建与调用
        对话框QWDialogLocate是从QDialog继承而来的可视化设计的对话框类,其界面设计不再详 述。为了在主窗口中也能操作对话框,需要保留对话框实例对象名,所以在MainWindow定义对 话框QWDialogLocate的一个指针dlgLocate,并初始化为NULL。
private:
    QWDialogLocate *dlgLocate=NULL;
        主窗口上的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    flags=dlgLocate->windowFlags(); //获取已有flags
//对话框设置为固定大小和StayOnTop
    dlgLocate->setWindowFlags(flags | Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTop
//对话框初始化设置
    dlgLocate->setSpinRange(theModel->rowCount(),theModel->columnCount());
    QModelIndex curIndex=theSelection->currentIndex();
    if (curIndex.isValid())
       dlgLocate->setSpinValue(curIndex.row(),curIndex.column());
    dlgLocate->show(); //非模态显示对话框
}
   在这段代码中,使用QWidget::setAttribute()函数将对话框设置为关闭时自动删除。
dlgLocate->setAttribute(Qt::WA_DeleteOnCIose);
        setAttribute()用于对窗体的一些属性进行设置,当设置为Qt::WA_DeleteOnClose时,窗口关闭 时会自动删除,以释放内存。这与前面两个对话框是不同的,前面两个对话框在关闭时缺省是隐 藏自己,除非显式地使用delete进行删除。
        程序还调用QWidget::setWindowFlags()将对话框设置为StayOnTop显示 。
dlgLocate->setWindowFIags(flags | Qt::WindowStaysOnTopHint);
        对话框窗口效果设置后,再设置其初始数据,然后调用show()显示对话框。显示对话框后, 主程序继续运行,不会等待对话框的返回结果。鼠标可以操作主窗口上的界面,但是因为 actTab_Locate被禁用了,不能再重复单击“定位单元格”按钮。
3.对话框中操作主窗口
        在对话框上单击“设定文字”按钮,会在主窗口中定位到指定的单元格,并设定为输入的文 字,按钮的代码如下:
void QWDialogLocate::on_btnSetText_clicked()
{//定位到单元格,并设置字符串
    int row=ui->spinBoxRow->value(); //行号
    int col=ui->spinBoxColumn->value();//列号

    MainWindow *parWind = (MainWindow*)parentWidget(); //获取主窗口
    parWind->setACellText(row,col,ui->edtCaption->text()); //设置单元格文字
    if (ui->chkBoxRow->isChecked()) //行增
        ui->spinBoxRow->setValue(1+ui->spinBoxRow->value());

    if (ui->chkBoxColumn->isChecked()) //列增
        ui->spinBoxColumn->setValue(1+ui->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 index=theModel->index(row,column);//获取模型索引
    theSelection->clearSelection(); //清除现有选择
    theSelection->setCurrentIndex(index,QItemSelectionModel::Select); //定位到单元格
    theModel->setData(index,text,Qt::DisplayRole);//设置单元格字符串
}
     这样就实现了在对话框里对主窗口进行的操作,主要是获取主窗口对象,然后调用相应的函数。
4.主窗口中操作对话框
        在主窗口上用鼠标单击TableView组件的某个单元格时,如果单元格定位对话框digLocate己 经存在,就将单元格的行号、列号更新到对话框上,实现代码如下:
void MainWindow::on_tableView_clicked(const QModeIIndex &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);
}
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_Locate
    parWind->setDlgLocateNull(); //将窗口指针设置为NULL
}

     在closeEvent()事件里,调用主窗口的两个函数,将actTab_Locate重新使能,将主窗口内指向对话框的指针设置为NULL。主窗口中这两个函数的实现代码如下:

void MainWindow::setActLocateEnable(bool enable)
{
    ui->actTab_Locate->setEnabled(enable);
}

void MainWindow::setDlgLocateNull()
{
    dlgLocate=NULL;
}

        利用closeEvent()事件,可以询问窗口是否退出,例如为主窗口添加closeEvent()事件的处理,代码如下:

void MainWindow::closeEvent(QCloseEvent *event)
{ //窗口关闭时询问是否退出
   QMessageBox::StandardButton result=QMessageBox::question(this, "确认",                         "确定要退出本程序吗?",                                                       QMessageBox::Yes|QMessageBox::No|
                      QMessageBox::Cancel,
                      QMessageBox::No);
    if (result==QMessageBox::Yes)
        event->accept();
    else
        event->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::setActLocateEnable(bool enable)
{ //设置actTab_Locate的enable属性
    ui->actTab_Locate->setEnabled(enable);
}

void MainWindow::selectACell(int row, int column)
{
    QModelIndex index=theModel->index(row,column);
    theSelection->clearSelection();
    theSelection->setCurrentIndex(index,QItemSelectionModel::Select);
}

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::on_actTab_Locate_triggered()
{//创建 StayOnTop的对话框,对话框关闭时自动删除
//通过控制actTab_Locate的enable属性避免重复点击
    QWDialogLocate  *dlgLocate;//定位单元格对话框,show()调用,关闭时自己删除
    dlgLocate = new QWDialogLocate(this); //创建对话框,传递指针
    dlgLocate->setAttribute(Qt::WA_DeleteOnClose); //对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框
    Qt::WindowFlags    flags=dlgLocate->windowFlags(); //获取已有flags
//对话框设置为固定大小和StayOnTop
    dlgLocate->setWindowFlags(flags | Qt::WindowStaysOnTopHint); //设置对话框固定大小,StayOnTop
//对话框初始化设置
    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&)));

//对话框是否信号,设置action的属性
    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
{
    Q_OBJECT
private:
    void closeEvent(QCloseEvent *event);
    void showEvent(QShowEvent *event);
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的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 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的信号与槽的机制,无须获取对方的指针,程序结构上更简单一些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1389675.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ceph的介绍与部署

目录 存储基础 单机存储设备 DAS&#xff08;直接附加存储&#xff0c;是直接接到计算机的主板总线上去的存储&#xff09; NAS&#xff08;网络附加存储&#xff0c;是通过网络附加到当前主机文件系统之上的存储&#xff09; SAN&#xff08;存储区域网络&#xff09; 单…

【C++】vector模拟实现过程中值得注意的点

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 前言 本篇文章旨在记录博主在模…

linux高级篇基础理论十二( 自动化运维工具Ansible )

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…

分布式存储

1 存储基础 1.1 单机存储设备 DAS&#xff08;直接附加存储&#xff0c;是直接接到计算机打的主板总线上去的存储&#xff09; UDE、SATA、SCSI、SAS、USB接口的磁盘 所谓的接口就是一种存储设备驱动下的磁盘设备&#xff0c;提供块级别的存储 NAS&#xff08;网络附加存储…

通俗易懂实现功能强大的实战项目 springboot+java+vue+mysql 日常办公用品直售推荐系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

投资自己,成就未来——社科院杜兰大学金融管理硕士项目

或许你一直在寻找一个能够提升自己、实现职业突破的机会。如果你对金融领域充满热情&#xff0c;并且渴望在这个竞争激烈的行业中脱颖而出&#xff0c;那么我要向你介绍一个绝佳的选择——中国社会科学院与美国杜兰大学金融管理硕士项目。 在这个高速发展的时代&#xff0c;投…

C语言调试大作战:与VS编译器共舞,上演一场“捉虫记”的艺术与科学

少年们好&#xff0c;我是博主那一脸阳光&#xff0c;我们接下来介绍C语言的调试和bug的分享。 引言&#xff1a; “如果你曾经在深夜与一串神秘莫测的C代码狭路相逢&#xff0c;彼此瞪大眼睛&#xff0c;犹如牛仔对决般紧张刺激&#xff1b;或者你曾试图驯服一段狂野不羁的循环…

C++入门案例——通讯录管理系统 控制台项目

前言 C入门案例——通讯录管理系统 & 控制台项目 目录 前言总体概览实体类设计显示页面和退出系统 添加联系人逻辑拆解相关代码 显示联系人逻辑拆解相关代码 根据名字删除联系人逻辑拆解相关代码 根据名字查找联系人逻辑拆解相关代码 修改联系人逻辑拆解相关代码 清空所有…

如何公网远程访问Axure RP制作的本地web页面【内网穿透】

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

Angular系列教程之组件

文章目录 前言组件的基本概念组件与指令的关系在模板中使用组件总结 前言 在Angular中&#xff0c;组件是构建Web应用程序的核心单元。它们允许我们将UI划分为独立且可重用的部分&#xff0c;并通过数据绑定和事件处理等机制来实现交互性。本文将介绍Angular组件的基本概念&am…

2024大数据“打假”:什么才是真湖仓一体?

编者按&#xff1a;近年来&#xff0c;随着金融、制造、政务、交通、医疗等行业数字化转型深入&#xff0c;大量智慧应用涌现&#xff0c;使得构建强大的数据分析技术栈成为必须&#xff0c;也让“湖仓一体”成为热门词汇。但面对市场中各色各样的湖仓技术&#xff0c;众多行业…

【漏洞复现】Kubernetes PPROF内存泄漏漏洞(CVE-2019-11248)

Nx01 产品简介 Kubernetes&#xff08;简称K8S&#xff09;是Google在2014年开源的一个容器集群管理系统。它用于容器化应用程序的部署、扩展和管理&#xff0c;目标是让部署容器化应用简单且高效。 Nx02 漏洞描述 漏洞存在于Kubernetes的1.18.6版本之前&#xff0c;可能导致未…

某侠网js逆向wasm解析

本次目标地址如下&#xff0c;使用base64解密获得 aHR0cHM6Ly93d3cud2FpbWFveGlhLm5ldC9sb2dpbg 打开网址&#xff0c;本次的目标是登录接口&#xff0c;如下图 本文主要讲解wasm的解析&#xff0c;所以对其他参数不做逆向处理&#xff0c;本次由wasm加密的参数只有sign一个&a…

07 整合SSM的快速理解

1.1 第一问&#xff1a;SSM整合需要几个IoC容器&#xff1f; 两个容器 本质上说&#xff0c;整合就是将三层架构和框架核心API组件交给SpringIoC容器管理&#xff01; 一个容器可能就够了&#xff0c;但是我们常见的操作是创建两个IoC容器&#xff08;web容器和root容器&…

记一次小黄站渗透过程,实操!

前言 记录某一次无意点开的一个小网站的渗透过程&#xff0c;幸运的是搭建平台是phpstudy&#xff0c;cms是beecms&#xff0c;beecms有通用漏洞&#xff0c;然后去网上找了资料&#xff0c;成功getshell并获取服务器权限。 渗透过程 无意点开一个网站&#xff0c;发现网站比…

【操作系统】在阅读论文:OrcFS: Orchestrated file system for flash storage时需要补充的基础知

在阅读论文&#xff1a;OrcFS: Orchestrated file system for flash storage是需要补充的基础知识 这篇论文是为了解决软件层次之间的信息冗余问题 To minimize the disk traffic, the file system buffers the updates and then flushes them to the disk as a single unit, …

datawhale 大模型理论基础 引言

学习地址&#xff1a;大模型理论基础 一、什么是语言模型&#xff08;Language Model) 语言模型其实是一个概率模型&#xff0c;给每一个句子列表计算一个概率值&#xff1a; p(x1​,…,xL​) 例如&#xff1a; p(the, mouse, ate, the, cheese)0.02…

解决若依Vue3前后端分离---路由切换时显示白屏

解决若依Vue3前后端分离---路由切换时显示白屏 1.问题重述 解决基于Vue3若依前后端分离项目中出现的路由正常切换但是就是不显示数据的问题&#xff0c;也就是不发起网络请求的问题。 找到如下位置中AppMain.vue文件 将除了css中的代码进行替换成如下的代码。 <template&g…

Python数据分析案例34——IMDB电影评论情感分析(Transformer)

电影评论的情感分析 案例背景 很多同学对电影系列的数据都比较喜欢&#xff0c;那我就补充一下这个最经典的文本分类数据集&#xff0c;电影情感评论分析。用神经网络做。对国外的英文评论文本进行分类&#xff0c;看是正面还是负面情感。 数据集介绍 数据集&#xff1a;IMDb…