slider->setMaximum(100);//设置最大值 slider->setMinimum(0); //设置最小值
slider->setGeometry(10,60,350,35);//设置几何参数 slider->setValue(45);//设置当前值
slider->setOrientation(Qt::Horizontal);//设置控件方向,水平
slider->setStyleSheet(\/*设置groove属性*/ \ \ \
\ \ \ \
\/*设置handle属性*/ \ \ \
\/*设置上下边距缩小height*/ \
\/*设置border的弯角属性*/ \
图3-2-2 slider设置之后的效果
还可以将QSlider控件分成4部分:groove、handle、add page、sub page。其中
add page是控制handle右侧的groove外观;sub page是控制handle左侧的groove外观。下面给出一段示例代码,其效果如图3-2-3所示: QSlider *slider = new QSlider(Qt::Horizontal); slider->setRange(0, 100);//set default range slider->setStyleSheet(
\\
\
\
\
\qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.34, fx:0.5, fy:0.5, stop:0.293785 rgba(255, 255, 255, 255), stop:0.379831 rgba(236, 236, 236, 180), stop:0.830508 rgba(255, 158, 158, 0));}\
\
\
\
#7B7B7B);}\
\
图3-2-3 slider设置之后的效果
在上段示例代码中,handle并未使用背景图片,而是用color pattern填充了background-color。sub page部分同样使用了color pattern进行颜色填充。型如qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #D6D6D6, stop:1 #7B7B7B);的颜色样式可以利用Qt Designer工具进行编辑,同时工具中也提供了多种固定的样式,可以在这些固定样式的基础上进行修改,也可以进行全新的创作。Qt Designer中的property?style sheet?Add Gradient? background-color中的各种pattern对应的效果如图3-2-4所示:
图3-2-4 Qt Designer中提供的固定样式
4 事件处理机制
所有Qt应用程序都是由事件驱动的,程序的每个动作都是由幕后某个事件所触发。应用程序在main函数中进行初始化,然后在main函数中由一个QApplication对象调用exec方法,这就启动了应用程序的事件循环。
事件循环负责处理两个任务:
A 事件循环负责处理来自系统的事件(比如重新绘制一个窗口区域)。事件循环将接收到的来自系统的事件转换成基于Qt的事件类型,转换后的事件被封装成以QEvent作为基类的派生类。
B 事件循环负责处理Qt自身产生的事件(比如某个指定时间到而触发的定时事件)。这些事件也是基于QEvent的,被事件循环处理。
每个QEvent都有一个类型。QEvent的子类可以包含所需的全部信息。比如,Qt通过QCoreApplication::postEvnets()将事件传递给特定的对象。这些接收事件QMouseEvent处理按键及鼠标位置的信息。
的对象必须继承自QObject。这个方法的第一个参数是接收事件的对象,第二个参数是QEvent对象。postEvents()将事件传递给目标对象的event()方法。event()方法的任务是依据接收事件的对象的所属类的需求来决定处理或忽略接收到的事件。这个event()方法也被称作事件句柄(event handler)。如果一个事件不能被接收方立即处理,该事件将被放入一个队列然后延迟处理。
根据Qt处理事件的机制,可以将事件处理由强到弱分成几个级别(强者先处理): 给QApplication对象安装事件过滤器:一旦给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个eventFilter()。
在Qt对象上安装事件过滤器:事件过滤器可以让对象A接收、处理对象B的事件。对于对象B的每个事件,先由A接收并处理(被A的eventFilter()过滤一遍),然后剩下还需处理的事件再传递给对象B去处理。
重载event()函数:通过重载event()函数,可以在事件被特定的事件处理函数处理之前处理它。
重载特定事件处理函数:比如重载keyPressEvent(), paintEvent(),timerEvent()等。 4.1 事件过滤器的应用(eventFilter)
在进行事件过滤之前,必须先安装事件过滤器。假设需要给对象B安装事件过滤器,对象B的事件先被A过滤一遍,再传到B。那么,首先要在对象A的构造函数中调用installEventFilter()函数来监视对象B的事件。
安装过滤器之后,对象B完全放弃了它自己的事件,由对象A来决定是将本属于B的事件过滤掉还是将它们传递给B。在A中需要重载eventFilter()函数,其定义如下: bool QObject::eventFilter(QObject *watched, QEvent *e);
参数watched允许对来自多个被监视的对象加以区分,参数e是被处理的事件。返回值告诉Qt的事件系统,该如何处理事件。如果返回false,事件e将被传递给被监视的对象;如
果返回true,事件e将被过滤掉,这意味着该事件将不会传递到原本想到达的目标对象。
event filter的常见应用场合:
用来处理热键 -- 比如一个界面上可以由用户热键来触发的多个按钮。 由于只有得到焦点的控件才能获得键盘的事件, 如果不用event filter就需要给每个button都加上键盘事件的处理, 还要在button里去访问兄弟button的指针, 逻辑非常混乱。 如果由主窗体做各个按钮的eventFilter, 则只需要在主窗体里去处理键盘事件就好, 而且主窗体可以很容易的访问到各个button的指针, 很方便。
用来代替派生和重写虚函数 -- Qt里的键盘鼠标事件基本上都是以虚函数的方式来处理, 要想重写虚函数则必须派生一个子类, 这样的话如果只是一个简单的事件处理也去派生子类代价未免大了些, 这时候就值得用用eventFilter。 比如我的MDI界面想在每个子窗体关闭的时候做一些统一的操作, 一般的做法是处理子窗体的closeEvent。 但显然给每个子窗体都去派生个子类太不现实, 最好的方法是把mainwindow作为子窗体的eventFilter去处理CloseEvent事件。
以下是一个应用事件过滤器的实例。该实例所实现的主要功能是,在一个含有QTextEdit对象与QTextBrowser对象的对话框中,向QTextEdit控件中输入字符,然后按“Return”键或“Enter”键,内容被追加到QTextBrowser对象中,同时清除QTextEdit对象中的内容。实例的运行效果如图4-1-1所示:
4-1-1 eventFilter实例运行效果
实现代码如下所示: // chatwindow.h
#ifndef CHATWINDOW_H #define CHATWINDOW_H #include
class ChatWindow : public QWidget {
Q_OBJECT public:
ChatWindow(QWidget *parent = 0);
bool eventFilter(QObject *watched, QEvent *e);//事件过滤器 void submitChatText();//负责发送text private:
QTextBrowser *conversationView;//文本浏览控件 QTextEdit *chatEdit;//文本编辑控件 };
#endif // CHATWINDOW_H
// chatwindow.cpp #include
ChatWindow::ChatWindow(QWidget *parent) : QWidget(parent) {
QVBoxLayout *lay = new QVBoxLayout(this); QSplitter *splitter = new QSplitter(Qt::Vertical, this); lay->addWidget(splitter);
conversationView = new QTextBrowser; chatEdit = new QTextEdit;