热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EssentialQt第十一章事件的运用

这一章将通过一个完成一个完成的程序,这个程序将会运用到多个事件。这个程序被命名为TitleWidget.在界面程序中,滚动播放一些文字非常常见ÿ
这一章将通过一个完成一个完成的程序,这个程序将会运用到多个事件。这个程序被命名为TitleWidget.在界面程序中,滚动播放一些文字非常常见,而这个程序的最用将是能滚动播放默认的字符或输入的文本,完成后大概是这个样子


其中的文字在从左到右不断的循环滚动播出。要实现这个程序,至少要用到3个事件,都是到目前尚未接触到的事件,先看程序头文件TitleWidget.h

#ifndef TITLEWIDGET_H__
#define TITLEWIDGET_H__
#include
#include
#include
#include
const QString DEFAULT_TITLE = "This is A TitleWidget For Test Event. ";//注释1
class TitleWidget:public QWidget
{private:int TextPoint;QString TextInfo;int TextTimeID;//注释2public:TitleWidget(QWidget*parent = 0);void setText(const QString& str );QString text()const;QSize sizeHint()const;//注释3protected:void showEvent(QShowEvent* event);void paintEvent(QPaintEvent* event);void timerEvent(QTimerEvent* event);//注释4
};
#endif


注释1: 对于这个程序来说,可以使用接下来的setText()函数来设置他滚动播放的内容,如果没有调用这个函数设置播放内容,则将会播放固定的文本
注释2: 变量TextPoint用于标记文本在窗体中的位置,在绘图中有重要作用,TextInfo为播放文本的内容,TextTimeID将用于标记一个定时器,这个定时器用于控制文本滚动的速度
注释3:这里用setText()函数和text()分别获得和返回播放文本的内容,而sizeHint()函数则用于根据文本内容来觉得窗体大小
注释4:这里将修改三个事件,分别对应显示事件,绘图事件和时间事件,这个窗体的主要功能依靠这三个时间实现

接下来是TitleWidget.cxx文件,在构造函数中将TextPoint和TextTimeID设为0,这两个值会在下面的事件函数中使用,而TextInfo则等于默认值DEFAULT_TITLE;

void TitleWidget::setText(const QString& str)
{TextInfo = str;update();//注释1updateGeometry();
}
QString TitleWidget::text()const
{return TextInfo;
}
QSize TitleWidget::sizeHint()const
{return fontMetrics().size(0,text());//注释2
}

注释1 :setText()函数设置滚动播放的文本,然后调用update()函数来强制刷新一次绘图事件,效果等同与窗体重新绘制一次,在Qt3以前版本,这样的操作会造成窗体的闪烁,需要做额外的处理,而从Qt4开始,则不会出现闪烁的情况,另一个函数updateGepmetry()则用于告诉窗体自身的布局管理器,窗体的形状已经改变了,布局管理器也需要做相应的改动。
注释2 :fontMetrics()用于返回一个QFontMetrics对象,这个对象包含了窗体部件字体相关的信息,这个了类的成员函数size()则返回文本的大小,这个QFontMetrics::size()第一个参数用于比特级的细节控制,对于这个例子来说,直接传值0即可,第二个参数为希望获得大小的文本,而上面已经实现了text()函数来获得程序滚动播放的文本内容

绘图事件实现

