`
mmdev
  • 浏览: 12950875 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

QT显示机制

 
阅读更多

了解QT显示机制,最重要的就是要了解QT是如何管理窗体的显示区域的,这里有个重要的类:QRegion, 在QT中可以通过QRegion定义一个窗体的显示区域,也可以通过QRegion定义窗体的可修改区域,比如在QPainter()中通过QPainter::setClipRect设定一个区域,我们绘图则只能在这个区域,此区域外绘图都是无效的。通过QRegion可以作一系列的逻辑运算,如两个区域相加,相减等。QRegion定义的区域不一定是连续的,但一定是由封闭的区域组成的,我们常会碰到一个窗体的显示区域被其他窗体分割为几块的情况。QT对这些显示区域的管理,类似于对窗体的管理,也是通过服务器与客户端的方式。参照以前的说法Server表示为全局的Global ,客户端为本地得Local。那么WindowsServer管理一个全局的显示区域即所有的Top-Level widget显示区域。而其他的child windget 的管理则在每一个QT应用程序中由QWSRegionManager管理,Top_Level widget 显示区域也会加载在其中,这个不难理解,因为Server只是负责将窗体事件发送到客户端,具体处理还是由客户端来操作。具体的流程还是来看代码吧。

显示区域管理者QWSRegionManager的初始化
服务器:
通过调用openDisplay()。
客户端:
在QWSDisplayData类的构造函数中通过调用QWSDisplayData::init()完成。

考虑一个比较简单的情况,我们要显示的widget 是一个Top_Leverl widget。在调用Show()函数中,这个widget将通过showWindows()向服务器请求做三件事:(以下窗体是指在global windows statck 中的TOP_Level widget)
1:调用QWSDisplay::requestRegion向服务器请求窗体显示区域。
2:调用QWSDdisplay::setAltitude向服务器请求设置窗体的优先级。此优先级是指在windows statck中的位置,而不是指QWSWidow 中的窗体优先级属性。Windows statck 中的第一个窗体就是显示在LCD上最前面的窗体。
3:调用QWSDisplay::requestFocus 向服务器请求设置窗体为焦点窗体。焦点窗体能接收Key, Mouse 事件,但不是所有的焦点窗体都能接收Key,Mouse 事件,如果有窗体设置为GrabKey 或则GrabMouse 则Key, Mouse 事件将分别传递至此窗体。
下面将通过代码分析winddows Server对这三个请求的处理过程:
一: QWSDisplay::requestRegion的处理
void QWSServer::invokeRegion( QWSRegionCommand *cmd, QWSClient *client )
{
................
QRegion region;
region.setRects(cmd->rectangles, cmd->simpleData.nrectangles);
if ( !region.isEmpty() )
changingw->setNeedAck( TRUE );
bool isShow = !changingw->isVisible() && !region.isEmpty();
setWindowRegion( changingw, region ); //***设置窗体显示区域
syncRegions( changingw ); //***通知客户端
刷新显示区域
if ( isShow )
emit windowEvent( changingw, Show );
if ( !region.isEmpty() )
emit windowEvent( changingw, Geometry );
else
emit windowEvent( changingw, Hide );
if ( focusw == changingw && region.isEmpty() )
setFocus(changingw,FALSE);
.................
}
invokeRegion调用setWindowRegion设置窗体显示区域,调用syncRegions通知客户端 刷新显示区域,并产生一些窗体事件如:Show, Geometry,Hide 。
setWindowRegion函数的实现如下:
QRegion QWSServer::setWindowRegion( QWSWindow* changingw, QRegion r )
{
QRegion exposed;
if (changingw) {
changingw->requested_region = r;
r = r - serverRegion; //exposed不为空则有显示区域被释放
exposed = changingw->allocation() - r; //低等级窗体增加可见区域
} else {
exposed = serverRegion-r;
serverRegion = r;
}
QRegion extra_allocation;
int windex = -1;

bool deeper = changingw == 0;
for (uint i=0; i<windows.count(); i++) {
QWSWindow* w = windows.at(i);
if ( w == changingw ) {
windex = i;
extra_allocation = r - w->allocation(); //如果extra_allocation不为空
deeper = TRUE; //需要增加新的新的显示区域
} else if ( deeper ) {
w->removeAllocation(rgnMan, r);//低优先级窗体去掉被覆盖的区域
r -= w->allocation();//如果r为空 则更低优先级的窗体被完全覆盖
} else { //如果窗体是第一次调用Show 直接走这
//higher windows
r -= w->allocation();//如果r为空 则窗体被高优先级窗体完全覆盖
}
if ( r.isEmpty() ) { //窗体被完全覆盖
break; // Nothing left for deeper windows
}
}
...................
if ( changingw && !changingw->requested_region.isEmpty() )
changingw->addAllocation( rgnMan, extra_allocation & screenRegion );
//为changingw窗体增加新的可见区域 置modifed标志为TRUE
else if ( !disablePainting )
paintServerRegion();

exposeRegion( exposed, windex+1 );//增加低级窗体可见区域。
return exposed;
}
注:增加新的显示区域不一定是整个显示区域的面积增大了,而是显示区域的块变多了。 一个显示区域可能由多个不连续和连续的Region组成。

void QWSServer::exposeRegion( QRegion r, int start )
{
r &= screenRegion;
for (uint i=start; i<windows.count(); i++) {
if ( r.isEmpty() ) //可见区域为空
break; // Nothing left for deeper windows
QWSWindow* w = windows.at(i);
w->addAllocation( rgnMan, r ); //增加新的可见区域 置modifed标志为TRUE
r -= w->allocation(); //r 更低级窗体可见区域
}
dirtyBackground |= r; //得到需要刷新的背景区域 如果r为空 则新增区域为0
}
exposeRegion为低等级窗体增加可见区域。

syncRegions:此函数主要是向客户端发送RegionModified事件,真正的绘图也是由客户端来完成。 还是通过代码来分析:
void QWSServer::syncRegions( QWSWindow *active )
{
rgnMan->commit(); //拷贝数据到一段共享内存,服务器为读写权限,客户端为只读
notifyModified( active );//通过客户端显示区域已更改,客户端绘制相关区域
paintBackground( dirtyBackground );//绘制背景区域修改部分。
dirtyBackground = QRegion();
}

void QWSServer::notifyModified( QWSWindow *active )
{
// notify active window first
if ( active )
active->updateAllocation(); //首先通知active 窗体
// now the rest //通知所有modified标志为TRUE的窗体
for (uint i=0; i<windows.count(); i++) {
QWSWindow* w = windows.at(i);
w->updateAllocation();
}
}
void QWSWindow::updateAllocation()
{
if ( modified || needAck) {
c->sendRegionModifyEvent( id, exposed, needAck ); // 发送消息
exposed = QRegion(); //复位低级窗体新增显示区域
modified = FALSE; //modified为真表示窗体的显示区域被修改。
needAck = FALSE;
}
}

客户端对RegionModifyEvent的处理。
客户端接收到消息后会调用translateRegionModifiedEvent函数来进行处理
bool QETWidget::translateRegionModifiedEvent( const QWSRegionModifiedEvent *event )
{
QWSRegionManager *rgnMan = qt_fbdpy->regionManager();
if ( alloc_region_index < 0 ) {
alloc_region_index = rgnMan->find( winId() ); //从共享内存中得到region索引
if ( alloc_region_index < 0 ) {
return FALSE;
}
}
QWSDisplay::grab();
int revision = *rgnMan->revision( alloc_region_index );
if ( revision != alloc_region_revision ) {
alloc_region_revision = revision;
QRegion newRegion = rgnMan->region( alloc_region_index );//得到显示区域
QWSDisplay::ungrab();
alloc_region = newRegion;

// set children's allocated region dirty
................
} else {
QWSDisplay::ungrab();
}
if ( event->simpleData.nrectangles )
{ // alloc_region >= exposed
QRegion exposed; //需要刷新区域的大小
exposed.setRects( event->rectangles, event->simpleData.nrectangles );
QSize s( qt_screen->deviceWidth(), qt_screen->deviceHeight() );
exposed = qt_screen->mapFromDevice( exposed, s );
qwsUpdateActivePainters();
repaintDecoration( exposed, FALSE );//绘制窗体的一些修饰如边框,caption等
repaintHierarchy( exposed, FALSE ); //绘制窗体显示区域及子窗体通过发送
} //PaintEvent事件到各窗体
qws_regionRequest = FALSE;
return TRUE;
}
repaintHierarchy函数中所有需要刷新的子窗体都会收到Paint事件。在Paint事件中,开始绘图。显示中只刷新exposed这个区域而不是将分配的区域alloc_region 全部刷新一次,这样做可以提高效率。

二:QWSDdisplay::setAltitude 的处理
invokeSetAltitude(const QWSChangeAltitudeCommand *cmd,
QWSClient *client)
{
int winId = cmd->simpleData.windowid;
int alt = cmd->simpleData.altitude;
bool fixed = cmd->simpleData.fixed;
...................
QWSWindow* changingw = findWindow(winId, 0);
...................
changingw->setNeedAck( TRUE );
if ( fixed && alt >= 1) {
changingw->onTop = TRUE;
}
if ( alt < 0 )
lowerWindow( changingw, alt ); //窗体优先级下降
else
raiseWindow( changingw, alt ); // 提升窗体优先级
if ( !changingw->forClient(client) ) {
refresh();
}
}
invokeSetAltitude通过调用lowerWindow,raiseWindow来调整窗体的优先级,如果一个Widget被显示,即调用Show此时alt == 0; 如果alt == 1则此窗体应该为最上层,如果alt == 2则窗体位FULL-SCREEN即全屏显示的窗体,可以通过setWFlags(WStyle_StaysOnTop) 来设定这个属性。 优先级较高的窗体将被优先显示, 在没有显式通过SetRegionPriority命令来改变窗体优先级的话,在Windows Stack中窗体将按照后进的优先级较高为原则。 可以参考 insertPrioritizedWindow函数,在qt-embedded-free-3.3.6 可能没有这个函数,因为在这个版本中不存在窗体优先级,除了WStyle_StaysOnTop属性的窗体为第一级优先级外,其他窗体都按照后进的优先为原则。
三:QWSDisplay::requestFocus 的处理请参考invokeSetFocus函数。

分享到:
评论

相关推荐

    QT的显示机制

    QT的显示机制,可以看看,比较不错 QT的显示机制,可以看看,比较不错 QT的显示机制,可以看看,比较不错

    QT实现信号与槽机制

    用Qt实现信号与槽机制,未使用ui实现窗口的变换和显示。

    基于QT实现串口数据收发及多路数据动态显示

    QT5.7开发,基于QSerialport、QChart实现串口数据的接收、发送,并动态显示数据。 采用信号与槽机制实现。

    QT登陆验证机制并显示数据库内容源码

    QT登陆验证机制,并显示数据库内容 代码详见源文件 注册验证为:验证用户名是否已存在、两次输入密码是否相同,满足则注册成功。 修改密码验证为:验证用户名是否存在,新密码是否与旧密码不同。 登陆验证为:验证...

    基于QT的视频显示程序

    代码功能:通过TCP网络通信实现图像数据的接收,进而将其进行绘制于UI上显示,实现实时视频的播放效果。代码框架利用了QT的多线程机制,解决图像显示的卡顿问题。

    QT多线程实现图片以缩略图形式显示图片 .tar

    自己写的一个简单多线程,可以参考下,应该对多线程同步有用,与普通的重写run函数有不同,重点是理解QT信号的几个同步机制。

    Qt5.9C++开发指南 源码 资源.zip

    本书以Qt 5.9 LTS版本为开发平台,详细介绍了Qt C++开发应用程序的技术,包括Qt应用程序的基本架构、信号与槽工作机制、图形显示的Graphics/View架构、数据编辑和显示的Model/View架构、对话框和多窗口的设计与调用...

    qt必备学习手册初级

    5 Qt消息机制和事件 50 5.1 事件 50 5.2 event() 52 5.3 事件过滤器 55 5.4 总结 59 5.5 不规则窗体 62 6 绘图和绘图设备 63 6.1 QPainter 63 6.2 绘图设备 65 6.2.1 QPixmap、QBitmap、QImage 66 6.2.2 QPicture ...

    qt编程 qt 国际化

    Qt 使用了自己定义的Locale机制,在编码支持和信息文件(Message File)的翻译上... Qt 的这种机制可以使 Qt 的同一 组件(QWidget)上同时显示不同编码的文本。 比如,Qt 的标签上可以同时使用中文简体 和中文繁体文本。

    Qt线程间通信,线程控制界面显示

    自己写的在线程内使用信号与槽机制,控制界面的显示。会一点点Qt的人都能看懂。

    QT编写的简易安防视频监控系统

    15:QT4与QT5均可编译通过 亲测无误 "&gt;说明: 1:此示例只是用来显示视频流 并没有处理存储视频及回放视频功能 2:在打开项目后务必将构建里面的影子构建 Shadow build 取消 3:实时显示视频 视频响应速度比VLC QTAV等...

    王维波《Qt5.9 C++开发指南》(配套资源)

    该书以Qt 5.9 LTS版本为开发平台,详细介绍了包括Qt应用程序的基本架构、信号与槽工作机制、 图形显示的Graphics/View架构、数据编辑和显示的Model/View架构、对话框和多窗口的设计与调用方法等技术;也介绍了常用...

    精通qt4编程(源代码)

    \初级篇 第1章 Qt初步实践 卢传富 建立了第一个较简单的Qt应用程序,在GUI用户界面中显示一行中文。 2 \ 第2章 对话框 \——QDialog 卢传富介绍了Qt的对话框类QDialog,实现了一个自定义的登录对话框,举例说明了Qt...

    基于QT程序设计的多人聊天室

    在界面跳转方面,通过QT独有的信号和槽机制,进行设计,此项目主要在登录界面和消息交互界面设计了界面的跳转。至于客户端和服务端的搭建,是本项目主要需要实现的地方,通过ip地址和端口号,进行,各个客户端之间的...

    精通Qt4编程(第二版)源代码

    \初级篇 第1章 Qt初步实践 卢传富 建立了第一个较简单的Qt应用程序,在GUI用户界面中显示一行中文。 2 \ 第2章 对话框 \——QDialog 卢传富介绍了Qt的对话框类QDialog,实现了一个自定义的登录对话框,举例说明了...

    QT5图形与图画

    关于QT5自带绘图功能的一些精讲和实例 1,QT基础图形绘制 2,QT5双缓冲机制 3,QT5 SVG格式图片的显示

    Qt小实例 C++资源

    使用Qt Creator,用C++语言写了一个小实例,第一次用,工程名还是helloworld,但是具有了一个界面,实现显示框数据随slider控件变化的功能,对于初学者有助于理解Qt的机制。

    通过Qt界面控制步进电机的启停

    1,在QT程序中,新建一件,再添加一个用于操作硬件的新方法,如controlMachine,建立按钮与con个属于你自己的类,如Widget用于显示。 2,在你的类中添加按钮控trolMachine函数之间的信号与槽机制(使用connect函数)...

Global site tag (gtag.js) - Google Analytics