An application of Qt

A Naruto-Themed Data analyzer with GUI

1. Introduction

​ As the final program of the course problem solving and practice, this project took more time than I have envisaged. But finally all the mandatory and elective functions are realized, and it’s fairly complete and robust. Furthermore I added a multitude of Naruto-related pictures to make it look better and to make the process more enjoyable holistically. By now it can analyze both users and places by charts or on the map, and it can also give an access of the similarity between two users or two places concerning on the spatio-temporal information given.

​ Generally speaking, the whole project can be divided into two parts, with two mainwindows dealing with the corresponding tasks. The first is the part coping with the data while loading, in which I used QTextStream to read the information line by line and stored them in the data structure after pretreatment. It looks like the picture below.

The second part is for the series of tasked based on the data stored after filtration. The user of this UI can push the buttons on the working window demonstrated below.

​ Another point worth mentioning is the usage of the class QThread. For each task I wrote a class to do the data-dealing work. The object of it will be put into a subthread, and transmit certain data structures back after doing the work . Another method is to put all the tasks into one class named Tasks. This can reduce the number of header files you write, but it may not be so friendly when debugging.

2. Details of the project

About data-loading

After clicking the button, a filter window will be shown to select the range and field you need. And when the user pushes the button”选好惹”,the parameters will be recorded simultaneously, and the data will embark to load.

A class named loadfile is used for the part. An object of it will be created and added to a subthread:

1
2
3
4
5
6
//创建子线程对象
QThread *t=new QThread;
//创建任务类对象
loadfile * load=new loadfile;
//将任务类对象移动到子线程中
load->moveToThread(t);

and a signal will be send so that the object can do its work:

1
2
3
4
//关联信号函数
connect(this,&MainWindow::loadStart,load,&loadfile::startLoad);
//启动子线程
t->start();

During the process, we will also receive the data sent back, so that the ProgressBar can update itself and the button can be set to be clickable after all the data is successfully loaded:

1
2
3
4
5
6
//接收子线程发送的数据
demo->ui->pushButton->setDisabled(true);
connect(load,&loadfile::transmitCounter,this,[=](int i)
{
pointer->setValue(i*100/1500000);
});

finally after all those mentioned above, the ui of my work window will be shown and the user can select the tasks he want:

1
2
//切换到工作界面
connect(demo->ui->pushButton,&QPushButton::clicked,this,&MainWindow::switchToWorkWindow);

An example of the details in the basic functions

for every function, a corresponding task class as long as a ui for parameters selection is written. A better way method may be that we can put all the ui we need into one single window, and use the class QStackedWidgets to switch between the pages. But as I have gone far on my way, I didn’t consider changing the structure.

​ Let’s take the function of comparing two places as an example, others can be realized in a similar way.

​ After the task class(named visitcmp in my case)has received the data, it will do its work and generate the objects of QPieSeries and QLineSeries :

1
2
3
4
5
6
7
8
9
10
11
12
13
//饼图
QPieSeries *pieserie = new QPieSeries();
pieserie->append(QString::number(loc1),loc1visitor);
pieserie->append(QString::number(loc2),loc2visitor);
//线图
QLineSeries * trackseries1=new QLineSeries;
for(int i=0;i<a.length();i++)
{
if(a[i].totalvisit!=0)
{
trackseries1->append(QDateTime(a[i].date).toMSecsSinceEpoch(),a[i].totalvisit);
}
}

and send the series back using signals in Qt:

1
emit sendData(pieserie,trackseries1,trackseries2);

after that our workwindow will receive the series and use them to draw the picture we want.

But I soon discovered that as there is an enormous number of data, the line on the picture is so thick and tight that the picture can’t be uglier and it can not be adjusted by the events of my mouse:

To partly solve the problem, I rewrite the class QChartView . A class named ChartView inherited the original class, in which I rewrite the mouse events

In mouse move events, the start and end coordinates of the mouse is recorded, and the graph is moved along with the vector we get through the mouse action:

1
2
3
4
5
6
7
8
QPoint moveVec=curPos-m_last;//移动向量
m_last=curPos;//更新鼠标的现在位置
if(!m_rangesaved)
{
m_rangesaved=true;
this->saveAxisRange();
}
this->chart()->scroll(-moveVec.x(),moveVec.y());//实现拖动鼠标的移动功能

