Qt6教程之二(4) item views

编程入门 行业动态 更新时间:2024-10-15 12:38:15

Qt6教程<a href=https://www.elefans.com/category/jswz/34/1767314.html style=之二(4) item views"/>

Qt6教程之二(4) item views

item views包括list view、tree view、table view、column view、undo view,主要用于显示数据,同时也是MVD(Model-View-Delegate,就是模型/视图/代理的意思)的view层主要显示控件。

使用model/View结构来管理数据与视图的关系,model负责数据的存取,数据的交互通过delegate来实现。这里不打算讲解MVD的原理,仅仅站在实用的角度对下列控件进行逐个演示。

list view称为列表视图,可以用来以列表的形式展示数据;

tree view称为树型视图,可以用来展示树状结构数据;

table view成为表格视图,主要用来以行列的方式展示数据;

column view成为列表控件,主要用于以列为单位展示数据的列表控件;

undo view称为撤销命令视图,用于在应用程序中实现撤消/重做功能,将撤销栈的内容显示并输出到列表控件的控件。

在前面几个章节,我们在演示代码时均通过UI布局和纯代码实现两种方式来演示控件的使用,在此将不再使用UI拖拽布局的方式,因为只有使用纯代码才能实现item views的使用!

接下来开始敲代码:

1、list view

 工程结构如下,创建的工程文件名字叫test_item_views,  窗口继承QWidget,   代码主要是在widget.cpp中写,

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<QModelIndex>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:
//定义一个槽函数,用于实现鼠标点击listview项时实现逻辑void printMSG(QModelIndex index);};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "qapplication.h"
#include<QListView>
#include<QStandardItemModel>
#include<QMessageBox>
#include<QModelIndex>
#include<QStyle>Widget::Widget(QWidget *parent): QWidget(parent)
{//设置窗口的位置和大小setGeometry(100,100,600,400);//创建qlistview对象QListView *listview=new QListView(this);//创建item的model对象,用于装载listview需要的数据QStandardItemModel *itemModel=new QStandardItemModel(this);//创建QStandardItem对象,用于管理单项数据QStandardItem *item=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(1)),"beijing");QStandardItem *item2=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(3)),"tianjing");QStandardItem *item3=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(5)),"guiyang");QStandardItem *item4=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(9)),"shenzhen");QStandardItem *item5=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(11)),"hainan");//把item装入model中itemModel->appendRow(item);itemModel->appendRow(item2);itemModel->appendRow(item3);itemModel->appendRow(item4);itemModel->appendRow(item5);//设置listview的modellistview->setModel(itemModel);//连接信号与槽,实现点击单项后的逻辑   connect(listview,SIGNAL(clicked(QModelIndex)),this,SLOT(printMSG(QModelIndex)));}Widget::~Widget()
{
}//槽函数定义:  当点击listview的单项时,把项的内容弹出来
void Widget::printMSG(QModelIndex index)
{QMessageBox msg;msg.setText ((index.data()).toString());msg.exec();
}

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

程序运行效果:

2、tree view

 工程结构如下,创建的工程文件名字叫test_item_views,  窗口继承QWidget,   代码主要是在widget.cpp中写,

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<QModelIndex>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:
//定义一个槽函数,用于实现鼠标点击listview项时实现逻辑void printMSG(QModelIndex index);};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include<QListView>
#include<QStandardItemModel>
#include<QMessageBox>
#include<QModelIndex>
#include<QStyle>
#include <QTreeView>
#include<QFileSystemModel>Widget::Widget(QWidget *parent): QWidget(parent)
{//设置窗口的位置和大小setGeometry(100,100,width(),height());//创建treeview对象QTreeView *treeview=new QTreeView(this);treeview->setGeometry(100,100,600,600);treeview->setAnimated(true);//创建model对象,用于管理单项数据QFileSystemModel *fileModel=new QFileSystemModel;//set root pathfileModel->setRootPath(QDir::currentPath());//设置listview的modeltreeview->setModel(fileModel);//连接信号与槽,实现点击单项后的逻辑connect(treeview,SIGNAL(clicked(QModelIndex)),this,SLOT(printMSG(QModelIndex)));}Widget::~Widget()
{
}//槽函数定义:  当点击listview的单项时,把项的内容弹出来
void Widget::printMSG(QModelIndex index)
{QMessageBox msg;msg.setText ((index.data()).toString());msg.exec();
}

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

程序运行效果:

3、table view

 工程结构如下,创建的工程文件名字叫test_item_views,  窗口继承QWidget,   代码主要是在widget.cpp中写,

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<QModelIndex>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void printMSG(QModelIndex index);};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "qapplication.h"
#include<QListView>
#include<QStandardItemModel>
#include<QMessageBox>
#include<QModelIndex>
#include<QStyle>
#include <QTableView>Widget::Widget(QWidget *parent): QWidget(parent)
{//设置窗口的位置和大小setGeometry(100,100,600,400);//创建qlistview对象QTableView *tableview=new QTableView(this);tableview->setGeometry(100,100,600,600);//创建item的model对象,用于装载listview需要的数据QStandardItemModel *itemModel=new QStandardItemModel(this);//创建QStandardItem对象,用于管理单项数据QStandardItem *SF=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(0)),"shenfen");QStandardItem *item=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(1)),"beijing");QStandardItem *item2=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(3)),"tianjing");QStandardItem *item3=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(5)),"guiyang");QStandardItem *item4=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(9)),"shenzhen");QStandardItem *item5=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(11)),"hainan");QStandardItem *m=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(0)),"money");QStandardItem *item6=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(1)),"100w");QStandardItem *item7=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(3)),"200w");QStandardItem *item8=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(5)),"60w");QStandardItem *item9=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(9)),"300w");QStandardItem *item10=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(11)),"90w");//把item装入model中itemModel->setItem(0,0,SF);itemModel->setItem(0,1,item);itemModel->setItem(0,2,item2);itemModel->setItem(0,3,item3);itemModel->setItem(0,4,item4);itemModel->setItem(0,5,item5);itemModel->setItem(1,0,m);itemModel->setItem(1,1,item6);itemModel->setItem(1,2,item7);itemModel->setItem(1,3,item8);itemModel->setItem(1,4,item9);itemModel->setItem(1,5,item10);//设置listview的modeltableview->setModel(itemModel);//连接信号与槽,实现点击单项后的逻辑connect(tableview,SIGNAL(clicked(QModelIndex)),this,SLOT(printMSG(QModelIndex)));}Widget::~Widget()
{
}//槽函数定义:  当点击listview的单项时,把项的内容弹出来
void Widget::printMSG(QModelIndex index)
{QMessageBox msg;msg.setText ((index.data()).toString());msg.exec();
}

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

程序运行效果:

4、column view

 工程结构如下,创建的工程文件名字叫test_item_views,  窗口继承QWidget,   代码主要是在widget.cpp中写,

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<QModelIndex>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void printMSG(QModelIndex index);};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "qapplication.h"
#include<QListView>
#include<QStandardItemModel>
#include<QMessageBox>
#include<QModelIndex>
#include<QStyle>
#include <QTableView>
#include<QColumnView>Widget::Widget(QWidget *parent): QWidget(parent)
{//设置窗口的位置和大小setGeometry(100,100,600,400);//创建qlistview对象QColumnView *columnView=new QColumnView(this);columnView->setGeometry(100,100,600,600);//创建item的model对象,用于装载listview需要的数据QStandardItemModel *itemModel=new QStandardItemModel(this);//创建QStandardItem对象,用于管理单项数据QStandardItem *SF=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(0)),"shenfen");QStandardItem *item=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(1)),"beijing");QStandardItem *item2=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(3)),"tianjing");QStandardItem *item3=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(5)),"guiyang");QStandardItem *item4=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(9)),"shenzhen");QStandardItem *item5=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(11)),"hainan");QStandardItem *m=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(0)),"money");QStandardItem *item6=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(1)),"100w");QStandardItem *item7=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(3)),"200w");QStandardItem *item8=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(5)),"60w");QStandardItem *item9=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(9)),"300w");QStandardItem *item10=new QStandardItem(QApplication::style()->standardIcon(QStyle::StandardPixmap(11)),"90w");//把item装入model中itemModel->appendRow(SF);itemModel->appendRow(item);itemModel->appendRow(item2);itemModel->appendRow(item3);itemModel->appendRow(item4);itemModel->appendRow(item5);itemModel->appendRow(m);itemModel->appendRow(item6);itemModel->appendRow(item7);itemModel->appendRow(item8);itemModel->appendRow(item9);itemModel->appendRow(item10);//设置listview的modelcolumnView->setModel(itemModel);//连接信号与槽,实现点击单项后的逻辑connect(columnView,SIGNAL(clicked(QModelIndex)),this,SLOT(printMSG(QModelIndex)));}Widget::~Widget()
{
}//槽函数定义:  当点击listview的单项时,把项的内容弹出来
void Widget::printMSG(QModelIndex index)
{QMessageBox msg;msg.setText ((index.data()).toString());msg.exec();
}

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

运行效果:

5、undo view

 undo view这个控件涉及到的知识点非常多,主要参照Qt官方示例,工程结构如下,

开始贴代码,也可以直接在Qt的官方示例中寻找,

头文件:

commands.h


#ifndef COMMANDS_H
#define COMMANDS_H#include <QUndoCommand>
#include "document.h"class AddShapeCommand : public QUndoCommand
{
public:AddShapeCommand(Document *doc, const Shape &shape,QUndoCommand *parent = nullptr);void undo() override;void redo() override;private:Document *m_doc;Shape m_shape;QString m_shapeName;
};class RemoveShapeCommand : public QUndoCommand
{
public:RemoveShapeCommand(Document *doc, const QString &shapeName,QUndoCommand *parent = nullptr);void undo() override;void redo() override;private:Document *m_doc;Shape m_shape;QString m_shapeName;
};class SetShapeColorCommand : public QUndoCommand
{
public:SetShapeColorCommand(Document *doc, const QString &shapeName,const QColor &color, QUndoCommand *parent = nullptr);void undo() override;void redo() override;bool mergeWith(const QUndoCommand *command) override;int id() const override;private:Document *m_doc;QString m_shapeName;QColor m_oldColor;QColor m_newColor;
};class SetShapeRectCommand : public QUndoCommand
{
public:SetShapeRectCommand(Document *doc, const QString &shapeName,const QRect &rect, QUndoCommand *parent = nullptr);void undo() override;void redo() override;bool mergeWith(const QUndoCommand *command) override;int id() const override;private:Document *m_doc;QString m_shapeName;QRect m_oldRect;QRect m_newRect;
};#endif // COMMANDS_H

document.h


#ifndef DOCUMENT_H
#define DOCUMENT_H#include <QWidget>QT_FORWARD_DECLARE_CLASS(QUndoStack)
QT_FORWARD_DECLARE_CLASS(QTextStream)class Shape
{
public:enum Type { Rectangle, Circle, Triangle };explicit Shape(Type type = Rectangle, const QColor &color = Qt::red, const QRect &rect = QRect());Type type() const;QString name() const;QRect rect() const;QRect resizeHandle() const;QColor color() const;static QString typeToString(Type type);static Type stringToType(const QString &s, bool *ok = nullptr);static const QSize minSize;private:Type m_type;QRect m_rect;QColor m_color;QString m_name;friend class Document;
};class Document : public QWidget
{Q_OBJECTpublic:Document(QWidget *parent = nullptr);QString addShape(const Shape &shape);void deleteShape(const QString &shapeName);Shape shape(const QString &shapeName) const;QString currentShapeName() const;void setShapeRect(const QString &shapeName, const QRect &rect);void setShapeColor(const QString &shapeName, const QColor &color);bool load(QTextStream &stream);void save(QTextStream &stream);QString fileName() const;void setFileName(const QString &fileName);QUndoStack *undoStack() const;signals:void currentShapeChanged(const QString &shapeName);protected:void paintEvent(QPaintEvent *event) override;void mousePressEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;private:void setCurrentShape(int index);int indexOf(const QString &shapeName) const;int indexAt(const QPoint &pos) const;QString uniqueName(const QString &name) const;QList<Shape> m_shapeList;QPoint m_mousePressOffset;QString m_fileName;QUndoStack *m_undoStack = nullptr;int m_currentIndex = -1;int m_mousePressIndex = -1;bool m_resizeHandlePressed = false;
};#endif // DOCUMENT_H

mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "ui_mainwindow.h"class Document;class MainWindow : public QMainWindow, public Ui::MainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);void addDocument(Document *doc);void removeDocument(Document *doc);void setCurrentDocument(Document *doc);Document *currentDocument() const;public slots:void openDocument();void saveDocument();void closeDocument();void newDocument();void addShape();void removeShape();void setShapeColor();void addSnowman();void addRobot();void about();void aboutQt();private slots:void updateActions();private:QUndoGroup *m_undoGroup;QString fixedWindowTitle(const Document *doc) const;
};#endif // MAINWINDOW_H

