Qt创建自定义对话框

一、模态显示自定义对话框(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 &current, 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 &current,const QModelIndex &previous);
    void on_act_setRC_triggered();

    void on_act_setHeader_triggered();

    void on_act_locateTheCell_triggered();

    void updata_tdialoglcoate_value(const QModelIndex &current,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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值