最近考虑开发一款兵棋软件,名字都想好了,叫犀牛兵棋,打算支持四边形地图和六边形地图。
前者比较好说,后者在根据屏幕坐标计算格子坐标的时候,稍微有点麻烦。
先说下我们的坐标系是x轴向右,y轴向上,原点在左下角。
格子地图坐标如下
根据格子坐标计算出对应世界坐标系的函数如下
QPointF GridCell6Manager::getWorldPosByCellCoordinate(int x,int y)
{
if (x % 2 == 0)
return QPointF(1.5f*res*(x+1),
(0.5*R3+R3*y)*res);
return QPointF(1.5f*res*(x + 1),
(R3 + y * R3)*res);
}
QPoint GridCell6Manager::getCellCoordinateByWorldPos(int x,int y)
{
QPoint point(-1,-1);
float xpos = x-res*0.5f;
float ypos = y/(R3*res) - 0.5f;
int yset[2] = {std::floorf(ypos),std::ceilf(ypos)};
xpos /= (1.5*World::getInstance().getWorldResolution());
int xset[2] = { std::floorf(xpos),std::ceilf(xpos)};
auto p00 = getWorldPosByCellCoordinate(xset[0],yset[0]);
auto p01 = getWorldPosByCellCoordinate(xset[0],yset[1]);
auto p10 = getWorldPosByCellCoordinate(xset[1],yset[0]);
auto p11 = getWorldPosByCellCoordinate(xset[1],yset[1]);
float d00 = distance2<float>(x,y,p00.x(),p00.y());
float d01 = distance2<float>(x,y,p01.x(),p01.y());
float d10 = distance2<float>(x,y,p10.x(),p10.y());
float d11 = distance2<float>(x,y,p11.x(),p11.y());
int i,j;
if(d00 < d01 && d00 < d10 && d00 < d11)
{
i = xset[0];
j = yset[0];
}
else if(d00 > d01 && d01 < d10 && d01 < d11)
{
i = xset[0];
j = yset[1];
}
else if(d10 < d00 && d10 < d01 && d10 < d11)
{
i = xset[1];
j = yset[0];
}
else
{
i = xset[1];
j = yset[1];
}
return QPoint(i,j);
}
其中res为格子边长,R3为sqrt(3)常量
在这个基础上就可以计算从世界坐标到格子坐标的转换了
#include <Windows.h>
#include <wininet.h>
#include <stdio.h>
#include <string>
#include <io.h>
using namespace std;
#pragma comment(lib, "wininet.lib")
const DWORD DWORD_MAX_CCH_OF_TEST_URL = 256;
const DWORD DWORD_MAX_CCH_OF_HOST_NAME = 128;
const DWORD DWORD_MAX_CCH_OF_URL_PATH = 256;
int breakpointDownload(const std::wstring& url, const std::wstring& folder, void(*cb)(double),std::wstring& name)
{
int index = url.find_last_of(L'/');
std::wstring filename = url.substr(index + 1);
index = filename.find_first_of(L'?');
if (index != std::wstring::npos)
filename = filename.substr(0,index);
if (!folder.empty())
filename = folder + L"\\" + filename;
std::wstring tempfile = filename + L".dl";
_wremove(filename.c_str());
HINTERNET hInetOpen = NULL;
HINTERNET hInetConnect = NULL;
HINTERNET hInetRequest = NULL;
HANDLE lhFile = NULL;
URL_COMPONENTS ldCrackedURL;
ZeroMemory(&ldCrackedURL, sizeof(URL_COMPONENTS));
ldCrackedURL.dwStructSize = sizeof(URL_COMPONENTS);
TCHAR szHostName[DWORD_MAX_CCH_OF_HOST_NAME] = { 0 };
ldCrackedURL.lpszHostName = szHostName;
ldCrackedURL.dwHostNameLength = DWORD_MAX_CCH_OF_HOST_NAME;
wchar_t szUrlPath[DWORD_MAX_CCH_OF_URL_PATH] = { 0 };
ldCrackedURL.lpszUrlPath = szUrlPath;
ldCrackedURL.dwUrlPathLength = DWORD_MAX_CCH_OF_URL_PATH;
if (FALSE == InternetCrackUrl(url.c_str(),url.size(), 0, &ldCrackedURL))
{
return 0;
}
hInetOpen = InternetOpen(L"MSIE/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (NULL == hInetOpen)
{
return 0;
}
hInetConnect = InternetConnect(hInetOpen, ldCrackedURL.lpszHostName, ldCrackedURL.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL == hInetConnect)
{
return 0;
}
lhFile = CreateFile(tempfile.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (lhFile == INVALID_HANDLE_VALUE)
{
return 0;
}
LARGE_INTEGER ldFileSize;
if (FALSE == GetFileSizeEx(lhFile, &ldFileSize))
{
return 0;
}
LONGLONG lllStartPos = 0;
if(0 == ldFileSize.QuadPart)
{
}
else
{
if (INVALID_SET_FILE_POINTER == SetFilePointer(lhFile, 0, NULL, FILE_END))
{
return 0;
}
lllStartPos = ldFileSize.QuadPart;
}
wchar_t lscRangeStartPosition[30] = { 0 };
if (0 != _i64tow_s((__int64)(lllStartPos), lscRangeStartPosition, sizeof(lscRangeStartPosition), 10))
{
return 0;
}
wstring loAdditionalHeader = L"Range: bytes=";
loAdditionalHeader += lscRangeStartPosition;
loAdditionalHeader += L"-\r\n";
const wchar_t* lplpszAcceptTypes[] = { L"*/*", NULL };
hInetRequest = HttpOpenRequest(hInetConnect,L"GET", ldCrackedURL.lpszUrlPath,L"HTTP/1.1", NULL,lplpszAcceptTypes, 0, 0);
if (NULL == hInetConnect)
{
return 0;
}
if (FALSE == HttpSendRequest(hInetRequest, loAdditionalHeader.c_str(), loAdditionalHeader.size(), NULL, 0))
{
return 0;
}
DWORD ldwStatusCode;
DWORD ldwCbOfStatusCode = sizeof(ldwStatusCode);
if (FALSE == HttpQueryInfo(hInetRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &ldwStatusCode, &ldwCbOfStatusCode, 0))
{
return 0;
}
if (416 == ldwStatusCode)
{
_wrename(tempfile.c_str(), filename.c_str());
name = filename;
return 1;
}
else if (200 != ldwStatusCode && 206 != ldwStatusCode)
{
return 0;
}
DWORD dwFile = 10000;
DWORD dwSize = sizeof(DWORD);
if (FALSE == HttpQueryInfo(hInetRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwFile, &dwSize, 0))
{
}
else
dwFile += lllStartPos;
BYTE lpbBufferToReceiveData[2048];
DWORD ldwCbBuffer = 2048;
DWORD ldwCrtCbReaded;
DWORD ldwCbWritten = 0;
bool lbIsOk = false;
LONGLONG lllCbAllRead = lllStartPos;
do
{
if (FALSE == InternetReadFile(hInetRequest, lpbBufferToReceiveData, ldwCbBuffer, &ldwCrtCbReaded))
{
break;
}
if (ldwCrtCbReaded == 0)
{
break;
}
if (FALSE == WriteFile(lhFile, lpbBufferToReceiveData, ldwCrtCbReaded, &ldwCbWritten, NULL) || ldwCbWritten != ldwCrtCbReaded)
{
break;
}
ZeroMemory(lpbBufferToReceiveData, ldwCrtCbReaded);
lllCbAllRead += ldwCrtCbReaded;
double p = lllCbAllRead * 100.0 / dwFile;
if (p > 100)
p = 100;
if (cb)
cb(p);
} while (true);
if (NULL != lhFile)
{
CloseHandle(lhFile);
}
if (NULL != hInetRequest)
{
InternetCloseHandle(hInetRequest);
}
if (NULL != hInetConnect)
{
InternetCloseHandle(hInetConnect);
}
if (NULL != hInetOpen)
{
InternetCloseHandle(hInetOpen);
}
_wrename(tempfile.c_str(), filename.c_str());
name = filename;
return 1;
}
使用Qt开发的,具体涉及QNetwork/Qjson/QChart等各个Qt模块
软件支持日线,分时,周线,月线等不同周期的混合量化分析;支持选股和回测二个模式;支持K线识别;支持常见的10多种技术指标;
同时还支持基于LEVEL2的资金流分析和查看。
为了方便使用,我还自行开发了一套脚本解释系统
一个macd金叉死叉的量化脚本如下:
#设置K线文件目录
config.source.k.dir=data
#设置分笔数据文件目录
config.source.ticket.dir=ticket
#设置level2文件路径
config.source.lv2.dir=lv2
#设置K线数据格式
config.source.k.format=default
#设置分时最大加载日期数
source.ticket.maxtickloaded=5
#设置小单最大额度
config.source.lv2.v1=5
#设置中单最大额度
config.source.lv2.v2=100
#设置大单最大额度,超过此数值则为超大单
config.source.lv2.v3=500
#定义单日股票买入排序,默认为成交量降序(可选volasc,increaseasc,increasedesc)
config.trade.buy.order=voldesc
#定义股票买入时机,默认为开盘(可选open/auto)
config.trade.buy.point=open
#定义股票卖出时机,默认为尾盘(可选第二天开盘价-早盘)
config.trade.sale.point=close
#是否使用立即止盈模式,达到设定盈利立刻卖出
config.trade.sale.rapid=yes
#设置单股最大持有日期
config.trade.max.hold.day=3
#设定单股买入后再次买入禁买日期间隔
config.trade.min.exclude=6
#设置止盈点
config.trade.max.profit=64.0
#设定止损点
config.trade.max.lost=-9.0
#设定交易成本(千分之.)
config.trade.tradecost=0.8
#设定单日最大可买股票数
config.trade.max.count=3
#设定股票买入最大允许涨幅
config.trade.max.allow.increase=3.2
#设定股票买入最大允许跌幅
config.trade.max.allow.decrease=-3.2
buy.macd.diff,0>macd.dea,0
buy.macd.diff,-1<macd.dea,-1
buy.macd.diff,0>value,0.0
buy.ohlc.increase,0>value,0.5
很容易理解吧
有兴趣可以在www.snail007.com下载使用
Libcefwenjianjia文件夹比较简单
分别是浏览器,基础类,渲染类以及打印输出(utility)相关
Chromium下的目录结构很多,可分为几类:编译相关,实验性工程相关,谷歌浏览器相关,专有库相关,代码相关
l Android_webview Android上的webview控件
l Apps Chrome程序相关
l Ash插件相关
l Base 提供公共的功能代码
l Blimp 支持裁剪Chrome的谷歌实验性项目
l Blink 没用
l Breakpad开源崩溃报告项目
l Build 构建配置
l BuildTools 同上
l Cc 谷歌合成器(chromium compositor)实现部分 涉及帧/层的渲染布局以及图形合成
l Cef Chrome的Cef封装
l Chrome 谷歌浏览器程序核心代码
l Chrome_elf 错误崩溃报告动态链接库实现
l ChromeCast Chrome广播相关
l ChromeOS
l Clound_Print 谷歌云打印相关
提供谷歌浏览器页面预览打印清单
l Components 浏览器基础组建目录和资源,比如关于界面资源和UI,Crash页面显示资源和界面等
l Content 多进程沙盒浏览器核心代码
l Courgetter 谷歌提供的二进制文件对比核心算法,在谷歌浏览器中用于比较不同版本的二进制差异
l Cryto 加密库
l Dbus 数据总线相关
l Device 提供辅助设备相关支持
,涉及蓝牙,电池,NFC,USB等
l Docs
l Extensions 一个可复用的模块,目前用于扩展Chrome浏览器
l Gin V8相关的便利类,提供字典,数字缓存等功能
l Google APIS
l Google update
l GPU 涉及blink,gl,ipc等
l Headless提供无头浏览器模式
– 用于爬虫,自动化测试等
l Infra 未知
l IOS IOS系统相关
l IPC 跨进程通信相关
l Jingle P2P传输库
l Mandoline 一个基于Mojo脚本构建Chrome的实验性库
l Mash ?
l Media Chrome的多媒体模块,支持音频播放和录音等功能
l Mojo 支持多类型的沙盒内容
l Native Client /Natice Client SDK支持在浏览器中执行多脚本语言而不限于js
l Net 网络功能库
l Pdf PDF格式相关
l PPAPI Chrome扩展插件框架
l Printing 打印相关
l Remoting 远程控制和调试相关
l Rlz库 用于统计软件产品分发和市场使用统计相关
l SandBox 沙盒
l Sdch 一种压缩格式
l Skia Skia图像库目前用于Chrome和Android
l Sql sqlite封装库
l Storage 数据储存
l StyleGuide Chrome 代码风格指南
l Sync Chrome账号多数据同步
l Testing
l Third party 第三方库集合
l Tools Chrome工具集
l UI Chrome UI库
l URL 网页链接解析相关
l V8 V8 js库
l Win8 在windows上使chrome以metro模式展现
目前使用Cef框架的软件很多,除了我们的程序,还有网易云音乐,StartUML,通信达等都基于Cef框架。阅读Cef/Chrome底层代码有助于了解他的设计架构和细节,可以帮助我们解决一些Cef框架层面的故障,同时可以学习他的编程思想和框架结构提高编程能力。本文主要介绍Cef3和Chromium,涉及Cef3/Chromium编译,代码目录结构和具体功能实现细节,会根据需要不断完善。需要指出的是Cef3/Chrome版本之间代码框架,文件位置变动很多,如无特殊说明,本文以2623分支为基准。.
一 Cef3/Chromium的编译和音视频支持的修改
先说一点,国内从官网下载源码网络很不稳定,这里以别人下载好的cef2623版本来编译
网盘地址: https://pan.baidu.com/s/1jHY4hls
编译先决条件:win64系统,安装python2.7 Virtual Studio2013 硬盘空间大于54G以上
下载完成后解压 这里解压到D盘下的2623目录
打开CMD窗口 执行以下操作以设定环境变量
Set DEPOT_TOOLS_WIN_TOOLCHAIN=0
Set CEF_USE_GN=0
Set GYP_MSVS_VERSION=2013
Set GYP_GENERATORS=ninja,msvs-ninja
然后执行
python automate-git.py --download-dir=d:\cef3\source --branch=2623 --no-update --build-log-file --verbose-build --force-distrib --force-build
大致等待5个小时即可编译完成
注意,指定—no-update 不更新代码;如果不需要编译debug版本,则需要指定
—no-debug-build
输出目录在src\cef\binary_distrib下
Cefclient.exe为demo程序,输入www.html5test.com可查看支持音视频的情况
当前编译好的2623对音视频的支持如下:
音视频的支持有2处需要修改分别是
1是在source/chromium/src/cef/cef.gypi文件 在variables节点下增加
'proprietary_codecs': 1,
'ffmpeg_branding': 'Chrome',
2是修改二者
source\chromium\src\third_party\ffmpeg\chromium\config\Chrome\win\ia32\config.h
source\chromium\src\third_party\ffmpeg\chromium\config\Chrome\win\x64\config.h
在宏FFMPEG_CONFIGURATION 中增加
–enable-decoder=’rv10,rv20,rv30,rv40,cook,h263,h263i,mpeg4,msmpeg4v1,msmpeg4v2,msmpeg4v3,amrnb,amrwb,ac3,flv’
–enable-demuxer=’rm,mpegvideo,avi,avisynth,h263,aac,amr,ac3,flv,mpegts,mpegtsraw’
–enable-parser=’mpegvideo,rv30,rv40,h263,mpeg4video,ac3
可以根据需要修改要支持的音视频情况
def psar(barsdata, iaf = 0.02, maxaf = 0.2):
length = len(barsdata)
dates = list(barsdata['Date'])
high = list(barsdata['High'])
low = list(barsdata['Low'])
close = list(barsdata['Close'])
psar = close[0:len(close)]
psarbull = [None] * length
psarbear = [None] * length
bull = True
af = iaf
ep = low[0]
hp = high[0]
lp = low[0]
for i in range(2,length):
if bull:
psar[i] = psar[i - 1] + af * (hp - psar[i - 1])
else:
psar[i] = psar[i - 1] + af * (lp - psar[i - 1])
reverse = False
if bull:
if low[i] < psar[i]:
bull = False
reverse = True
psar[i] = hp
lp = low[i]
af = iaf
else:
if high[i] > psar[i]:
bull = True
reverse = True
psar[i] = lp
hp = high[i]
af = iaf
if not reverse:
if bull:
if high[i] > hp:
hp = high[i]
af = min(af + iaf, maxaf)
if low[i - 1] < psar[i]:
psar[i] = low[i - 1]
if low[i - 2] < psar[i]:
psar[i] = low[i - 2]
else:
if low[i] < lp:
lp = low[i]
af = min(af + iaf, maxaf)
if high[i - 1] > psar[i]:
psar[i] = high[i - 1]
if high[i - 2] > psar[i]:
psar[i] = high[i - 2]
if bull:
psarbull[i] = psar[i]
else:
psarbear[i] = psar[i]
return {"dates":dates, "high":high, "low":low, "close":close, "psar":psar, "psarbear":psarbear, "psarbull":psarbull}
这段代码有点问题 需要修改下才能使用
生成的dmp文件提示错误
ExceptionAddress: 7c812fd3 (kernel32+0x00012fd3)
ExceptionCode: c06d007f
ExceptionFlags: 00000000
NumberParameters: 1
Parameter[0]: 0012f7b0
执行 dds 0012f7b0
显示:
0:000> dds 0012f7b0
0012f7b0 00000024
0012f7b4 038d96d4 libcef!_DELAY_IMPORT_DESCRIPTOR_dbghelp_dll
0012f7b8 039121b4 libcef!_imp__SymGetSearchPathW
0012f7bc 03678f30 libcef!_sz_dbghelp_dll
0012f7c0 00000001
0012f7c4 038d9de6 libcef!dxva2_NULL_THUNK_DATA_DLN+0x7e
0012f7c8 68d60000
DBGENG: dbghelp.dll - Partial symbol image load missing image info
DBGHELP: Module is not fully loaded into memory.
DBGHELP: Searching for symbols using debugger-provided data.
DBGHELP: e:\workspace\codes\pc2.0\build\release\dbghelp.pdb - file not found
DBGHELP: e:\workspace\codes\pc2.0\build\release\dll\dbghelp.pdb - file not found
DBGHELP: e:\workspace\codes\pc2.0\build\release\symbols\dll\dbghelp.pdb - file not found
DBGHELP: d:\2623\source\chromium\src\out\release\dbghelp.pdb - file not found
DBGHELP: d:\2623\source\chromium\src\out\release\dll\dbghelp.pdb - file not found
DBGHELP: d:\2623\source\chromium\src\out\release\symbols\dll\dbghelp.pdb - file not found
DBGHELP: dbghelp.pdb - file not found
*** WARNING: Unable to verify timestamp for dbghelp.dll
*** ERROR: Module load completed but symbols could not be loaded for dbghelp.dll
DBGHELP: dbghelp - no symbols loaded
dbghelp
0012f7cc 00000000
0012f7d0 0000007f
0012f7d4 038db314 libcef!dxva2_NULL_THUNK_DATA_DLN+0x15ac
0012f7d8 00000003
0012f7dc 00000000
0012f7e0 0012f890
0012f7e4 0233264b libcef!_tailMerge_dbghelp_dll+0xd
0012f7e8 0012f7b0
0012f7ec 039121b4 libcef!_imp__SymGetSearchPathW
0012f7f0 00000008
0012f7f4 7c9301db ntdll+0x101db
0012f7f8 00642f9e libcef!base::debug::`anonymous namespace'::InitializeSymbols+0x9e [d:\2623_\source\chromium\src\base\debug\stack_trace_win.cc @ 80]
0012f7fc ffffffff
0012f800 0017dbe0
0012f804 00000400
0012f808 00000006
0012f80c 00000000
0012f810 00000000
0012f814 00000000
0012f818 09193a78
0012f81c 0000037b
0012f820 00000128
0012f824 00000001
0012f828 77d193e9
为
SymGetSearchPathW函数找不到所致,文件为dbghelp.dll
使用更新后的dbghelp.dll替换后正常
这里以别人下载好的cef2623版本来编译(默认支持mp3/h64)
网盘地址: https://pan.baidu.com/s/1jHY4hls
编译先决条件:win64系统,安装python2.7 Virtual Studio2013 硬盘空间大于54G以上
下载完成后解压这里解压到D盘下的2623目录
打开CMD窗口执行以下操作以设定环境变量
Set
DEPOT_TOOLS_WIN_TOOLCHAIN=0
Set
CEF_USE_GN=0
Set
GYP_MSVS_VERSION=2013
Set GYP_GENERATORS=ninja,msvs-ninja
然后执行
python
automate-git.py --download-dir=e:\cef3\source --branch=2623 --no-update
--build-log-file --verbose-build --force-distrib --force-build
大致等待5个小时即可编译完成
注意,这个指定—no-update 不更新代码,如果不需要编译debug版本,则需要指定
—no-debug-build
输出目录在src\cef\binary_distrib下
Cefclient.exe为demo程序,点击并输入www.html5test.com可查看支持音视频的情况
当前编译好的2623对音视频的支持如下:
音视频的支持有2处需要修改分别是
1是在source/chromium/src/cef/cef.gypi文件在variables节点下增加
'proprietary_codecs': 1,'ffmpeg_branding': 'Chrome',
2是修改
source\chromium\src\third_party\ffmpeg\chromium\config\Chrome\win\ia32\config.h
和source\chromium\src\third_party\ffmpeg\chromium\config\Chrome\win\x64\config.h
在宏FFMPEG_CONFIGURATION 中增加
–enable-decoder=’rv10,rv20,rv30,rv40,cook,h263,h263i,mpeg4,msmpeg4v1,msmpeg4v2,msmpeg4v3,amrnb,amrwb,ac3,flv’
–enable-demuxer=’rm,mpegvideo,avi,avisynth,h263,aac,amr,ac3,flv,mpegts,mpegtsraw’
–enable-parser=’mpegvideo,rv30,rv40,h263,mpeg4video,ac3
可以根据需要修改要支持的音视频情况
摘要: QCustomPlot和QWt各有千秋前者偏轻,但是功能有点弱了,可以修改QCustomPlot增加Qwt的一些模块和类如下 代码为QComstomPlot使用QwtText的例子Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->class Q...
阅读全文
class HTMLLayer : public QCPLayerable
{
Q_OBJECT
public:
HTMLLayer(QCustomPlot* plot);
~HTMLLayer();
public:
QString layerName()const;
void setVisible(bool visible);
void setHTML(const QString& html);
void setPen(const QPen& pen);
void setFont(const QFont& font);
protected:
virtual void applyDefaultAntialiasingHint(QCPPainter* painter)const;
virtual void draw(QCPPainter* painter);
private:
QPen mPen;
QFont mFont;
QTextDocument mDocument;
};
HTMLLayer::HTMLLayer(QCustomPlot* plot):
QCPLayerable(plot)
{
}
void HTMLLayer::setHTML(const QString& html)
{
mDocument.setHtml(html);
}
HTMLLayer::~HTMLLayer()
{
}
QString HTMLLayer::layerName()const
{
return "HtmlLayer";
}
void HTMLLayer::setVisible(bool visible)
{
QCPLayer* layer = mParentPlot->layer(layerName());
if(layer)
{
layer->setVisible(visible);
}
}
void HTMLLayer::setPen(const QPen& pen)
{
mPen = pen;
}
void HTMLLayer::setFont(const QFont& font)
{
mFont = font;
}
void HTMLLayer::applyDefaultAntialiasingHint(QCPPainter* painter)const
{
}
void HTMLLayer::draw(QCPPainter* painter)
{
painter->save();
QRectF rect = mParentPlot->rect();
painter->setPen(mPen);
painter->setFont(mFont);
painter->setAntialiasing(true);
QwtPainter::drawSimpleRichText(painter,rect,Qt::AlignLeft | Qt::AlignTop,mDocument);
painter->restore();
}
void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect,
int flags, const QTextDocument &text )
{
QTextDocument *txt = text.clone();
painter->save();
painter->setFont( txt->defaultFont() );
qwtUnscaleFont( painter );
txt->setDefaultFont( painter->font() );
txt->setPageSize( QSizeF( rect.width(), QWIDGETSIZE_MAX ) );
QAbstractTextDocumentLayout* layout = txt->documentLayout();
const double height = layout->documentSize().height();
double y = rect.y();
if ( flags & Qt::AlignBottom )
y += ( rect.height() - height );
else if ( flags & Qt::AlignVCenter )
y += ( rect.height() - height ) / 2;
QAbstractTextDocumentLayout::PaintContext context;
context.palette.setColor( QPalette::Text, painter->pen().color() );
painter->translate( rect.x(), y );
layout->draw( painter, context );
painter->restore();
delete txt;
}