最近用QT开发一个软件,遇到一些问题在网上找不到完善的解决方案,自己做了一些尝试后最后找到符合自己需要的,还有对一些问题的理解,在此做一些记录。不一定是很有效率的通用解决方案,希望遇到相关问题的可以在这里找到一些思路。
先记录下刚刚做完的窗口背景设置,我需要的是:在没有选择图片的时候,显示背景颜色,而在有图片的时候显示图片,并且图片要可以选择:“居中”、”平铺”、”缩放”、”拉伸”四种填充方式。图片示例如下:
① 图片小于widget情况,从左到右依次为:没有图片、“居中”、“平铺”、“缩放”、“拉伸”
① 图片大于widget情况,从左到右依次为:没有图片、“居中”、“平铺”、“缩放”、“拉伸”
在网上查,基本上都在说明QT设置背景颜色、图片的三种方式:setStyleSheet、QPalette、paintEvent。在这里我不作过多用法说明,而针对我的需求,说下这几种方法:
1、使用setStyleSheet
背景颜色和背景图片可以同时设置(background-color、background-image),存在以下行为:图片路径无法正确解析时,只显示背景颜色;图片可以解析时,按设置方式显示图片,而在图片范围外显示背景颜色。默认的图片显示位置为左上角,填充方式是平铺。这两个可以通过background-position、background-repeat来调整。
存在问题:这种方式设置的图片都是按原图大小进行显示,不能进行缩放。而且url只能填入路径,不能是一个QPixmap,所以也无法通过调整图片大小来缩放显示。所以只能实现“居中”、”平铺”两种形式,而无法实现“缩放”、“拉伸”
一种替代方式是使用border-image属性,这种方法显示的图片就是图片调整到widget大小再显示,实现”拉伸”形式。同样无法实现缩放。这种方法不够灵活。
2、使用画板QPalette
这种方式是通过给QPalette设置QBrush画刷来设置背景的,最有用的地方在于它可以设置QPixmap,使得背景图片可以按照我们想要的大小进行变化,可以轻松实现”拉伸”方式。
存在问题:这种方法会以平铺的方式填充满整个widget,即使你把图片scale到自己想到的大小,剩余的地方也会被填充。所以这种方式只能实现“平铺”、“拉伸”,而无法实现“居中”、“缩放”。
3、重写paintEvent方法
这种方法是最灵活的,可以按照自己想要的任何方式描绘背景。可以实现“居中”、“平铺”、“缩放”、“拉伸”。
存在问题:因为背景如何显示全部要自己手动实现,需要精确的坐标计算图片的显示位置。特别是“平铺”方式,需要根据widget大小和图片的大小先判断出要重复画多少次图,还要计算每一次图的起点。
★★★★★
如果是QLabel这种可以直接设置QPixmap的,就可以比较简单地实现常用的背景图片四种显示方式。而对于不能设置QPixmap的widget,在允许的情况下可以重载该widget,并在该widget内创建一个与widget同样大小的QLabel,专门用来显示背景。在我的项目中,因为要调整的widget是自己实现的,所以最终采用了在内部创建一个QLabel专门处理背景显示问题。
相关的设置代码如下:
QLabel label = new QLabel(this);
label.setGeometry(0, 0, this->width(), this->height());
QPixmap bgImage("1.jpg");
if (bgImage.isNull())
{
label->setStyleSheet("background-color:black");
}
else
{
switch (方式)
{
case 居中:
label->setStyleSheet("background-color:black;background-image:url(1.jpg);background-position:center;background-repeat:no-repeat;");
break;
case 缩放:
label->setStyleSheet("background-color:black");
label->setAlignment(Qt::AlignCenter);
label->setPixmap(bgImage.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
break;
case 拉伸:
label->setStyleSheet("background-color:black");
label->setPixmap(bgImage.scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
break;
case 平铺:
label->setStyleSheet("background-color:black;background-image:url(1.jpg);background-position:top left;background-repeat:repeat-xy;");
break;
}
}