首页 > 其他 > 详细

自定义对话框及其调用

时间:2020-02-21 19:21:06      阅读:78      评论:0      收藏:0      [点我收藏+]

最近在阅读Qt 5.9 C++开发指南,为了加深对书本上内容的理解,参照书上的讲解尝试写了一些demo,用于以后工作中查阅,如果涉及侵权请告知实例程序samp6_2

mymainwindow.h

#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H

#include "mydialog.h"
#include <QMainWindow>
#include <QWidget>
#include <QAction>
#include <QStandardItemModel>
#include <QTableView>
#include <QItemSelectionModel>
//#include <QStandardItem> // 如果我不包含这个头文件,但是下面用了这个类,为什么不报错???
#include <QLabel>

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QAction *_actSetRowColumn;
    QAction *_actSetHeader;
    QAction *_actLocateTable;
    QAction *_actExit;
    QTableView *_tableView;
    QLabel *_labStatus;
    QStandardItemModel *_standardItemModel;
    QItemSelectionModel *_itemSelectionModel;
    DialogHeader *_dialogHeader;
    DialogLocate *_dialogLocate;

public:
    MyMainWindow(QWidget *parent = nullptr);
    ~MyMainWindow();

    void iniUI();
    void iniSignalSlots();

public slots:
    void actSetRowColumnTriggered();
    void actSetHeaderTriggered();
    void actLocateTableTriggered();
    void tableViewClicked(const QModelIndex &index);
    void setAlignment(QStandardItem *item); // 必须要是槽函数,才能响应信号与槽,用于使整个表格居中

    void setCellText(int row, int column, const QString &text);
    void setActLoacteTableEnabled(bool enable);
    void setDialogLocateNull();

signals:
    void rowColumnChanged(const QModelIndex &index);
};

#endif // MYMAINWINDOW_H

mymainwindow.cpp

#include "mymainwindow.h"
#include <QIcon>
#include <QToolBar>
#include <QStatusBar>
#include <QModelIndex>

MyMainWindow::MyMainWindow(QWidget *parent) : QMainWindow(parent)
{
    iniUI();

    _standardItemModel = new QStandardItemModel(this);
    _tableView->setModel(_standardItemModel); // 设置tableview的model
    _itemSelectionModel = new QItemSelectionModel(_standardItemModel);
    _tableView->setSelectionModel(_itemSelectionModel); // 设置tableview的selectmodel

    iniSignalSlots(); // 先创建对象才能连接信号与槽,否则crash

    _dialogHeader = nullptr;
    _dialogLocate = nullptr;
}

MyMainWindow::~MyMainWindow()
{

}

// 初始化界面
void MyMainWindow::iniUI()
{
    // 创建4个action
    _actSetRowColumn = new QAction(QIcon(":/images/rowcolumn.bmp"), "设置行数列数");
    _actSetHeader = new QAction(QIcon(":/images/header.bmp"), "设置表头标题");
    _actLocateTable = new QAction(QIcon(":/images/locate.bmp"), "定位单元格");
    _actExit = new QAction(QIcon(":/images/exit.bmp"), "退出");

    // 创建1个toolbar,并把4个action放进来,设置toolbar按钮风格为图上字下,最后设置为主窗口的工具栏
    QToolBar *toolBar = new QToolBar();
    toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    toolBar->addAction(_actSetRowColumn);
    toolBar->addAction(_actSetHeader);
    toolBar->addAction(_actLocateTable);
    toolBar->addAction(_actExit);
    addToolBar(toolBar);

    // 创建一个tableview,把这个tableview设置为主窗口的centralwidget
    _tableView = new QTableView();
    setCentralWidget(_tableView);

    // 创建一个状态栏,设置为主窗口的状态栏
    _labStatus = new QLabel();
    QStatusBar *statusBar = new QStatusBar();
    statusBar->addWidget(_labStatus);
    setStatusBar(statusBar);

    // 设置窗口初始大小
    resize(1100, 600);
}