void TitleWidget::paintEvent(QPaintEvent* event)
{QPainter P(this); //注释1int TextWidth &#61; fontMetrics().width(text());//注释2if(TextWidth <1)return;int X &#61; - TextPoint; //注释3while(X }

注释1&#xff1a; QPainter是一个画笔&#xff0c;他作用是在他的父对象上画画&#xff0c;这里他的父对象是this,所以他的作用就是在窗体上画东西&#xff0c;要使用这个类需要包含头文件#include
注释2&#xff1a; 这里再次利用fontMetrics()函数的返回值来获得文本的大小信息&#xff0c;不过这里是获得文本的长度
注释3&#xff1a; 这里X是一个文本的起始位置&#xff0c;举例&#xff0c;窗体最左段的坐标为0,最初TextPoint的值为0,程序设定文本每个一段时间向左移动一个位置&#xff0c;而TextPoint用于标记文本移动的距离&#xff0c;假设文本向左移动了两次&#xff0c;则TextPoint的值为2,而文本起始的位置则为-2&#xff08;即向左移动了单位2&#xff09;&#xff0c;当然&#xff0c;从-2到0这段文本不会显示在窗体中
注释4 &#xff1a;这里调用了QPainter的成员函数来“画画”&#xff0c;这里画的是文本&#xff0c;

显示事件实现

void TitleWidget::showEvent(QShowEvent* event)
{TextTimeID &#61; startTimer(30);//注释1QWidget::showEvent(event);//注释2
}

注释1&#xff1a; 这个是窗体的显示事件函数&#xff0c;前面说过Qt窗体创建是默认是隐藏的&#xff0c;必须调用show()函数来显示&#xff0c;而调用show()函数就触发了这个显示时间&#xff0c;而在这个程序的显示事件中&#xff0c;需要添加一个功能&#xff0c;这个功能调用基类成员函数startTimer()来生产一个定时器&#xff0c;这个函数参数为定时器的时间间隔&#xff0c;单位为毫秒&#xff0c;例子中这个定时器在窗体显示的时候开始&#xff0c;每隔30毫秒就会触发一次窗体自身的时间事件&#xff0c;这个函数的返回值用于标记创建的定时器&#xff0c;Qt允许一个窗体有多个定时器&#xff0c;创建的时候将会用一个ID来标记&#xff0c;追踪他们
注释2&#xff1a; 由于只是添加功能&#xff0c;所以这里调用下基类的显示事件函数

时间事件实现

void TitleWidget::timerEvent(QTimerEvent* event)
{if(event->timerId() &#61;&#61; TextTimeID)//注释1{&#43;&#43;TextPoint;if(TextPoint >&#61; fontMetrics().width(text()))//注释2TextPoint &#61; 0;scroll(-1,0);//注释3}elseQWidget::timerEvent(event);//注释4
}

注释1&#xff1a; 在显示事件中&#xff0c;窗体在显示的时候会生成一个定时器&#xff0c;这个定实际每隔30毫秒就会触发一次时间事件&#xff0c;但操作系统也会触发事件时间&#xff0c;所以需要判断是否由显示事件中的那个定时器触发的&#xff0c;可以通过事件的timerId()函数返回触发这次事件的定时器ID来判断
注释2&#xff1a; 每隔一段时间&#xff08;程序中为30毫秒&#xff09;TextPoint会记录文本移动距离&#xff0c;当移动具体超过了文本长度&#xff0c;则重置为0,即文本向左移动了一个自身的距离&#xff0c;则可以视为没有移动
注释3&#xff1a; 这里使用了scroll()函数&#xff0c;是的文本向左移动一个像素&#xff0c;注意地一个参数是负代表向左移动&#xff0c;上文中采用update()函数来强制刷新一次绘图之间&#xff0c;而这里由于之需要改变文本位置&#xff0c;不需要改动&#xff08;重新绘制&#xff09;整个窗体。

然后程序编译运行后差不多是这个样子的

到这里实现了滚动播放文本的功能&#xff0c;此外还可以在添加一些功能&#xff0c;比如很多人希望有个暂停和继续滚动的动能&#xff0c;为了演示这个功能&#xff0c;可以添加一个槽来实现&#xff0c;为了程序能&#xff08;想用户演示&#xff09;控制空能&#xff0c;可以暂时使用鼠标左键点击来控制&#xff0c;滚动的状态下点击就暂停&#xff0c;暂停的状态下就滚动
为了实现这样的功能&#xff0c;需要在类中添加一个变量bool值来追踪窗体的滚动状态&#xff0c;在构造函数中设置TitleState &#61; true;因为窗体默认是滚动的&#xff0c;然后还需要修改下窗体的鼠标点击事件&#xff0c;舍得鼠标左键点击的时候会发射一个自定义的信号

void TitleWidget::mousePressEvent(QMouseEvent* event)
{if(event->button() &#61;&#61; Qt::LeftButton)emit LeftClick(); //注释1QWidget::mousePressEvent(event);
}

注释1&#xff1a; 这个信号在类中定义&#xff0c;用于和槽连接
然后是控制是否滚动的槽函数的实现

void TitleWidget::StopTitleRun()
{if(TitleState &#61;&#61; true){TitleState &#61; false;killTimer(TextTimeID); //注释1TextTimeID &#61; 0;}else if(TitleState &#61;&#61; false){TextTimeID &#61; startTimer(30);//注释2TitleState &#61; true;}
}

注释1&#xff1a;TitleState值可以判断窗体目前是滚动还是停止状态&#xff0c; 这里使用killTimer()函数来停止并删除显示事件中产生的定时器
注释2&#xff1a; 这里重新生产一个定时器&#xff0c;来刷新时间事件&#xff0c;达到重启滚动的效果
最后在构造函数中将鼠标点击事件中发射的信号和这个槽连接起来

connect(this,SIGNAL(LeftClick()),this,SLOT(StopTitleRun()));

这样鼠标左键点击就可以控制窗体滚动/停止&#xff0c;当这个窗体作为别的窗体的子窗体&#xff08;比如一个程序的警告信息播出栏&#xff09;&#xff0c;可以删除这个连接和鼠标点击时间函数&#xff0c;让别的程序特定的信号和这个槽链接&#xff0c;这样就能控制这个部件的行为
这个类的功能顺序可以概括为
1.窗体启动创建后调用show()函数显示&#xff0c;出发窗体显示事件&#xff0c;在显示事件中创建定时器&#xff0c;触发了时间时间
2.时间事件函数中每隔30毫秒刷新一次窗体绘图事件&#xff08;scroll()函数&#xff09;
3.绘图函数中重新绘制窗体&#xff0c;使用drawText()函数来重新绘制窗体&#xff08;的文本&#xff09;。
4.成员函数setText()作为接口&#xff0c;包含了强制窗体重绘的代码&#xff0c;调用该函数也会触发绘图事件

一些细节上的改动&#xff1a;首先关于时间的间隔这个程序设定为30毫秒&#xff0c;而这个值30是直接写在代码中的&#xff0c;这显然不是一个很好的编程习惯&#xff0c;因为很多程序可能需要修改滚动速度&#xff0c;所以在文件中定义一个常量来表示时间间隔会比较合适&#xff0c;可以使用

const int INTERVAL &#61; 30;

然后在实现使用INTERVAL而不是30,这样当有需要修改的时候只要修改下这个值就可以了而不用在逐行查看代码有没有遗漏的地方。
另一个细节就是在这个类的构造函数中使用了

setWindowFlags(Qt::CustomizeWindowHint);

这个函数是QWidget的成员函数&#xff0c;多数情况下用于自定义窗体&#xff0c;就一这个例子&#xff0c;我在演示是最初的演示截图中窗体并没有系统窗体自带的标题&#xff0c;最大化&#xff0c;最小化等部件&#xff0c;setWindowFlags()函数的参数是枚举Qt::WindowFlags,这个枚举值提供了很多自定义窗体的功能&#xff0c;其中就包括了这里演示的删除本地风格的标题&#xff0c;最大/小化部件等&#xff0c;用和不用这个函数&#xff0c;最后部件外观差别很大




最后需要注意的setWindowFlags()调用后很多外观的改动只有窗体是顶层窗体才会有区别




到这里完成了一个滚动窗体的制作&#xff0c;这个窗体提供了一个setText()的接口&#xff0c;用于设置滚动的文本内容&#xff0c;另外这个程序还可以用鼠标点击来控制播放/停止&#xff0c;这部分很容易根据需要改成窗体的控制接口代码&#xff0c;但这里还有点小问题&#xff0c;这个程序是以文本的大小作为窗体的大小&#xff0c;这样做是为了演示这个程序的时候显得比较。。。好看&#xff0c;窗体刚好是完美契合文本的大小&#xff0c;但如果这个窗体是用于其他程序的子窗体来说就有些不合适了&#xff0c;程序往往需要经常改变滚动的文本内容&#xff0c;事实上就演示的这个窗体而言&#xff0c;拉升下窗体就会使得滚动的文本出现问题。

要解决这个问题&#xff0c;最先要做的是删掉sizeHint()这个函数以及他的定义&#xff0c;这个函数在这个程序中的作用是让窗体的大小和文本完美契合&#xff0c;而如果一个程序需要使用这个窗体&#xff0c;往往会根据实际情况自定义窗体的大小&#xff0c;所以就这个窗体而言&#xff0c;没有必要自己定义大小。

然后就是修改绘图事件函数里的代码。

void TitleWidget::paintEvent(QPaintEvent* event)
{QPainter P(this);int TextWidth &#61; fontMetrics().width(text());int WidgetWidth &#61; width();//注释1if(TextWidth <1)return;int X &#61; - TextPoint;while(X }
注释1&#xff1a; 这里获取窗体的宽度


注释2&#xff1a; 原先的代码最大的绘制范围&#xff08;宽度&#xff09;是文本的宽度&#xff0c;导致拉伸窗体后拉申的部分显示不全或着不显示&#xff0c;这里改用窗体的宽度作为绘制范围&#xff08;宽度&#xff09;&#xff0c;使得窗体拉伸后仍然能够正常显示



推荐阅读
  • 本次发布的Qt音乐播放器2.0版本在用户界面方面进行了细致优化,提升了整体的视觉效果和用户体验。尽管核心功能与1.0版本保持一致,但界面的改进使得操作更加直观便捷,为用户带来了更为流畅的使用体验。此外,我们还对部分细节进行了微调,以确保软件的稳定性和性能得到进一步提升。 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
  • Android目录遍历工具 | AppCrawler自动化测试进阶(第二部分):个性化配置详解
    终于迎来了“足不出户也能为社会贡献力量”的时刻,但有追求的测试工程师绝不会让自己的生活变得乏味。与其在家消磨时光,不如利用这段时间深入研究和提升自己的技术能力,特别是对AppCrawler自动化测试工具的个性化配置进行详细探索。这不仅能够提高测试效率,还能为项目带来更多的价值。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 本文探讨了使用JavaScript在不同页面间传递参数的技术方法。具体而言,从a.html页面跳转至b.html时,如何携带参数并使b.html替代当前页面显示,而非新开窗口。文中详细介绍了实现这一功能的代码及注释,帮助开发者更好地理解和应用该技术。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 深入解析:React与Webpack配置进阶指南(第二部分)
    在本篇进阶指南的第二部分中,我们将继续探讨 React 与 Webpack 的高级配置技巧。通过实际案例,我们将展示如何使用 React 和 Webpack 构建一个简单的 Todo 应用程序,具体包括 `TodoApp.js` 文件中的代码实现,如导入 React 和自定义组件 `TodoList`。此外,我们还将深入讲解 Webpack 配置文件的优化方法,以提升开发效率和应用性能。 ... [详细]
  • 开发笔记:深入解析Android自定义控件——Button的72种变形技巧
    开发笔记:深入解析Android自定义控件——Button的72种变形技巧 ... [详细]
author-avatar
dgsfdg3t4543
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有