// 我们假设有一个QLabel 用来显示某某信息,但是信息有时候过长,高度超过了QLabel的高度
// 这时候最好的方法是让其滚动,那么我们就来实现以下上下滚动。
// 要用到的QT 事件
void showEvent(QShowEvent *);
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *);
void hideEvent(QHideEvent *);
// paintEvent 这个事件是重绘事件
// timerEvent 既然是滚动肯定有个定时器,这是定时器事件
// showEvent 显示事件 例如 label->show() 时候触发
// hideEvent 隐藏事件 例如 label->hide() 时候触发
// 下面就附上代码进行详细说明 这里我们定义 VScrollLabel 类
------------------------------ Vscrolllabel.h-------------------------
#ifndef VSCROLLLABEL_H
#define VSCROLLLABEL_H
#include <QLabel>
class VScrollLabel : public QLabel // 继承 QLabel类
{
Q_OBJECT
public:
explicit VScrollLabel(QWidget *parent = 0, Qt::WindowFlags f=0);
virtual ~VScrollLabel(){}
public slots:
void setText(const QString &);
protected:
void showEvent(QShowEvent *);
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *);
void hideEvent(QHideEvent *);
private slots:
void metrics();
void startScroll();
signals:
void currentTextChanged();
private:
int getHeight();
private:
int offset;
int timerID;
int textHeight;
};
#endif // VSCROLLLABEL_H
#include "vscrolllabel.h"
#include <QPainter>
#include <QTimerEvent>
#include <QTimer>
VScrollLabel::VScrollLabel(QWidget *parent, Qt::WindowFlags f) :
QLabel(parent,f)
{
offset = timerID = textHeight = 0;
connect(this, SIGNAL(currentTextChanged()), SLOT(metrics()));
}
void VScrollLabel::setText(const QString &curText)
{
if (text() != curText) {
QLabel::setText(curText);
emit currentTextChanged();
}
}
// 开始启动定时器 设为 50
void VScrollLabel::startScroll()
{
timerID = startTimer(50);
}
void VScrollLabel::metrics()
{
offset = 0;
// getHeight + QLabel高度是为了 一段过长的文字显示完后再重新开始滚动显示
// 不然的话第一行会紧接着末尾显示出来。
textHeight = getHeight() +height() ;
QTimer::singleShot(500, this, SLOT(startScroll()));
this->update();
}
// 这里是重点,我们得到的一段信息有没有换行符号,要自动换行
// 这就要得到字体的高度和宽度来处理这一段文字,处理完后调用
// setText() 设置到Qlabel 上面去。
int VScrollLabel::getHeight()
{
#define MARGIN 5
char newMsg[1024] ={0};
char *message = text().toLatin1().data();
int len = strlen(message);
char mss[len];
memcpy(mss,text().toLatin1().data(),len);
int i;
int row =1;
int line_width =0;
int font_width = 0;
int max_width = 0;
int j=0;
QFontMetrics fm = fontMetrics();
int h = 18; // 这里指定我们想要的字体高度
printf("len = %d\n",len);
for (i=0; i<len; i++) {
font_width = fm.width(mss[i]);
if (mss[i] == '\n') { // line feed
line_width = 0;
newMsg[j++] = mss[i];
row++;
continue;
}
if ((line_width+font_width) > width()) {
max_width = line_width;
newMsg[j++] = '\n';
line_width = 0;
row++;
}
line_width += font_width;
newMsg[j++] = mss[i];
//printf("line_width = %d\n",line_width);
if (line_width > max_width) max_width = line_width;
if(j == sizeof(newMsg)-1) break;
}
printf("row = %d\n",row);
// 上面经过处理得到结果,查看下有多少行。
// 设置到QLabel 上去
setText(newMsg);
// 返回 行*字体高度 + 这里我们加了10 的预留空间。
return row*h+(MARGIN<<1);
}
// 显示我们就启动定时器
void VScrollLabel::showEvent(QShowEvent *)
{
metrics();
}
void VScrollLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
if (textHeight < 1) return;
int y = -offset;
while (y < height()) {
painter.drawText(0, y, width(), textHeight,
Qt::AlignLeft | Qt::AlignVCenter, text());
y += textHeight;
}
}
void VScrollLabel::timerEvent(QTimerEvent *event)
{
if (event->timerId() == timerID) {
++offset;
if (offset >= textHeight)
offset = 0;
scroll(0, -1); // X 轴不变,Y 轴 向上偏移 1
} else {
QWidget::timerEvent(event);
}
}
// 隐藏我们就停止掉 定时器
void VScrollLabel::hideEvent(QHideEvent *)
{
offset = 0;
if (timerID) killTimer(timerID);
}