// 连接信号与槽
void MyMainWindow::iniSignalSlots()
{
    // 连接4个action与对应的槽函数,连接tableview与刷新新窗口的值
    connect(_actSetRowColumn, SIGNAL(triggered()), this, SLOT(actSetRowColumnTriggered()));
    connect(_actSetHeader, SIGNAL(triggered()), this, SLOT(actSetHeaderTriggered()));
    connect(_actLocateTable, SIGNAL(triggered()), this, SLOT(actLocateTableTriggered()));
    connect(_actExit, SIGNAL(triggered()), this, SLOT(close())); // 直接调用主窗口的槽函数就行
    connect(_tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(tableViewClicked(QModelIndex)));
    connect(_standardItemModel, SIGNAL(itemChanged(QStandardItem *)), this, SLOT(setAlignment(QStandardItem *))); // 将表格所有文本居中

}

// _actSetRowColumn这个action的槽函数,打开窗口,通过窗口设置主界面model的大小
void MyMainWindow::actSetRowColumnTriggered()
{
    DialogSize *dialogSize = new DialogSize(this);
    Qt::WindowFlags flags = dialogSize->windowFlags();
    dialogSize->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); // 设置为固定大小的对话框,说白了就是不能拖拉放大缩小
    dialogSize->setRow(_standardItemModel->rowCount()); // 设置这个新对话框的初始行和列
    dialogSize->setColumn(_standardItemModel->columnCount());

    int result = dialogSize->exec(); // 以模态的形式执行,模态就是当这个窗口没关之前,不能操作主窗口
    if(result == QDialog::Accepted)  // 如果点击的是OK,那么获取子窗口的行列,设置主窗口的model
    {
        int row = dialogSize->row();
        _standardItemModel->setRowCount(row);
        int column = dialogSize->column();
        _standardItemModel->setColumnCount(column);
    }

    delete dialogSize; // 这种对话框创建比较简单,不需要和主窗口传递大量数据做初始化,所以调用完就可以删除节约内存
}

// _actSetHeader这个action的槽函数,打开窗口,设置model头
void MyMainWindow::actSetHeaderTriggered()
{
    if(_dialogHeader == nullptr) // 如果为null,说明没有创建,这种窗口与主窗口需要传输一些数据,所以每次调用完不删,提高对话框调用速度
    {
        _dialogHeader = new DialogHeader(this);
    }

    QStringList headerList;
    for(int i = 0; i < _standardItemModel->columnCount(); i++)
    {
        QString header = _standardItemModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
        headerList.append(header);
    }
    _dialogHeader->setHeaderList(headerList); // 设置子窗口初始值

    int result = _dialogHeader->exec(); // 以模态运行
    if(result == QDialog::Accepted) // 设置model头
    {
        headerList.clear();
        headerList = _dialogHeader->headerList();
        _standardItemModel->setHorizontalHeaderLabels(headerList);
    }
}

// _actLocateTable这个action的槽函数,打开子窗口,用于单元格定位和交互
void MyMainWindow::actLocateTableTriggered()
{
    _actLocateTable->setEnabled(false); // 当子窗口打开时,这个action就不能点了,不然不科学

    _dialogLocate = new DialogLocate(this);
    _dialogLocate->setAttribute(Qt::WA_DeleteOnClose); // 设置为关闭时删除对话框,这种设置与自己手动删除有什么区别???
    Qt::WindowFlags flags = _dialogLocate->windowFlags();
    _dialogLocate->setWindowFlags(flags | Qt::WindowStaysOnTopHint); // 设置子窗口在最上面
    _dialogLocate->setSpinRange(_standardItemModel->rowCount(), _standardItemModel->columnCount());

    QModelIndex index = _itemSelectionModel->currentIndex();
    if(index.isValid()) // 设置子窗口初值
    {
        _dialogLocate->setSpinValue(index.row(), index.column());
    }

    connect(_dialogLocate, SIGNAL(changeLocateActionEnabled(bool)), this, SLOT(setActLoacteTableEnabled(bool)));
    connect(_dialogLocate, SIGNAL(changeCellText(int, int, const QString &)), this, SLOT(setCellText(int, int, const QString &)));
    connect(this, SIGNAL(rowColumnChanged(const QModelIndex &)), _dialogLocate, SLOT(rowColumChanged(const QModelIndex &)));

    _dialogLocate->show(); // 以普通方式打开子窗口,打开子窗口后还可以操作主窗口
}