In wheel event I used zoomIn and zoomOut to make the picture larger or smaller according to the wheel:

1
2
3
4
5
const qreal fractor=1.2;
if(event->delta()>0)
this->chart()->zoom(fractor);
else
this->chart()->zoom(1/fractor);

which yields:

In addition to my method of rewritting the QChartView class , the class QCustomePlot may also be a powerful tool.

About the use of map

​ Adding a map is probably the most difficult part. First we need to write a QML file,which import a map from the Internet using the element Plugin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//接口
Plugin{
id:mapPlugin
name:"esri"//就这个显示的出来
}
//地图
Map{
id:map
visible: true
anchors.fill:parent
plugin:mapPlugin
zoomLevel: (maximumZoomLevel-minimumZoomLevel)*0.9

center:QtPositioning.coordinate(30.67, 104.05)//我大成都的坐标!
ListModel{
id:currentLoc
}
Slider{
id:zoom
value:(map.maximumZoomLevel-map.minimumZoomLevel)/2
from:map.minimumZoomLevel
to:map.maximumZoomLevel
Text {
id: zoomAdjust
text: qsTr("zoomAdjust")
}
onValueChanged: map.zoomLevel=zoom.value
}
}

​ in it Sliders are applied to adjust the view, (the tilt angle ,zoomin and zoomout ,rotation,ect.).

​ Several mapItemViews are added too, and each of them contains a Model that can show the coordinate of a certain people:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MapItemView{
id:routeDraw
model:currentRoute
delegate: trackDrawRoute
}
Component{
id:trackDrawRoute
MapItemGroup{
MapPolyline{
id:mapRouteLine
line.width: 1
line.color: "blue"
path:[origin,destination]
visible: isVisible
}
}
}

​ As a single people may go to many placed adjacent to each other, showing all the points in one go may be too ugly. I added a Timer, and after an interval of 500ms, a function is called and a new point will be set visible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//计时器类 
Timer{
id:animationTimer
interval:500
running: true
repeat: true
onTriggered: {
routeDraw.triggerRouteDemo()
}
}
//相应函数
function triggerRouteDemo(){
var lenth= currentRoute.count
for(var i=0;i<lenth;i++)
{
var data=currentRoute.get(i)
if(data.isVisible===false)
{
currentRoute.setProperty(i,"isVisible",true)
break
}

}
}

​ Also I customized the marker:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MapQuickItem{
id:userLocMaker
sourceItem: Image{
id: image
source: "qrc:/img/sources/kai.png"//设定成自己的图片
width:28
height:28
}
//从Model中取得坐标
coordinate: QtPositioning.coordinate(location.latitude,location.longitude)
anchorPoint.x: image.width/2
anchorPoint.y: image.height
visible: isVisible
}

and used QMetaObject::invokeMethod to transmit data from QT to QML:

1
QMetaObject::invokeMethod(proot,"ready",Q_ARG(QVariant,manager->m_locList.back()));

3. Results of the project

​ In general ,this GUI has realized all the functions required. Many kinds of graphs are applied, and It can show a map and give an report of two persons.

​ But some graph is still ugly, and the windows and buttons can still be optimized. I will not improved after 3 weeks spent on it for now because of the final tests. But I believe I will:

  • reduce the number of UIs, make them as a whole and more beautiful.
  • improve the legends on each graph, and try customeplot to draw pictures.
  • simplify the code and improve the complexity.

4. Further discussions

 In the part of data deep mining, I divided American land into 9 part according to **百度**, and analyze the similarity of two persons according to their times of visit in the 9 parts. While I use the time information to analyze the similarity of two places. That is, if they are visited by a similar number of people in a single day, we can decide how similar are they.

​ From the results, I suppose that maybe a certain group of people are friends or families, maybe we can do further analyze to decide where their home probably are. In another aspects, maybe some places are places of interests, so they are visited by many people in holidays.

​ Further work can be done to analyze these factors.

——-Otsutsuki_Orance

2021.12.27


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!