源文件:

commands.cpp


#include "commands.h"static constexpr int setShapeRectCommandId = 1;
static constexpr int setShapeColorCommandId = 2;/******************************************************************************
** AddShapeCommand
*/AddShapeCommand::AddShapeCommand(Document *doc, const Shape &shape, QUndoCommand *parent): QUndoCommand(parent), m_doc(doc), m_shape(shape)
{
}void AddShapeCommand::undo()
{m_doc->deleteShape(m_shapeName);
}void AddShapeCommand::redo()
{// A shape only gets a name when it is inserted into a documentm_shapeName = m_doc->addShape(m_shape);setText(QObject::tr("Add %1").arg(m_shapeName));
}/******************************************************************************
** RemoveShapeCommand
*/RemoveShapeCommand::RemoveShapeCommand(Document *doc, const QString &shapeName,QUndoCommand *parent): QUndoCommand(parent), m_doc(doc), m_shape(doc->shape(shapeName)), m_shapeName(shapeName)
{setText(QObject::tr("Remove %1").arg(shapeName));
}void RemoveShapeCommand::undo()
{m_shapeName = m_doc->addShape(m_shape);
}void RemoveShapeCommand::redo()
{m_doc->deleteShape(m_shapeName);
}/******************************************************************************
** SetShapeColorCommand
*/SetShapeColorCommand::SetShapeColorCommand(Document *doc, const QString &shapeName,const QColor &color, QUndoCommand *parent): QUndoCommand(parent), m_doc(doc), m_shapeName(shapeName), m_oldColor(doc->shape(shapeName).color()), m_newColor(color)
{setText(QObject::tr("Set %1's color").arg(shapeName));
}void SetShapeColorCommand::undo()
{m_doc->setShapeColor(m_shapeName, m_oldColor);
}void SetShapeColorCommand::redo()
{m_doc->setShapeColor(m_shapeName, m_newColor);
}bool SetShapeColorCommand::mergeWith(const QUndoCommand *command)
{if (command->id() != setShapeColorCommandId)return false;const SetShapeColorCommand *other = static_cast<const SetShapeColorCommand*>(command);if (m_shapeName != other->m_shapeName)return false;m_newColor = other->m_newColor;return true;
}int SetShapeColorCommand::id() const
{return setShapeColorCommandId;
}/******************************************************************************
** SetShapeRectCommand
*/SetShapeRectCommand::SetShapeRectCommand(Document *doc, const QString &shapeName,const QRect &rect, QUndoCommand *parent): QUndoCommand(parent), m_doc(doc), m_shapeName(shapeName), m_oldRect(doc->shape(shapeName).rect()), m_newRect(rect)
{setText(QObject::tr("Change %1's geometry").arg(shapeName));
}void SetShapeRectCommand::undo()
{m_doc->setShapeRect(m_shapeName, m_oldRect);
}void SetShapeRectCommand::redo()
{m_doc->setShapeRect(m_shapeName, m_newRect);
}bool SetShapeRectCommand::mergeWith(const QUndoCommand *command)
{if (command->id() != setShapeRectCommandId)return false;const SetShapeRectCommand *other = static_cast<const SetShapeRectCommand*>(command);if (m_shapeName != other->m_shapeName)return false;m_newRect = other->m_newRect;return true;
}int SetShapeRectCommand::id() const
{return setShapeRectCommandId;
}