// 这是设置主窗口表格数据的函数,通过子窗口获取父窗口对象,然后父窗口对象调用该函数,先试试这种方式,到时候改为信号与槽实现
void MyMainWindow::setCellText(int row, int column, const QString &text)
{
    QModelIndex index = _standardItemModel->index(row, column);
    _standardItemModel->setData(index, text);
    _itemSelectionModel->clearSelection();
    _itemSelectionModel->setCurrentIndex(index, QItemSelectionModel::Select);
}

// 用来主窗口和子窗口交互,主要用tableview的点击事件
void MyMainWindow::tableViewClicked(const QModelIndex &index)
{
//    if(_dialogLocate != nullptr)
//    {
//        _dialogLocate->setSpinValue(index.row(), index.column());
//    }

//    // 通过信号与槽机制来实现多窗口之间的交互
    if(index.isValid() && _dialogLocate != nullptr)
    {
        emit rowColumnChanged(index);
    }
}

// 同setCellText函数,当关闭子窗口时,要在子窗口设置主窗口的控件的状态
void MyMainWindow::setActLoacteTableEnabled(bool enable)
{
    _actLocateTable->setEnabled(enable);
}

// 当关闭子窗口时,要将子窗口对象设置为空,不然要crash,这也是一个问题,为什么要crash???
// 因为tableViewClicked函数中会调用_dialogLocate对象的函数,但是这个对象关闭子窗口的时候delete了
// 虽然delete了,但是没有置空,可能是个野指针之内的,我调试后发现无法获取那个对象的地址,但是用信号
// 与槽就不会有这个问题,因为delete时,信号与槽等于disc了
void MyMainWindow::setDialogLocateNull()
{
    _dialogLocate = nullptr;
}

// 这个函数是想设置tableview中所有文本居中
void MyMainWindow::setAlignment(QStandardItem *item)
{
    if(item)
    {
        item->setTextAlignment(Qt::AlignCenter);
    }
}

mydialog.h

#ifndef MYDIALOG_H
#define MYDIALOG_H

#include <QDialog>
#include <QSpinBox>
#include <QWidget>
#include <QStringListModel>
#include <QListView>
#include <QPushButton>
#include <QLineEdit>

class DialogSize : public QDialog
{
    Q_OBJECT

private:
    QSpinBox *_sbRow;
    QSpinBox *_sbColumn;
    QPushButton *_btnOK;
    QPushButton *_btnCancel;

public:
    DialogSize(QWidget *parent = nullptr);
    ~DialogSize();
    void iniUI();
    void iniSignalSlots();
    int row();
    int column();
    void setRow(int row);
    void setColumn(int column);

};

class DialogHeader : public QDialog
{
    Q_OBJECT

private:
    QPushButton *_btnOK;
    QPushButton *_btnCancel;
    QStringListModel *_stringListModel;
    QListView *_listView;

public:
    DialogHeader(QWidget *parent = nullptr);
    ~DialogHeader();
    void iniUI();
    void iniSignalSlots();
    void setHeaderList(QStringList &stringList);
    QStringList headerList();
};

class DialogLocate : public QDialog
{
    Q_OBJECT

private:
    QSpinBox *_sbRow;
    QSpinBox *_sbColumn;
    QLineEdit *_text;
    QPushButton *_btnOK;
    QPushButton *_btnClose;

public:
    DialogLocate(QWidget *parent);
    ~DialogLocate();

