博客
关于我
Qt之动态换图
阅读量:97 次
发布时间:2019-02-26

本文共 4006 字,大约阅读时间需要 13 分钟。

Abstract:
1,“动态创建”
2,封装qwt的Plot类
3,拖拽
4,Plot类型转换
一、功能描述
假设有一个信号分析的软件工程,在它的主窗口mainwindow上,左侧是一个测试项列表(QListWidget),右侧是四个图形窗口(Plot or QTableWidget)用于观察测试项的图形结果。现在要实现的功能是:通过拖拽右侧测试项列表中任一项到右侧的任一窗口,即可在该窗口观察对应的测试项图形结果,且这个图形结果有多种形式,如曲线图(PlotCurve)、光栅图(PlotRaster)和表格(
QTableWidget
)等,具体是哪种形式由具体的测试项决定。
二、功能分解实现
1,UI布局
通过Qt Designer,在左侧布一个
QListWidget,右侧布一个QFrame。然后将
QListWidget提升为CustomListWidget,使它支持拖拽功能(参考《C++ GUI Qt4》第9章“拖拽”的第一个例子),主要是重写函数
mousePressEvent
()和
mouseMoveEvent()。再然后
将右侧
QFrame提升为QuadSplitter(参考我的博文:
。最后就是用四个QWidget填充QuadSplitter。具体如下:
在mianwindow.h中定义:
static const int    s_iWidgetsNumber = 4;    // 右侧显示区的图表数量
QWidget           * m_pShowWidgets[2][2];    // 右侧显示区的四幅图或表
实现:
void MainWindow::CreateCharts()
{
for (int i = 0; i < s_iWidgetsNumber; i++)
{
// 创图表
m_pShowWidgets[i/2][i%2] = new Plot;
ui->frameDisplay->addWidget(m_pShowWidgets[i/2][i%2], i/2, i%2);
 
connect(m_pShowWidgets[i/2][i%2], SIGNAL(FullScreenToggle(QWidget*,bool)), this, SLOT(OnToggleSize(QWidget*,bool)));
connect(m_pShowWidgets[i/2][i%2], SIGNAL(DragComplete(QWidget*, QString)), this, SLOT(OnDragComplete(QWidget*, QString)));
}
}
上述代码中,还建立了两对信号与槽的连接,在后续将予以说明。
2,数据观察窗口
上面已经提到,测试项的图形结果有几种呈现形式:曲线图、光栅图和表格。其中图类,我采用QWT库,并封装一个Plot类,然后派生出PlotCurve和PlotRaster;表格的实现,为简单起见也是从Plot类派生出一个PlotTable类,在构造函数中将Plot相关的特性全部隐藏,然后采用PIMP模式(
pointer to implementation模式
),定义一个CustomTableWidget指针成员。事实上,直接使用CustomTableWidget也可以,只是在客户代码中要进行相应修改。下面再列出一些关键代码:
1)Plot的相关信号函数
signals:
void FullScreenToggle(QWidget* pWidget, bool bFullScreen);
void DragComplete(QWidget* pWidget, QString strTestItem);
2)Plot需要重写的事件处理函数
void Plot::mouseDoubleClickEvent(QMouseEvent *event)
{
if (Qt::LeftButton == event->button())
{
 
m_bFullScreen = !m_bFullScreen;
emit FullScreenToggle(this, m_bFullScreen);
}
else if (Qt::RightButton == event->button())
{
 
if (m_pPlotZoomer != NULL)
m_pPlotZoomer->zoom(0);
}
}
 
void Plot::dragEnterEvent(QDragEnterEvent *event)
{
DragListWidget *source = dynamic_cast<DragListWidget*>(event->source());
if (NULL == source)
return;
 
event->setDropAction(Qt::MoveAction);
event->accept();
}
 
void Plot::dropEvent(QDropEvent *event)
{
DragListWidget *source = dynamic_cast<DragListWidget*>(event->source());
if (NULL == source)
return;
 
event->setDropAction(Qt::MoveAction);
event->accept();
 
emit DragComplete(this, event->mimeData()->text());
}
 
