最近在阅读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