    void iniUI();
    void iniSignalSlots();
    void setSpinRange(int maxRow, int maxColumn);
    void setSpinValue(int row, int column);
    void closeEvent(QCloseEvent *e);

public slots:
    void btnOKClicked();
    void rowColumChanged(const QModelIndex &index);

signals:
    void changeLocateActionEnabled(bool enabled); // 这两个信号用来与主窗口交互
    void changeCellText(int row, int column, const QString &text);

};

#endif // MYDIALOG_H

mydialog.cpp

#include "mydialog.h"
#include "mymainwindow.h"
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QIcon>

DialogSize::DialogSize(QWidget *parent) : QDialog(parent)
{
    iniUI();
    iniSignalSlots();
}

DialogSize::~DialogSize()
{

}


// 初始化界面
void DialogSize::iniUI()
{
    _sbRow = new QSpinBox();
    _sbRow->setMinimum(0);
    _sbRow->setMaximum(20);
    _sbRow->setValue(10); // 设置这个控件的初值,其实没必要
    _sbColumn = new QSpinBox();
    _sbColumn->setMinimum(0);
    _sbColumn->setMaximum(20);
    _sbColumn->setValue(10);
    _btnOK = new QPushButton("确定");
    _btnCancel = new QPushButton("取消");

    QLabel *lab1 = new QLabel("行数");
    QLabel *lab2 = new QLabel("列数");
    QHBoxLayout *layout1 = new QHBoxLayout(); // 这种布局风格不行,万一工作中遇到添加一个控件什么的,不好修改,暂时没有好的想法如何改???
    layout1->addWidget(lab1);
    layout1->addWidget(_sbRow);
    QHBoxLayout *layout2 = new QHBoxLayout();
    layout2->addWidget(lab2);
    layout2->addWidget(_sbColumn);
    QVBoxLayout *layout3 = new QVBoxLayout();
    layout3->addLayout(layout1);
    layout3->addLayout(layout2);

    QGroupBox *box = new QGroupBox("设置表格行数和列数"); // 这个控件的作用就是显示标题,其他作用没体现出来
    box->setLayout(layout3);

    QVBoxLayout *layout4 = new QVBoxLayout();
    layout4->addWidget(_btnOK);
    layout4->addWidget(_btnCancel);

    QHBoxLayout *layout5 = new QHBoxLayout();
    layout5->addWidget(box);
    layout5->addLayout(layout4);

    setLayout(layout5);
    setWindowTitle("设置表格行数和列数");
    resize(200,100);
}

