多窗口之间通信和发送数据
多窗口之间通信和数据传送中使用了两种模式:第一种是使用了单例模式。第二种使用了观察者模式。如果有不足之处或者哪里有错误请多多指点。
第一种单例模式
点击下图空白区域,新建"新建项目",会弹出新窗口。因为这种比较简单,就使用单例模式:
单例模式介绍:
创建一个单例的类WidMessageManage
#ifndef MESSAGETYPES_H
#define MESSAGETYPES_H
#include <QString>
//单例模式的宏
#define POP_NEW_PRO_DIALOG_MESSAGE 1
#define UP_DATA_TREEFORM_MESSAGE 20
#define READE_SQLITE_FILE_NAMES 21
#define CREADE_SQLITE_TABLE_NAMES 22
#define READE_SQLITE_TABLE_NAMES 30
#ifndef WIDMESSAGEMANAGE_H
#define WIDMESSAGEMANAGE_H
#include <QObject>
#include <QVariant>
#include "MessageTypes.h"
class WidMessageManage : public QObject
{
Q_OBJECT
public:
static WidMessageManage *instance();
signals:
//全局单例模式,信号
void messageReceived(int MessageTypes,QVariant data);
public slots:
//全局单例模式,发送信号
void sendMessage(int MessageTypes,QVariant data);
};
#endif // WIDMESSAGEMANAGE_H
#include "WidMessageManage.h"
WidMessageManage *WidMessageManage::instance()
{
static WidMessageManage instance;
return &instance;
}
void WidMessageManage::sendMessage(int MessageTypes, QVariant data)
{
emit messageReceived(MessageTypes,data);
}
单例模式使用:
在窗口类PopCreateNewProDialog中使用WidMessageManage::instance()->sendMessage(POP_NEW_PRO_DIALOG_MESSAGE,str);函数实现单例模式发送消息和数据。
#include "PopCreateNewProDialog.h"
#include "ui_PopCreateNewProDialog.h"
#include "MessageTypes.h"
#include "WidMessageManage.h"
#include <QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
PopCreateNewProDialog::PopCreateNewProDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::PopCreateNewProDialog)
{
ui->setupUi(this);
//1.将窗口设置窗口
setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
//2.禁止拖动窗口大小
setFixedSize(this->width(),this->height());
//3.将窗口设置为关闭释放内存
setAttribute(Qt::WA_DeleteOnClose);
//4.随主函数关闭而关闭
setAttribute(Qt::WA_QuitOnClose, false);
//5.设置模态模式
setModal(true);
setWindowTitle(tr("新建项目名称"));
}
PopCreateNewProDialog::~PopCreateNewProDialog()
{
if(nullptr !=ui)
{
delete ui;
ui=nullptr;
}
}
void PopCreateNewProDialog::on_CreateNewPro_pB_clicked()
{
QString str=ui->CreateNewPro_LineEdit->text();
if(str.isEmpty())
{
return ;
}
WidMessageManage::instance()->sendMessage(POP_NEW_PRO_DIALOG_MESSAGE,str);
deleteLater();
}
在窗口类TreeForm中接收消息和处理。
//通过单例模式,接收信号消息
connect(WidMessageManage::instance(),&WidMessageManage::messageReceived,
this,&TreeForm::WidMessageUpdateRequest);
//单例模式,接收到的信号
void TreeForm::WidMessageUpdateRequest(int messageType, QVariant data)
{
switch (messageType) {
case UP_DATA_TREEFORM_MESSAGE:
updateTreeItem(qvariant_cast<QString>(data));
break;
case CREADE_SQLITE_TABLE_NAMES:
CreateChildItem(qvariant_cast<QStringList>(data),m_parentName);
break;
default:
break;
}
}
观察者模式介绍:
这里使用了中介观察者模式,实现窗口之间互相通信和传数据。
#ifndef UIMEDIATOR_H
#define UIMEDIATOR_H
#include "IObserver.h"
#include <QString>
class IObserver; // 前置声明
class UIMediator
{
public:
virtual void addObserver(IObserver *observer) = 0;
virtual void notifyAll(const QString &message) = 0;
};
#endif // UIMEDIATOR_H
#ifndef UIMEDIATORIMPL_H
#define UIMEDIATORIMPL_H
#include "UIMediator.h"
#include <QVector>
enum MESSAGE
{
TREEFORM_TO_CENTRAFORM_MESSAGE =0x00000001
};
class UIMediatorImpl : public UIMediator
{
public:
//观察者模式,注册
void addObserver(IObserver *observer) override;
//观察者模式,发送信号
void notifyAll(const QString &message) override;
private:
QVector<IObserver *> observers_;
};
#endif // UIMEDIATORIMPL_H
#include "UIMediatorImpl.h"
void UIMediatorImpl::addObserver(IObserver *observer)
{
observers_.push_back(observer);
}
void UIMediatorImpl::notifyAll(const QString &message)
{
for (auto observer : observers_) {
observer->onNotify(message);
}
}
观察者模式使用:
在入口类中创建 UIMediatorImpl 实例化。因为窗口类是嵌入了几层 ,所有这里啰嗦几句。
MainWindow窗口类只是用来,承载窗口使用所有是空白的。主要承载MainForm窗口类使用
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void initController();
private:
UIMediatorImpl mediator;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, p_Controller(new ControllerManager(&mediator))
, p_StackWid(new QStackedWidget(this))
, p_mainForm(new MainForm(&mediator,this))
{
ui->setupUi(this);
this->statusBar()->setSizeGripEnabled(false);//隐藏状态栏上的拖动图标
p_StackWid->addWidget(p_mainForm);
ui->mainWid_centralwidget->layout()->addWidget(p_StackWid);
initController();
}
各个子窗口会在MainForm 实例化,并把观察者中介UIMediator按照参数,传到需要的子窗口类中。
#ifndef MAINFORM_H
#define MAINFORM_H
#include <QWidget>
#include "TreeForm.h"
#include "CentralForm.h"
#include "ParamForm.h"
#include "BottomForm.h"
class UIMediatorImpl;
namespace Ui {
class MainForm;
}
class MainForm : public QWidget
{
Q_OBJECT
public:
explicit MainForm(UIMediator *mediator,QWidget *parent = nullptr);
~MainForm();
private:
Ui::MainForm *ui;
TreeForm *p_treeForm;
CentralForm *p_centralForm;
ParamForm *p_paramForm;
BottomForm *p_bottomForm;
};
#endif // MAINFORM_H
#include "MainForm.h"
#include "ui_MainForm.h"
MainForm::MainForm(UIMediator *mediator, QWidget *parent) :
QWidget(parent),
ui(new Ui::MainForm)
, p_treeForm(new TreeForm(mediator))
, p_centralForm(new CentralForm(mediator))
, p_paramForm(new ParamForm)
, p_bottomForm(new BottomForm)
{
ui->setupUi(this);
ui->treewid->layout()->addWidget(p_treeForm);
ui->centralwid->layout()->addWidget(p_centralForm);
ui->paramwid->layout()->addWidget(p_paramForm);
ui->bottomwid->layout()->addWidget(p_bottomForm);
}
MainForm::~MainForm()
{
delete ui;
}
子窗口使用观察者模式:
#ifndef TREEFORM_H
#define TREEFORM_H
#include <QWidget>
#include <QMenu>
#include <QVariant>
#include <QTreeWidgetItem>
#include "PopCreateNewProDialog.h"
#include "addSQLiteTableDialog.h"
#include "IObserver.h"
#include "UIMediator.h"
class UIMediator;
namespace Ui {
class TreeForm;
}
class TreeForm : public QWidget ,IObserver
{
Q_OBJECT
public:
explicit TreeForm(UIMediator *mediator,QWidget *parent = nullptr);
~TreeForm();
//观察者模式,接收信号
void onNotify(const QString &message) override;
//观察者模式,发送信号
void doSomething(const QString &message);
private:
//观察者模式,中介者
UIMediator *mediator_;
private:
void updateTreeItem(const QString &PathFile);
private:
//初始化菜单
void InitRightMenu();
private slots:
//弹出,创建新项目的Dialog
void PopCreateProDialog();
//qtreeWidget右键弹出菜单窗口
void SlotsPopUpMenu(const QPoint &pos);
void PopCreateTableDialog();
//执行点击内容时需要做的操作
void on_TreeForm_treeWidget_itemClicked(QTreeWidgetItem *item, int column);
// 执行在展开项时需要做的操作
void on_TreeForm_treeWidget_itemExpanded(QTreeWidgetItem *item);
// 用户点击了三角箭头,当前项折叠
void on_TreeForm_treeWidget_itemCollapsed(QTreeWidgetItem *item);
public slots:
//单例模式,接收到的信号
void WidMessageUpdateRequest(int messageType, QVariant data);
private:
//创建Item
void CreateTopItem(const QString &PathFile,const QString Type);
//创建Item的子项目
void CreateChildItem(const QStringList &strList,const QString &parentName);
//Delete Child Item
void DeleteChildItem(QTreeWidgetItem *item);
private:
QMenu *p_newProMenu;
QMenu *p_CreateTableMenu;
QAction *p_newProQAction;
QAction *p_CreateTableQAction;
private:
QString m_TreeItemParentName=NULL;
QList<QTreeWidgetItem *> topParentItemNames;
QString m_parentName;
QString mItemParentName=NULL;
private:
PopCreateNewProDialog *p_popCreateNewDialog=nullptr;
addSQLiteTableDialog *p_addSQLiteTableDialog=nullptr;
private:
Ui::TreeForm *ui;
};
#endif // TREEFORM_H
#include "TreeForm.h"
#include "ui_TreeForm.h"
#include "MessageTypes.h"
#include "WidMessageManage.h"
#include "UIMediator.h"
#include <QDir>
#include <QFileInfo>
#include <QDateTime>
#include <map>
#include <QTreeWidgetItem>
#include <QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
TreeForm::TreeForm(UIMediator *mediator,QWidget *parent) :
QWidget(parent),
mediator_(mediator)
, ui(new Ui::TreeForm)
{
ui->setupUi(this);
ui->TreeForm_treeWidget->setHeaderLabel(tr("项目名称"));
InitRightMenu();
//响应右键菜单信号槽-qtreeWidget右键弹出菜单窗口
connect(ui->TreeForm_treeWidget,&QTreeWidget::customContextMenuRequested,
this,&TreeForm::SlotsPopUpMenu);
//通过单例模式,接收信号消息
connect(WidMessageManage::instance(),&WidMessageManage::messageReceived,
this,&TreeForm::WidMessageUpdateRequest);
//注册观察者模式,信号接收人
mediator_->addObserver(this);
/**************************************************************/
//刷新Item目录
WidMessageManage::instance()->sendMessage(READE_SQLITE_FILE_NAMES,NULL);
}
TreeForm::~TreeForm()
{
delete ui;
}
//观察者模式,接收信号
void TreeForm::onNotify(const QString &message)
{
}
//观察者模式,触发信号
void TreeForm::doSomething(const QString &message)
{
mediator_->notifyAll(message);
}
void TreeForm::updateTreeItem(const QString &PathFile)
{
QString targetFormat=".db";
CreateTopItem(PathFile,targetFormat);
}
//初始化右键菜单
void TreeForm::InitRightMenu()
{
//打开右键菜单属性
ui->TreeForm_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
/*********************新建项目************************/
//右键菜单
p_newProMenu =new QMenu(ui->TreeForm_treeWidget);
p_newProQAction=new QAction;
p_newProQAction->setText(tr("新建项目"));
p_newProMenu->addAction(p_newProQAction);
p_newProMenu->addAction("取消");
//响应右键菜单信号槽
connect(p_newProQAction,SIGNAL(triggered()),
this,SLOT(PopCreateProDialog()));
/*********************新建表************************/
//右键菜单
p_CreateTableMenu= new QMenu(ui->TreeForm_treeWidget);
p_CreateTableQAction= new QAction;
p_CreateTableQAction->setText(tr("创建SQLite表名"));
p_CreateTableMenu->addAction(p_CreateTableQAction);
p_CreateTableMenu->addAction(tr("取消"));
//响应右键菜单信号槽
connect(p_CreateTableQAction,SIGNAL(triggered()),
this,SLOT(PopCreateTableDialog()));
}
//弹出,创建新项目的Dialog
void TreeForm::PopCreateProDialog()
{
p_popCreateNewDialog=new PopCreateNewProDialog;
p_popCreateNewDialog->show();
}
//qtreeWidget右键弹出菜单窗口
void TreeForm::SlotsPopUpMenu(const QPoint &pos)
{
//弹出菜单
QTreeWidgetItem *clickedItem=ui->TreeForm_treeWidget->itemAt(pos);
//弹出菜单判断是否,有父Item
if(NULL != clickedItem)
{
//判断是父节点
if(clickedItem->parent()==nullptr)
{
m_TreeItemParentName=clickedItem->text(0);
p_CreateTableMenu->exec(ui->TreeForm_treeWidget->mapToGlobal(pos));
}
}
//弹出菜单是没有父Item 在空白处点击了右键,弹性窗口菜单
else
{
p_newProMenu->exec(ui->TreeForm_treeWidget->mapToGlobal(pos));
}
}
void TreeForm::PopCreateTableDialog()
{
addSQLiteTableDialog::CreateEidtSQLiteDialog(mItemParentName);
}
//单例模式,接收到的信号
void TreeForm::WidMessageUpdateRequest(int messageType, QVariant data)
{
switch (messageType) {
case UP_DATA_TREEFORM_MESSAGE:
updateTreeItem(qvariant_cast<QString>(data));
break;
case CREADE_SQLITE_TABLE_NAMES:
CreateChildItem(qvariant_cast<QStringList>(data),m_parentName);
break;
default:
break;
}
}
void TreeForm::CreateTopItem(const QString &PathFile,const QString Type)
{
topParentItemNames.clear();
// 清空原有的顶层项
ui->TreeForm_treeWidget->clear();
QString targetFormat=Type;
if(PathFile.isNull())
{
cout<<"filesName";
return;
}
// 用于存储文件创建时间和文件名的映射
QString fliename=PathFile;//.toString();
QDir directory(fliename);
QStringList files=directory.entryList(QDir::Files);
QMap<QDateTime,QString>fileMap;
foreach (const QString &file, files)
{
//判断数据类型,挑选.DB数据类型
if(file.endsWith(targetFormat))
{
QFileInfo fileInfo(directory.absoluteFilePath(file));
QDateTime createdTime = fileInfo.created(); // 获取文件创建时间
// 将文件创建时间和文件名存入映射中
fileMap.insert(createdTime, file);
}
}
// 提取 QMap 的 key 到 QList 中
QList<QDateTime> sortedKeys = fileMap.keys();
// 根据创建时间创建 QTreeWidgetItem 并添加到 treeWidget 中
int sortedKeys_size=sortedKeys.size();
for(int i = sortedKeys_size- 1; i >= 0; --i)
{
const QDateTime &time = sortedKeys.at(i);
QTreeWidgetItem *newTopItem=new QTreeWidgetItem(ui->TreeForm_treeWidget);
newTopItem->setTextAlignment(0,Qt::AlignLeft | Qt::AlignVCenter); // 左对齐
// newTopItem->setData(0, Qt::UserRole, index); // 设置序号数据
// newTopItem->setText(0, QString::number(index) + ". " + file); // 显示序号和文件名
// 去掉文件名后缀
QString fileWithoutExtension = fileMap.value(time);
fileWithoutExtension.remove(targetFormat);
newTopItem->setData(0, Qt::UserRole, fileWithoutExtension); // 设置文件名数据
newTopItem->setText(0, fileWithoutExtension); // 显示文件名
// 设置显示三角箭头
newTopItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
ui->TreeForm_treeWidget->addTopLevelItem(newTopItem);
topParentItemNames.append(newTopItem);
}
// cout<<topParentItemNames.size();
// cout<<topParentItemNames.at(3)->text(0);
}
//创建Item的子项目
void TreeForm::CreateChildItem(const QStringList &strList,const QString &parentName)
{
// 遍历 QList<QTreeWidgetItem *> topParentItemNames
//topParentItemNames.clear();
for (QTreeWidgetItem *parentItem : topParentItemNames)
{
// 根据具体条件判断是否当前的 parentItem 是你要找的父项
if (parentItem->text(0) == parentName) // 假设父项的文本与 parentName 匹配
{
// 创建子项并添加到父项中
for (const QString &text : strList)
{
QTreeWidgetItem *childItem = new QTreeWidgetItem(parentItem, QStringList(text));
parentItem->addChild(childItem);
}
// 如果只需要找到一个合适的父项,可以在此处 break;
break;
}
}
}
void TreeForm::DeleteChildItem(QTreeWidgetItem *item)
{
// 删除子项
for (int i = item->childCount() - 1; i >= 0; --i)
{
delete item->child(i);
}
}
//执行点击内容时需要做的操作
void TreeForm::on_TreeForm_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
{
cout << "Arrow clicked - Expanded";
if (column == 0) { // 只处理第一列的点击事件,如果有多列,根据实际情况修改
if (item->childCount() > 0 && ui->TreeForm_treeWidget->isItemExpanded(item)) {
// 用户点击了三角箭头,并且当前项展开着
// 执行相应的动作
cout << "Arrow clicked - Expanded";
} else if (item->childCount() > 0 && !ui->TreeForm_treeWidget->isItemExpanded(item)) {
// 用户点击了三角箭头,并且当前项折叠着
// 执行相应的动作
cout << "Arrow clicked - Collapsed";
DeleteChildItem(item);
}
}
}
//执行在展开项时需要做的操作
void TreeForm::on_TreeForm_treeWidget_itemExpanded(QTreeWidgetItem *item)
{
QString str=item->text(0);
if(str!=NULL)
{
m_parentName=str;
WidMessageManage::instance()->sendMessage(READE_SQLITE_TABLE_NAMES,str);
}
}
// 用户点击了三角箭头,当前项折叠
void TreeForm::on_TreeForm_treeWidget_itemCollapsed(QTreeWidgetItem *item)
{
DeleteChildItem(item);
}