mainwindow.cpp


#include "mainwindow.h"
#include "document.h"
#include "commands.h"#include <QUndoGroup>
#include <QUndoStack>
#include <QFileDialog>
#include <QMessageBox>
#include <QRandomGenerator>
#include <QTextStream>
#include <QToolButton>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{setupUi(this);QWidget *w = documentTabs->widget(0);documentTabs->removeTab(0);delete w;connect(actionOpen, &QAction::triggered, this, &MainWindow::openDocument);connect(actionClose, &QAction::triggered, this, &MainWindow::closeDocument);connect(actionNew, &QAction::triggered, this, &MainWindow::newDocument);connect(actionSave, &QAction::triggered, this, &MainWindow::saveDocument);connect(actionExit, &QAction::triggered, this, &QWidget::close);connect(actionRed, &QAction::triggered, this, &MainWindow::setShapeColor);connect(actionGreen, &QAction::triggered, this, &MainWindow::setShapeColor);connect(actionBlue, &QAction::triggered, this, &MainWindow::setShapeColor);connect(actionAddCircle, &QAction::triggered, this, &MainWindow::addShape);connect(actionAddRectangle, &QAction::triggered, this, &MainWindow::addShape);connect(actionAddTriangle, &QAction::triggered, this, &MainWindow::addShape);connect(actionRemoveShape, &QAction::triggered, this, &MainWindow::removeShape);connect(actionAddRobot, &QAction::triggered, this, &MainWindow::addRobot);connect(actionAddSnowman, &QAction::triggered, this, &MainWindow::addSnowman);connect(actionAbout, &QAction::triggered, this, &MainWindow::about);connect(actionAboutQt, &QAction::triggered, this, &MainWindow::aboutQt);connect(undoLimit, &QSpinBox::valueChanged, this, &MainWindow::updateActions);connect(documentTabs, &QTabWidget::currentChanged, this, &MainWindow::updateActions);actionOpen->setShortcut(QString("Ctrl+O"));actionClose->setShortcut(QString("Ctrl+W"));actionNew->setShortcut(QString("Ctrl+N"));actionSave->setShortcut(QString("Ctrl+S"));actionExit->setShortcut(QString("Ctrl+Q"));actionRemoveShape->setShortcut(QString("Del"));actionRed->setShortcut(QString("Alt+R"));actionGreen->setShortcut(QString("Alt+G"));actionBlue->setShortcut(QString("Alt+B"));actionAddCircle->setShortcut(QString("Alt+C"));actionAddRectangle->setShortcut(QString("Alt+L"));actionAddTriangle->setShortcut(QString("Alt+T"));m_undoGroup = new QUndoGroup(this);undoView->setGroup(m_undoGroup);undoView->setCleanIcon(QIcon(":/icons/ok.png"));QAction *undoAction = m_undoGroup->createUndoAction(this);QAction *redoAction = m_undoGroup->createRedoAction(this);undoAction->setIcon(QIcon(":/icons/undo.png"));redoAction->setIcon(QIcon(":/icons/redo.png"));menuShape->insertAction(menuShape->actions().at(0), undoAction);menuShape->insertAction(undoAction, redoAction);toolBar->addAction(undoAction);toolBar->addAction(redoAction);newDocument();updateActions();
};void MainWindow::updateActions()
{Document *doc = currentDocument();m_undoGroup->setActiveStack(doc == nullptr ? nullptr : doc->undoStack());QString shapeName = doc == nullptr ? QString() : doc->currentShapeName();actionAddRobot->setEnabled(doc != nullptr);actionAddSnowman->setEnabled(doc != nullptr);actionAddCircle->setEnabled(doc != nullptr);actionAddRectangle->setEnabled(doc != nullptr);actionAddTriangle->setEnabled(doc != nullptr);actionClose->setEnabled(doc != nullptr);actionSave->setEnabled(doc != nullptr && !doc->undoStack()->isClean());undoLimit->setEnabled(doc != nullptr && doc->undoStack()->count() == 0);if (shapeName.isEmpty()) {actionRed->setEnabled(false);actionGreen->setEnabled(false);actionBlue->setEnabled(false);actionRemoveShape->setEnabled(false);} else {Shape shape = doc->shape(shapeName);actionRed->setEnabled(shape.color() != Qt::red);actionGreen->setEnabled(shape.color() != Qt::green);actionBlue->setEnabled(shape.color() != Qt::blue);actionRemoveShape->setEnabled(true);}if (doc != nullptr) {int index = documentTabs->indexOf(doc);Q_ASSERT(index != -1);static const QIcon unsavedIcon(":/icons/filesave.png");documentTabs->setTabIcon(index, doc->undoStack()->isClean() ? QIcon() : unsavedIcon);if (doc->undoStack()->count() == 0)doc->undoStack()->setUndoLimit(undoLimit->value());}
}void MainWindow::openDocument()
{QString fileName = QFileDialog::getOpenFileName(this);if (fileName.isEmpty())return;QFile file(fileName);if (!file.open(QIODevice::ReadOnly)) {QMessageBox::warning(this,tr("File error"),tr("Failed to open\n%1").arg(fileName));return;}QTextStream stream(&file);Document *doc = new Document();if (!doc->load(stream)) {QMessageBox::warning(this,tr("Parse error"),tr("Failed to parse\n%1").arg(fileName));delete doc;return;}doc->setFileName(fileName);addDocument(doc);
}QString MainWindow::fixedWindowTitle(const Document *doc) const
{QString title = doc->fileName();if (title.isEmpty())title = tr("Unnamed");elsetitle = QFileInfo(title).fileName();QString result;for (int i = 0; ; ++i) {result = title;if (i > 0)result += QString::number(i);bool unique = true;for (int j = 0; j < documentTabs->count(); ++j) {const QWidget *widget = documentTabs->widget(j);if (widget == doc)continue;if (result == documentTabs->tabText(j)) {unique = false;break;}}if (unique)break;}return result;
}void MainWindow::addDocument(Document *doc)
{if (documentTabs->indexOf(doc) != -1)return;m_undoGroup->addStack(doc->undoStack());documentTabs->addTab(doc, fixedWindowTitle(doc));connect(doc, &Document::currentShapeChanged, this, &MainWindow::updateActions);connect(doc->undoStack(), &QUndoStack::indexChanged, this, &MainWindow::updateActions);connect(doc->undoStack(), &QUndoStack::cleanChanged, this, &MainWindow::updateActions);setCurrentDocument(doc);
}void MainWindow::setCurrentDocument(Document *doc)
{documentTabs->setCurrentWidget(doc);
}Document *MainWindow::currentDocument() const
{return qobject_cast<Document*>(documentTabs->currentWidget());
}void MainWindow::removeDocument(Document *doc)
{int index = documentTabs->indexOf(doc);if (index == -1)return;documentTabs->removeTab(index);m_undoGroup->removeStack(doc->undoStack());disconnect(doc, &Document::currentShapeChanged, this, &MainWindow::updateActions);disconnect(doc->undoStack(), &QUndoStack::indexChanged, this, &MainWindow::updateActions);disconnect(doc->undoStack(), &QUndoStack::cleanChanged, this, &MainWindow::updateActions);if (documentTabs->count() == 0) {newDocument();updateActions();}
}void MainWindow::saveDocument()
{Document *doc = currentDocument();if (doc == nullptr)return;for (;;) {QString fileName = doc->fileName();if (fileName.isEmpty())fileName = QFileDialog::getSaveFileName(this);if (fileName.isEmpty())break;QFile file(fileName);if (!file.open(QIODevice::WriteOnly)) {QMessageBox::warning(this,tr("File error"),tr("Failed to open\n%1").arg(fileName));doc->setFileName(QString());} else {QTextStream stream(&file);doc->save(stream);doc->setFileName(fileName);int index = documentTabs->indexOf(doc);Q_ASSERT(index != -1);documentTabs->setTabText(index, fixedWindowTitle(doc));break;}}
}void MainWindow::closeDocument()
{Document *doc = currentDocument();if (doc == nullptr)return;if (!doc->undoStack()->isClean()) {int button= QMessageBox::warning(this,tr("Unsaved changes"),tr("Would you like to save this document?"),QMessageBox::Yes, QMessageBox::No);if (button == QMessageBox::Yes)saveDocument();}removeDocument(doc);delete doc;
}void MainWindow::newDocument()
{addDocument(new Document());
}static QColor randomColor()
{int r = QRandomGenerator::global()->bounded(3);switch (r) {case 0:return Qt::red;case 1:return Qt::green;default:break;}return Qt::blue;
}static QRect randomRect(const QSize &s)
{QSize min = Shape::minSize;int left = qRound((s.width() - min.width()) * (QRandomGenerator::global()->bounded(1.0)));int top = qRound((s.height() - min.height()) * (QRandomGenerator::global()->bounded(1.0)));int width = qRound((s.width() - left - min.width()) * (QRandomGenerator::global()->bounded(1.0))) + min.width();int height = qRound((s.height() - top - min.height()) * (QRandomGenerator::global()->bounded(1.0))) + min.height();return QRect(left, top, width, height);
}void MainWindow::addShape()
{Document *doc = currentDocument();if (doc == nullptr)return;Shape::Type type;if (sender() == actionAddCircle)type = Shape::Circle;else if (sender() == actionAddRectangle)type = Shape::Rectangle;else if (sender() == actionAddTriangle)type = Shape::Triangle;else return;Shape newShape(type, randomColor(), randomRect(doc->size()));doc->undoStack()->push(new AddShapeCommand(doc, newShape));
}void MainWindow::removeShape()
{Document *doc = currentDocument();if (doc == nullptr)return;QString shapeName = doc->currentShapeName();if (shapeName.isEmpty())return;doc->undoStack()->push(new RemoveShapeCommand(doc, shapeName));
}void MainWindow::setShapeColor()
{Document *doc = currentDocument();if (doc == nullptr)return;QString shapeName = doc->currentShapeName();if (shapeName.isEmpty())return;QColor color;if (sender() == actionRed)color = Qt::red;else if (sender() == actionGreen)color = Qt::green;else if (sender() == actionBlue)color = Qt::blue;elsereturn;if (color == doc->shape(shapeName).color())return;doc->undoStack()->push(new SetShapeColorCommand(doc, shapeName, color));
}void MainWindow::addSnowman()
{Document *doc = currentDocument();if (doc == nullptr)return;// Create a macro command using beginMacro() and endMacro()doc->undoStack()->beginMacro(tr("Add snowman"));doc->undoStack()->push(new AddShapeCommand(doc,Shape(Shape::Circle, Qt::blue, QRect(51, 30, 97, 95))));doc->undoStack()->push(new AddShapeCommand(doc,Shape(Shape::Circle, Qt::blue, QRect(27, 123, 150, 133))));doc->undoStack()->push(new AddShapeCommand(doc,Shape(Shape::Circle, Qt::blue, QRect(11, 253, 188, 146))));doc->undoStack()->endMacro();
}void MainWindow::addRobot()
{Document *doc = currentDocument();if (doc == nullptr)return;// Compose a macro command by explicitly adding children to a parent commandQUndoCommand *parent = new QUndoCommand(tr("Add robot"));new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(115, 15, 81, 70)), parent);new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(82, 89, 148, 188)), parent);new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(76, 280, 80, 165)), parent);new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(163, 280, 80, 164)), parent);new AddShapeCommand(doc, Shape(Shape::Circle, Qt::blue, QRect(116, 25, 80, 50)), parent);new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(232, 92, 80, 127)), parent);new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(2, 92, 80, 125)), parent);doc->undoStack()->push(parent);
}void MainWindow::about()
{QMessageBox::about(this, tr("About Undo"), tr("The Undo demonstration shows how to use the Qt Undo framework."));
}void MainWindow::aboutQt()
{QMessageBox::aboutQt(this, tr("About Qt"));
}

main.cpp


#include <QApplication>
#include "mainwindow.h"int main(int argc, char **argv)
{Q_INIT_RESOURCE(undo);QApplication app(argc, argv);MainWindow win;win.resize(800, 600);win.show();return app.exec();
}

UI布局界面:

运行效果:

undo工程文件下载资源链接: 

下篇文章链接:二 Qt控件之四五:item widgets

上一篇文章:Qt6教程之二(3) Buttons

更多推荐

Qt6教程之二(4) item views

本文发布于:2024-03-05 07:05:44,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1711634.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:之二   教程   item   views

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!