void DialogSize::iniSignalSlots()
{
    connect(_btnOK, SIGNAL(clicked()), this, SLOT(accept()));
    connect(_btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
}

int DialogSize::row()
{
    return _sbRow->value();
}

int DialogSize::column()
{
    return _sbColumn->value();
}

void DialogSize::setRow(int row)
{
    _sbRow->setValue(row);
}

void DialogSize::setColumn(int column)
{
    _sbColumn->setValue(column);
}

DialogHeader::DialogHeader(QWidget *parent) : QDialog (parent)
{
    iniUI();
    iniSignalSlots();

    _stringListModel = new QStringListModel(this); // 这个子窗口主要显示主窗口的表格头,所以用stringlistmodel就好
    _listView->setModel(_stringListModel);
}

DialogHeader::~DialogHeader()
{

}

void DialogHeader::iniUI()
{
    _btnOK = new QPushButton(QIcon(":/images/ok.bmp"),"确定"); // 给按钮设置图案,好像只能设置为图片在左字在右
    _btnCancel = new QPushButton(QIcon(":/images/cancel.bmp"),"取消");

    _listView = new QListView();
    QHBoxLayout *layout1 = new QHBoxLayout();
    layout1->addWidget(_listView);
    QGroupBox *box = new QGroupBox("表头标题");
    box->setLayout(layout1);

    QVBoxLayout *layout2 = new QVBoxLayout();
    layout2->addWidget(_btnOK);
    layout2->addWidget(_btnCancel);

    QHBoxLayout *layout3 = new QHBoxLayout();
    layout3->addWidget(box);
    layout3->addLayout(layout2);

    setLayout(layout3);
    setWindowTitle("设置表头标题");
    resize(200,100);
}

void DialogHeader::iniSignalSlots()
{
    connect(_btnOK, SIGNAL(clicked()), this, SLOT(accept()));
    connect(_btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
}

QStringList DialogHeader::headerList()
{
    return _stringListModel->stringList();
}

void DialogHeader::setHeaderList(QStringList &stringList)
{
    _stringListModel->setStringList(stringList);
}

DialogLocate::DialogLocate(QWidget *parent) : QDialog (parent)
{
    iniUI();
    iniSignalSlots();
}

DialogLocate::~DialogLocate()
{

}

void DialogLocate::iniUI()
{
    _sbRow = new QSpinBox();
    _sbColumn = new QSpinBox();
    _btnOK = new QPushButton("设定文字");
    _btnClose = new QPushButton("关闭");
    _text = new QLineEdit();

    QLabel *lab1 = new QLabel("行号");
    QLabel *lab2 = new QLabel("列号");
    QLabel *lab3 = new QLabel("设定文字");

    QHBoxLayout *layout1 = new QHBoxLayout();
    layout1->addWidget(lab1);
    layout1->addWidget(_sbRow);

    QHBoxLayout *layout2 = new QHBoxLayout();
    layout2->addWidget(lab2);
    layout2->addWidget(_sbColumn);

    QHBoxLayout *layout3 = new QHBoxLayout();
    layout3->addWidget(lab3);
    layout3->addWidget(_text);

    QVBoxLayout *layout4 = new QVBoxLayout();
    layout4->addLayout(layout1);
    layout4->addLayout(layout2);
    layout4->addLayout(layout3);

    QGroupBox *box = new QGroupBox();
    box->setLayout(layout4);

    QVBoxLayout *layout5= new QVBoxLayout();
    layout5->addWidget(_btnOK);
    layout5->addWidget(_btnClose);

    QHBoxLayout *layout6 = new QHBoxLayout();
    layout6->addWidget(box);
    layout6->addLayout(layout5);

    setLayout(layout6);
    resize(300,150);
}

void DialogLocate::iniSignalSlots()
{
    connect(_btnOK, SIGNAL(clicked()), this, SLOT(btnOKClicked()));
    connect(_btnClose, SIGNAL(clicked()), this, SLOT(close()));
}

void DialogLocate::btnOKClicked()
{
    int row = _sbRow->value();
    int column = _sbColumn->value();
    QString text = _text->text();
//    MyMainWindow *mainWindow = static_cast<MyMainWindow *>(parentWidget()); // 通过函数的形式,进行主窗口与子窗口的交互
//    mainWindow->setCellText(row, column, text);
    emit changeCellText(row, column, text);
}

void DialogLocate::setSpinRange(int maxRow, int maxColumn)
{
    _sbRow->setRange(0, maxRow);
    _sbColumn->setRange(0, maxColumn);
}

void DialogLocate::setSpinValue(int row, int column)
{
    _sbRow->setValue(row);
    _sbColumn->setValue(column);
}

void DialogLocate::rowColumChanged(const QModelIndex &index)
{
    if(index.isValid())
    {
        _sbRow->setValue(index.row());
        _sbColumn->setValue(index.column());
    }
}

void DialogLocate::closeEvent(QCloseEvent *e)
{
//    MyMainWindow *mainWindow = static_cast<MyMainWindow *>(parentWidget()); // 同btnOKClicked函数
//    mainWindow->setActLoacteTableEnabled(true);
//    mainWindow->setDialogLocateNull();

    emit changeLocateActionEnabled(true);
}

main.cpp

#include "mymainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyMainWindow w;
    w.show();

    return a.exec();
}

效果展示

技术分享图片

技术分享图片

技术分享图片

技术分享图片

自定义对话框及其调用

原文:https://www.cnblogs.com/samp000/p/12342466.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!