QT自己制作仪表盘控件、图片绕图片中心点旋转

真正的自定义控件,是可以集成到UI设计界面中的,可以直接用鼠标拖放到UI设计界面中,不过这种方法网上找了好久也没找到完整的制作方法,网上能找到的方法,虽然支持鼠标拖放,但是仍然需要在工程中添加源码,很不方便,暂时我不打算使用这个方法了。

我使用的方法是用pri子工程,这种方法使得控件和新工程之间的耦合度也算是比较低,使用pri的方法请参考我的另一篇博文。

先看一下效果图:

原理无非就是贴图,仪表盘背景贴一张图,仪表指针再贴一张图,然后根据自定义的public接口函数,实时修改仪表指针的旋转角度。

为了更美观,我们可以用WPS/excel制作仪表盘贴图:

请参考我的另一篇博客《用wps/excel制作仪表盘》

自定义这种控件,用到的几个知识点如下:

1、如何添加图片到工程中?

你可以直接在工程中引用图片的绝对/相对路径,但是一旦图片的路径变化了,就得改源码,很烦。最好的方法就是把图片添加为资源文件,右击工程,添加新文件->QT->QT resource File,即可添加一个qrc文件,然后在工程文件目录树的qrc文件中按下图添加资源图片即可。如下图所示,我添加了4张图片。

2、仪表盘和仪表指针必须要用带透明通道的png或者gif文件?

如前面效果图所示,仪表盘和指针之外都是透明的,目前我只知道png支持任意部位透明或半透明,gif支持局部全透明,jpg、bmp等格式是不支持透明的。稍微会一点PS的话,做这种图很简单,就是抠图而已,然后另存为png或gif就行了。

3、如何在界面中显示图片?

显示图片有两种方法,一种是使用QLable的setPixmap( ) 或 setPicture( )函数来直接显示图片,另一种是使用QPainter在覆盖的void paintEvent(QPaintEvent *event)函数中使用QPainter::drawPixmap( )来绘制图片。

相对来说,QLable显示图片更简单,QPainter绘制图片自由度更高。

3.1 QLable旋转图片

QLable想要自由旋转图片就很不方便,我们分两种情况来讨论,

(1)图片自适应QLable的大小时

通过设置QLable::setScaledContents(true);可以使内容(文字或图片)充满整个QLable矩阵框。

ui->label_0->setFrameShape (QFrame::Box);//显示边框
ui->label_1->setFrameShape (QFrame::Box);

ui->label_0->setScaledContents(true);//内容自适应边框的大小
ui->label_1->setScaledContents(true);

ui->label_0->setPixmap(QPixmap(":/pic/rect2.png"));

QMatrix matrix;
matrix.rotate(30);//旋转30度
ui->label_1->setPixmap(QPixmap(":/pic/rect2.png").transformed(matrix));

感官上来看,第二个QLable为了能容纳旋转后的图片,只能把图片缩小了。

(2)不缩放图片,图片在QLable中总是显示为原大小时

注释掉上面程序段的内容自适应语句setScaledContents,效果如下:

我们发现QT总是从QLable左侧边缘开始绘制,并垂直居中显示图片,虽然两次绘制出的矩形大小相同(都是图片的原始大小),但是显然这两次绘制橙色矩形的中心点是不同的。当然我们可以通过精密计算,使得两次的中心点相同,但计算过程太耗费CPU。总的来说,这种旋转方式不适合绘制仪表盘的旋转指针,因为仪表盘的旋转指针总是绕某个固定点进行旋转的。

3.2 使用QPainter旋转图片

QPainter绘制图片时,需要QWidget或者其子类作为画布,这里我们选择QWidget作为画布,然后使用QPainter在QWidget上绘制图片。QPainter只能在覆盖的void paintEvent(QPaintEvent *event)函数中使用,因此,我们必须写一个新类,继承QWidget并重写paintEvent函数,假设新类的名称为ImgContainer:

ImgContainer::ImgContainer(QWidget *parent)
    :QWidget(parent)
    ,rot_deg(0)
{
    this->show();
    pixmap = new QPixmap();
}
/*
注意,不要传局部变量到pixmapIn来
*/
void ImgContainer::setPaintPicture(QPixmap &pixmapIn)
{
    pixmap = &pixmapIn;
}
void ImgContainer::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
//    painter.setRenderHint(QPainter::TextAntialiasing, true);//抗锯齿
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);//平滑像素图

    painter.translate(width() / 2, height() / 2);  //移动物体坐标系原点到图片中心
    painter.rotate(rot_deg);                //顺时针旋转物体坐标系
    painter.drawPixmap(-width() / 2, -height() / 2, width(), height(), *pixmap);
}
void ImgContainer::setRotation(float deg)
{
    rot_deg = deg;
    update();//立即刷新界面(内部会调到paintEvent(QPaintEvent *event))
}

这段代码展示了如何绘制旋转图片,而且我们可以通过QPainter::drawPixmap的参数指定绘制出的图片的大小。在这段代码示例中,我绘制的图片长宽=画布QLable的长宽。

在ui中拖出两个widget,并提升为ImgContainer,然后在mainwidows.c中执行:

 ui->widget_1->setPaintPicture(*(new QPixmap(":/pic/rect2.png")));
    ui->widget_2->setPaintPicture(*(new QPixmap(":/pic/rect2.png")));
    ui->widget_2->setRotation(30);

效果如下:

这个旋转效果非常适合用来旋转仪表盘指针。

猜你喜欢

转载自blog.csdn.net/qq_31073871/article/details/89702951
今日推荐