Qt信号和槽信核心机制
在谈系统的实现时必须先谈一下Qt编程的核心机制——信号和槽机制,要精通Qt编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是Qt的核心特性,简单来说当某个信号比如说click点击,doubleclick双击,当一个widgt绘图有改变,定时器循环到一个周期时,这些所有的事件都可以相当于一个信号发射,只要用一个QObject::connect()函数(具体怎么写,代码里很多很多实例),把对应的SIGNAL(信号)和SLOT(槽)连接,槽是普通的C++成员函数,可以被正常调用,他们可以有很多信号与其相关联,槽函数里写当信号改变时你想让系统完成的功能。这就是我对Qt的信号和槽的初步理解。随着我不断的学习,相信会理解的越来越深刻和准确的。[1]
5.2 系统实现关键代码
5.2.1 大小写转换伪代码
If(价格输入框里面的内容是不是为空)
{
定义变量分别存储价格输入框的值,整数部分的值;
小数部分的值等于输入的值减去整数部分;
定义一个空的QString字符串,留着存储处理流程完毕的最终结果;
定义一个存有"元", "拾", "佰", "仟", "万", "亿"的char数组;
定义一个存有"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"的char数组;
处理整数部分;
把字符转换为数字,即‘0’到0,‘1’到1,‘2’到2等这样;
添加计数单位;
最后在将处理结果QString传到ui中的价格显示的labline;
}
5.2.2 生成合同序号的代码
//生成合同序号函数
QString WeituoInput::reffMake()
{
QSqlQuery query;
query.exec("SELECT max(reff) from ashare_ordwth ");
while(query.next())
{
//qDebug()<<"录入第"<<query.value(0).toInt()+1<<"条记录";
int a = query.value(0).toInt();
++a;
QString str = QString("%1").arg(a,10,10,QChar('0'));
return str;
}
}
5.2.3 画K线图关键代码
void DayLine::paintEvent(QPaintEvent *)
{
QPainter painter(this);
//坐标平移
painter.translate(40,520);
painter.drawText(-30,0,"(0,0)");
QPen pen; //画笔
//绘制背景各个虚线
pen.setStyle(Qt::DotLine); //设置画笔风格 点线
painter.setPen(pen);
//横向虚线
for(int i = 0; i < 18; i++)
{
painter.drawLine(0,-30*i,1500,-30*i);
}
for(int i = 0; i < 15; i++)
{
painter.drawLine(150*i,0,150*i,-510);
}
//画日K线图
float openPrice;//开盘价
float closePrice;//收盘价
float maxPrice;//最高价
float minPrice;//最低价
int j = 0;
// QList<double> open = values.at(3);
// qDebug()<<"开盘价"<<open;
// QList<double> high = values.at(2);
// qDebug()<<"最高价"<<high;
// QList<double> low = values.at(1);
// qDebug()<<"最低价"<<low;
// QList<double> close =values.at(0);
// qDebug()<<"收盘价"<<close;
//新建两个Qlist用于得到所有最高价里的最大值和最低价里的最小值
QList<double> maxlist =high;
qDebug()<<"最高价maxlist排序前"<<maxlist;
qSort(maxlist.begin(), maxlist.end(),qGreater<double>());//将最高价格按照递减排序得到
QList<double> minlist =low;
qDebug()<<"最低价minlist排序前"<<minlist;
qSort(minlist.begin(), minlist.end());//将最高价格按照递增排序得到
qDebug()<<"maxlist.at(0)"<<maxlist.at(0);
qDebug()<<"minlist.at(0)"<<minlist.at(0);
double highestMaxPrice =maxlist.at(0);
double lowestMinPrice =minlist.at(0);
for(int a=0;a<60;a++)
{
openPrice=open.at(a);
minPrice=low.at(a);
maxPrice=high.at(a);
closePrice=close.at(a);
j++;
//开始对得到Qlist数据进行处理,画出K线图
if(openPrice <= closePrice)
{
pen.setStyle(Qt::SolidLine);
pen.setColor(QColor(255,0,0));
QBrush brush(QColor(255,0,0)); //画刷
painter.setPen(pen); //添加画笔
painter.setBrush(brush); //添加画刷
painter.drawRect(j*15+1,-350*(closePrice-lowestMinPrice)/(highestMaxPrice - lowestMinPrice),
13,-350*(closePrice-openPrice)/(highestMaxPrice - lowestMinPrice)); //绘制矩形 painter.drawLine(j*15+8,-350*(maxPrice-lowestMinPrice)/(highestMaxPrice - lowestMinPrice), j*15+8,-350*(minPrice-lowestMinPrice)/(highestMaxPrice - lowestMinPrice)); //绘制直线
}
else
{
pen.setStyle(Qt::SolidLine);
pen.setColor(QColor(0,255,0));
QBrush brush(QColor(0,255,0)); //画刷
painter.setPen(pen); //添加画笔
painter.setBrush(brush); //添加画刷 painter.drawRect(j*15+1,-350*(openPrice-lowestMinPrice)/(highestMaxPrice - lowestMinPrice),13,-350*(closePrice - openPrice)/(highestMaxPrice - lowestMinPrice)); //绘制矩形 painter.drawLine(j*15+8,-350*(maxPrice-lowestMinPrice)/(highestMaxPrice - lowestMinPrice),j*15+8,-350*(minPrice-lowestMinPrice)/(highestMaxPrice - lowestMinPrice)); //绘制直线
}
}
}
5.2.4 解析导入的.csv表格文件关键代码
处理导入的csv数据文件函数
QMultiMap <int,QList<double> >StockInfo::importData(QString PATH)
{
QFile csvFile(PATH);
QStringList CSVList;
CSVList.clear();
if (csvFile.open(QIODevice::ReadWrite))
{
QTextStream stream(&csvFile);
while (!stream.atEnd())
{
CSVList.push_back(stream.readLine());//push_back作用为在list尾部加入一个数据
}
csvFile.close();
}
//处理之前先声明四个Qlist分别用来存储开收高低四个价格
QList<double> open;
QList<double> high;
QList<double> low;
QList<double> close;
int i;
for(i=0;i<60;i++)
{
QStringList stockList = CSVList[i+1].split(",");
//使用Inseert而不用append是因为这样可以把本来读取到的今天的数据在最前面转换到最后去
open.insert(0,stockList[1].toDouble());
high.insert(0,stockList[2].toDouble());
low.insert(0,stockList[3].toDouble());
close.insert(0,stockList[4].toDouble());
}
qDebug()<<"stockinfo中开盘价"<<open;
qDebug()<<"stockinfo中最高价"<<high;
qDebug()<<"stockinfo中最低价"<<low;
qDebug()<<"stockinfo中收盘价"<<close;
//然后把这个四个list用多值QMap存储返回待用
QMultiMap <int,QList<double> > multimap;
multimap.insert(0,open);
multimap.insert(0,high);
multimap.insert(0,low);
multimap.insert(0,close);
return multimap;
}
5.2.5 “价格优先,时间优先”撮合原则关键代码
第一步:首先分别用两个函数将委托表中的委托记录按照买卖标志’B’或者’s’来排序
1.买的记录按照价格从高到低排序
void PanKou::getB_record()
{
//过滤出买入的记录
B_model->setFilter(QObject::tr("bs= '%1'").arg("B"));
//根据价格属性,即第7列,按价格降序排列保证买入队列价格高的在最前面
B_model->setSort(7,Qt::DescendingOrder);
}
2.卖的记录按照价格从低到高排序
void PanKou::getS_record()
{
//过滤出卖出的记录
S_model->setFilter(QObject::tr("bs= '%1'").arg("S"));
//根据价格属性,即第7列,按价格升序排列保证卖出队列价格低的在最前面
S_model->setSort(7,Qt::AscendingOrder);
}
第二步:
if(买的记录的股票代码==卖的记录的股票代码)
{
If(买的记录价格>=卖的记录的价格)
{
取出该价格的所有记录按照时间先后顺序排列
for(a=0;a<B_model->rowCount();a++)
{
B=a;//传出买入成功记录的序号
int B_Qty = B_model->record(a).value("Qty").toInt();
for( b=0;b<S_model->rowCount();b++)
{
S=b;//传出卖出成功记录的序号
int S_Qty = S_model->record(b).value("Qty").toInt();
if(买的数量<卖的数量)
{
向成交回报表新增两条记录,一条是买成功的记录,一条是卖成功的记录;
把委托数据库表中的卖队列数量更新,买队列的记录删除;
}
if(买的数量==卖的数量)
{
向成交回报表新增两条记录,一条是买成功的记录,一条是卖成功的记录;
把委托数据库表中的买卖队列的记录都删除;
}
if(买的数量>卖的数量)
{
向成交回报表新增两条记录,一条是买成功的记录,一条是卖成功的记录;
把委托数据库表中的买队列数量更新,卖队列的记录删除;
}
}
}
}
5.3 系统实现遇到问题及关键技术
5.3.1 QString的arg方法
在源码中很多地方需要用到Qstring的arg方法,可以解决很多问题:
- 在sql语句中使用变量
QString acc = ui->gddmEdit->text();
QString stock = ui->zqdmEdit->text();
// 在SQL语句中使用变量!!!
//求出买入的总数
QSqlQuery query1;
query1.exec(QString("select sum(Qty) from ashare_ordwth where acc=%1 and stock=%2 and bs=%3").arg(acc).arg(stock).arg("'B';"));
第二行代码中由于要查询的acc,stock,bs都是变量,使用arg函数后,就可以用arg后面的acc,stock和‘B’来替换,实现传参的sql查询。[1]
- 实现将‘1’变为‘B0001’这样的形式
QString的arg()方法用于填充字符串中的%1,%2...为给定的参数,如
QString m = tr("%1:%2:%3").arg("12").arg("60").arg("60"); // m = "12:60:60:
它还有另外一种重载方法:
QString QString::arg(int a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char( ' ' )) const
这个方法用于填充字符串中的%1,%2...为给定格式的整形数字,其中第一个参数是要填充的数字,第二个参数为最小宽度,第三个参数为进制,第四个参数为当原始数字长度不足最小宽度时用于填充的字符。
例如:
QString text = QString("%1:%2").arg(123, 5, 10, QChar('0')).arg(456, 5, 10, QChar('0')); // text = "00123:00456"[2]
- 实现将科学计数法转换为普通的输出格式
QString QString::arg(double a,int fieldWidth = 0,char format ='g',int precision = -1, QChar fillChar = QLatin1Char(' '))const
多了两个参数:format和precision,一个指明规格,一个指明精度。规格默认为 'g' 或 'G',指示后面的精度为整数和小数部分总和的长度;规格为'e'或 'E' 时,表示为科学记数法形式,精度部分指示的为小数部分的位数长度;
规格为f时,规格为其他字符时,无作用,输出原double数字。如:
doubled = 11.345689;
str = QString("delta: %1").arg(d, 0,'g',4);
//结果为:"delta: 11.35" ---这里进行了四舍五入
str = QString("delta: %1").arg(d, 0,'G',5);
//结果为:"delta: 11.346" ---这里进行了四舍五入,也就是format为g或者G结果是一样的
str = QString("delta: %1").arg(d, 0,'e',4);
//结果为:"delta: 1.2346e+01"
str = QString("delta: %1").arg(d, 0,'E',4);
//结果为:"delta: 1.2346E+01" --当format为e或者E时,精度表示的是小数点后的位数
str = QString("delta: %1").arg(d, 0,'f',4);
//结果为:"delta: 11.3457" --四舍五入
str = QString("delta: %1").arg(d, 0,'r',4);
//结果为:"delta: 11.3457"
str = QString("delta: %1").arg(d, 0,'Q',4);
//结果为:"delta: 11.3457" --当format为f或者其他字符时,以原格式输出,而且精度表示小数点后的位数,而且采取四舍五入[4]
5.3.2 QMultiMap的用法
Map是单值类型的,也就是说,如果一个新的值分配给一个已存在的键,则旧值会被覆盖。如果你需要让一个key可以索引多个值,可以使用QMultiMap<K, T>。这个类允许一个key索引多个value,如:
QMultiMap<int, QString> multiMap;
multiMap.insert(1, "one");
multiMap.insert(1, "eins");
multiMap.insert(1, "uno");
QList<QString> vals = multiMap.values(1)
主要是对value和values的理解:
详情我是参考了博客:http://devbean.blog.51cto.com/448512/248373/的介绍。[4]
5.3.3 Qcustomplot绘图控件的使用
我使用这个控件主要是想利用他来画K线图,但是我研究了这个控件后,知道了里面有一个已经实现了的方法是专门画K线图的,叫作qcpfinancial,我看了这个类里面的所有方法,当看到蜡烛图和ohcl时,很兴奋,但是在我准备把自己的数据传入,希望用这个类画出我想要的图时,发现并不是我要的效果,在很长一段时间里,我不断的看这个类里方法的说明。以为我是用错了。里面的setdata()方法,我知道怎么传值。最后我还是没能画出来。于是我不得不自己写方法去画K线图。
答辩完后,我尝试着翻墙去寻找这个类的用法,我相信一定是我哪里代码写的有问题。终于在我放弃使用这个类,准备回公司去问前辈的,我想我应该学习一下另外一个绘图空间QWT,在这个控件里我也研究了它专门用来画金融行业图像的类。终于我观察代码,发现了我不能画出正确图形的原因,是因为我没有把样式设置为蜡烛图,而默认的画图样式是另外一种叫作bar的图形,也许只是因为我对股票图形的了解不多,如果我知道还有这种图像的时候,我肯定会知道我只是设置错了图形样式。