这个几个函数主要实现两个功能。第一个是实现双击放大指定窗口到填充整个QuadSplitter。其原理是Plot接收鼠标双击事件,然后给mainwindow发信号,mainwindow的槽函数再来调整
QuadSplitter。这就是上面第一个connect()函数的作用。第二个是实现拖拽进入处理和拖拽释放处理。通过拖拽,在本例传递过来的是一个字符串,即CustomListWidget中某项-测试项名。
3,测试项的“动态创建”
对于测试项,我采用的是“动态创建”的设计模式,参考我的博文:  。不同的是,我的CTestItem是继承自QObject,并添加了Q_OBJECT宏。因为,我在mianwindow中是这样定义的:
QPointer<CTestItem> m_pTestItems[2][2];      // 显示在界面的四个测试项,与上面的四幅图或表一一对应
将CTestItem用QPointer管理起来,不需要手动管理内存。但是,QPointer管理的对象必须是QObject及其子类,且不可复制。
再来看切换函数:
void MainWindow::OnDragComplete(QWidget *pWidget, QString itemName)
{
for (int i = 0; i < s_iWidgetsNumber; ++i)
{
if (pWidget == (m_pShowWidgets[i/2][i%2]))
{
//             if (itemName.toStdWString().c_str() == m_pTestItems[i/2][i%2]->GetClassName())
//                 return;
 
m_pTestItems[i/2][i%2] = CRuntimeClass::LoadObject(itemName.toStdWString().c_str(), &m_pShowWidgets[i/2][i%2]);
 
// 测试项切换时,如果前后图表的类型不一致,会在CTestItem的构造函数中进行delete和new的操作
// delete操作会消除m_pShowWidgets之前建立起来的父子对象关系以及信号与槽函数的绑定关系,故需重新建立
if (m_pShowWidgets[i/2][i%2]->parentWidget() != ui->frameDisplay)
{
ui->frameDisplay->addWidget(m_pShowWidgets[i/2][i%2], i/2, i%2);
connect(m_pShowWidgets[i/2][i%2], SIGNAL(FullScreenToggle(QWidget*,bool)), this, SLOT(OnToggleSize(QWidget*,bool)));
connect(m_pShowWidgets[i/2][i%2], SIGNAL(DragComplete(QWidget*, QString)), this, SLOT(OnDragComplete(QWidget*, QString)));
}
break;
}
}
}
仅仅只需将测试项名(字符串)传入即可,其他的由“动态创建”机制来处理。另一出彩的设计是,在具体的CTestItemA的构造函数中,需要对传入的QWidget进行类型判断。如下:
if (!(m_pShowWidget = qobject_cast<PlotCurve *>(*ppWidget)))
{
qDebug("qobject_cast *>(ppWidget) fail");
delete (*ppWidget);
*ppWidget = NULL;
*ppWidget = m_pShowWidget = new PlotCurve;
}
如果传入的是匹配的类型则直接转换,不匹配则删除之前的再new新的匹配的类型。

转载地址:http://qkqu.baihongyu.com/

你可能感兴趣的文章
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置binlog_使用处理器抓取binlog数据_实际操作01---大数据之Nifi工作笔记0040
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_实现数据插入数据到目标数据库_实际操作03---大数据之Nifi工作笔记0042
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_生成插入Sql语句_实际操作02---大数据之Nifi工作笔记0041
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_不带分页处理_01_QueryDatabaseTable获取数据_原0036---大数据之Nifi工作笔记0064
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_无分页功能_02_转换数据_分割数据_提取JSON数据_替换拼接SQL_添加分页---大数据之Nifi工作笔记0037
查看>>
NIFI从Oracle11G同步数据到Mysql_亲测可用_解决数据重复_数据跟源表不一致的问题---大数据之Nifi工作笔记0065
查看>>
NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
查看>>
nifi使用过程-常见问题-以及入门总结---大数据之Nifi工作笔记0012
查看>>
NIFI分页获取Mysql数据_导入到Hbase中_并可通过phoenix客户端查询_含金量很高的一篇_搞了好久_实际操作05---大数据之Nifi工作笔记0045
查看>>
NIFI分页获取Postgresql数据到Hbase中_实际操作---大数据之Nifi工作笔记0049
查看>>
NIFI同步MySql数据_到SqlServer_错误_驱动程序无法通过使用安全套接字层(SSL)加密与SQL Server_Navicat连接SqlServer---大数据之Nifi工作笔记0047
查看>>
NIFI同步MySql数据源数据_到原始库hbase_同时对数据进行实时分析处理_同步到清洗库_实际操作06---大数据之Nifi工作笔记0046
查看>>
Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066
查看>>
【Flink】Flink 1.9 版本 web UI 突然没有日志
查看>>
NIFI大数据进阶_FlowFile拓扑_对FlowFile内容和属性的修改删除添加_介绍和描述_以及实际操作---大数据之Nifi工作笔记0023
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_处理器介绍_处理过程说明---大数据之Nifi工作笔记0019
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_实际操作---大数据之Nifi工作笔记0020
查看>>
NIFI大数据进阶_Json内容转换为Hive支持的文本格式_实际操作_02---大数据之Nifi工作笔记0032
查看>>