IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> QT通过QStyle自定义滚动条 -> 正文阅读

[游戏开发]QT通过QStyle自定义滚动条

在qt里面有默认的滚动区域可以方便使用,QScrollArea,这个自带了水平和垂直滚动条。

但是这些默认样式一般不是我们想要的,例如很多时候我们只需滚动块,而不需要其他的控件。

例如效果:

?

现在介绍自定义滚动条。

1.关闭默认滚动条显示

在使用QScrollArea时,垂直和水平滚动条全部不展示:

	area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

2.派生QScrollBar

class MyScrollBar :public QScrollBar
{
	Q_OBJECT
public:
	MyScrollBar(QWidget* parent = nullptr);
	~MyScrollBar();
	QSize sizeHint()const override;
	void setArea(QAbstractScrollArea * area);
protected:
	void paintEvent(QPaintEvent *ev) override;
	
private slots:
	void onSetRange(int min, int max);
private:
	QAbstractScrollArea* m_area = nullptr;
	MyScrollStyle* m_style = nullptr;
};

我们自定义的QScrollBar需要绑定原有的滚动条信号,这里我们只处理垂直滚动条:

void MyScrollBar::setArea(QAbstractScrollArea * area)
{
	area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	auto bar = area->verticalScrollBar();
	QObject::connect(
		bar, SIGNAL(rangeChanged(int, int)), this, SLOT(onSetRange(int, int)));
	QObject::connect(
		bar, SIGNAL(valueChanged(int)), this, SLOT(setValue(int))
	);
	QObject::connect(
		this, SIGNAL(valueChanged(int)), bar, SLOT(setValue(int))
	);
	setVisible(false);
	m_area = area;

    //设置成自定义的样式
	m_style = new MyScrollStyle();
	setStyle(m_style);
}

绑定了原有滚动条的滚动范围变化、值变化,更新到自定义滚动条;自定义的滚动条的值变化后,也需要更改原滚动条的值。注意:第一步设置的只是不展示滚动条,其实他还是在的。

在滚动范围变化后,将滚动条设置位置并展示:

void MyScrollBar::onSetRange(int min, int max)
{
	if (max > 0)
	{
		setVisible(true);
		setGeometry(m_area->rect().width() - width() - 2, 2, width(), height());
	}
	setRange(min, max);
}

3.自定义QStyle

翻看qt文档,可以看到滚动条有几个子控件:


QStyle::SC_ScrollBarAddLine
QStyle::SC_ScrollBarSubLine
QStyle::SC_ScrollBarAddPage
QStyle::SC_ScrollBarSubPage
QStyle::SC_ScrollBarFirst
QStyle::SC_ScrollBarLast
QStyle::SC_ScrollBarSlider
QStyle::SC_ScrollBarGroove
这些含义可以在qt文档里面找到,例如SC_ScrollBarAddLine就是滚动条的“下一行”按钮:

?我们要做的是只剩下里面的灰色滚动控件。

所以我们继承QStyle后,override这些控件的大小就行:

class MyScrollStyle :public QCommonStyle
{
public:
	MyScrollStyle();
	QRect subControlRect(ComplexControl cc,const QStyleOptionComplex* opt,
		SubControl sc, const QWidget* widget /*= nullptr*/) const override;
};

MyScrollStyle::MyScrollStyle()
{

}

QRect MyScrollStyle::subControlRect(ComplexControl cc,
	const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget /*= nullptr*/) const
{
	if (cc == QStyle::CC_ScrollBar)
	{
		QRect ret;
		if (const QStyleOptionSlider* scrollbar = qstyleoption_cast<const QStyleOptionSlider*>(opt)) {
			const QRect scrollBarRect = scrollbar->rect;
			int sbextent = 0;
			int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
				scrollBarRect.width() : scrollBarRect.height());
			int sliderlen;
			// calculate slider length
			if (scrollbar->maximum != scrollbar->minimum) {
				uint range = scrollbar->maximum - scrollbar->minimum;
				int contentlen = 0;
				sliderlen = 2 * maxlen / 3;
				if (widget)
				{
                    //这里给定的最大高度,按照自己的喜好处理
                    //我的Scrollbar设置的parent为:QAbstractScrollArea
					QAbstractScrollArea* area = qobject_cast<QAbstractScrollArea*>(widget->parentWidget());
					QWidget * w = area->viewport();
					contentlen = w->height();
					int nPageCount = contentlen / maxlen;
					if (nPageCount > 0)
					{
						sliderlen = sliderlen / nPageCount;
					}
				}
				int slidermin = proxy()->pixelMetric(PM_ScrollBarSliderMin, scrollbar, widget);
				if (sliderlen < slidermin || range > INT_MAX / 2)
					sliderlen = slidermin;
				if (sliderlen > maxlen)
					sliderlen = maxlen;
			}
			else {
				sliderlen = maxlen;
			}

			int sliderstart = sbextent + sliderPositionFromValue(scrollbar->minimum,
				scrollbar->maximum,
				scrollbar->sliderPosition,
				maxlen - sliderlen,
				scrollbar->upsideDown);

			switch (sc) {
			case SC_ScrollBarSubLine:            // top/left button
			case SC_ScrollBarAddLine:            // bottom/right button
			case SC_ScrollBarSubPage:            // between top/left button and slider
			case SC_ScrollBarAddPage:            // between bottom/right button and slider
				break;
			case SC_ScrollBarGroove:
				if (scrollbar->orientation == Qt::Horizontal)
					ret.setRect(sbextent, 0, scrollBarRect.width() - sbextent * 2,
						scrollBarRect.height());
				else
					ret.setRect(0, sbextent, scrollBarRect.width(),
						scrollBarRect.height() - sbextent * 2);
				break;
			case SC_ScrollBarSlider:
				if (scrollbar->orientation == Qt::Horizontal)
					ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height());
				else
					ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen);
				break;
			default:
				break;
			}
			return ret;
		}
	}
	return QCommonStyle::subControlRect(cc, opt, sc, widget);
}

只处理SC_ScrollBarGroove(可滚动区域)和SC_ScrollBarSlider(滚动滑块),其余的控件大小全返回空Rect。

4. 复写滚动条的paintevent

在滚动条的paintevent里面,我们取出控件进行绘制:

void MyScrollBar::paintEvent(QPaintEvent *ev)
{
	QRect rc = this->rect();
	QPainter painter(this);
	painter.fillRect(rc, QColor("#FFFFFF"));  //绘制滚动条背景

	QStyleOptionSlider opt;
	initStyleOption(&opt);

	QRect sliderRc = style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider,this);  //获取滑块控件

	QPainterPath p;
	p.addRoundedRect(sliderRc, 5, 5);
	painter.fillPath(p, QColor(0,0,0,0x33));

}

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:21:40  更:2022-04-06 16:23:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 19:55:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码