博客
关于我
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/

你可能感兴趣的文章
No qualifying bean of type ‘com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>‘ available
查看>>
No resource identifier found for attribute 'srcCompat' in package的解决办法
查看>>
no session found for current thread
查看>>
No static resource favicon.ico.
查看>>
no such file or directory AndroidManifest.xml
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
NO.23 ZenTaoPHP目录结构
查看>>
no1
查看>>
NO32 网络层次及OSI7层模型--TCP三次握手四次断开--子网划分
查看>>
NOAA(美国海洋和大气管理局)气象数据获取与POI点数据获取
查看>>
NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
查看>>
node
查看>>
node exporter完整版
查看>>
node HelloWorld入门篇
查看>>
Node JS: < 一> 初识Node JS
查看>>
Node JS: < 二> Node JS例子解析
查看>>
Node Sass does not yet support your current environment: Linux 64-bit with Unsupported runtime(93)解决
查看>>
Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime(72)
查看>>
Node 裁切图片的方法
查看>>
node+express+mysql 实现登陆注册
查看>>