Qt——升级系列(Level Eight):界面优化

目录

QSS

  背景介绍

  基本语法

  QSS设置方式

        指定控件样式设置

        全局样式设置

        从文件加载样式表

        使用Qt Designer 编辑样式

  选择器

        选择器概况

        子控件选择器

        伪类选择器

  样式属性

        盒模型

  控件样式示例

        按钮

        复选框、单选框

        输入框

        列表

        菜单栏

        登录界面

绘图

  基本概念

  绘制各种形状

        绘制线段

        绘制矩形

        绘制圆形

        绘制文本

        设置画笔

        设置画刷

  绘制图片

        绘制简单图片

        缩放图片

        旋转图片

  特殊的画图设备

        QPixmap

        QImage

        QPicture

QSS

  背景介绍

        在⽹⻚前端开发领域中, CSS 是⼀个⾄关重要的部分. 描述了⼀个⽹⻚的 "样式". 从⽽起到对⽹⻚美化的作⽤.

        Qt 仿照 CSS 的模式, 引⼊了 QSS, 来对 Qt 中的控件做出样式上的设定, 从⽽允许程序员写出界⾯更好看代码.

        QSS(Qt Style Sheets)是Qt中用于定义和定制界面样式的一种机制。类似于CSS(Cascading Style Sheets),QSS允许开发者通过简单的语法规则为Qt应用程序的控件(如窗口、按钮、标签等)设置样式,从而实现界面的美化和个性化定制。

注意:如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突, 则 QSS 优先级更⾼.

  基本语法

        对于 CSS 来说, 基本的语法结构⾮常简单.

选择器 
{
    属性名: 属性值; 
}

        QSS 沿⽤了这样的设定.  

选择器 
{
    属性名: 属性值; 
}

 其中:
        • 选择器 描述了 "哪个 widget 要应⽤样式规则".
        • 属性 则是⼀个键值对, 属性名表⽰要设置哪种样式, 属性值表⽰了设置的样式的值.

下面是一个典型的 Qt 程序中用于设置界面样式的示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent),  // 构造函数的初始化列表,将 parent 作为父类的构造函数参数
    ui(new Ui::Widget)  // 创建了 Ui::Widget 对象的实例,通常是在 Qt Designer 生成的 UI 类
{
    ui->setupUi(this);  // 调用 setupUi 函数初始化界面,将当前 Widget 作为参数传递

    // 为 QPushButton 设置样式表,使其文字颜色为红色
    ui->pushButton->setStyleSheet("QPushButton { color: red; }");
}

  QSS设置方式

        指定控件样式设置

        QWidget 中包含了 setStyleSheet ⽅法, 可以直接设置样式.上述代码我们已经演⽰了上述设置⽅式.

        另⼀⽅⾯, 给指定控件设置样式之后, 该控件的⼦元素也会受到影响.

代码⽰例: ⼦元素受到影响

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个垂直布局管理器
    QVBoxLayout layout(&parentWidget);

    // 创建一个 QPushButton 作为父级控件的子元素
    QPushButton *button1 = new QPushButton("Button 1", &parentWidget);
    layout.addWidget(button1);

    // 创建另一个 QPushButton 作为父级控件的子元素
    QPushButton *button2 = new QPushButton("Button 2", &parentWidget);
    layout.addWidget(button2);

    // 设置父级控件的样式表,同时会影响其所有子元素
    parentWidget.setStyleSheet("QWidget { background-color: lightblue; }"
                               "QPushButton { color: white; background-color: green; }");

    parentWidget.show();

    return app.exec();
}

代码结果:

        全局样式设置

        还可以通过 QApplication 的 setStyleSheet ⽅法设置整个程序的全局样式.

全局样式优点:
        • 使同⼀个样式针对多个控件⽣效, 代码更简洁.
        • 所有控件样式内聚在⼀起, 便于维护和问题排查.

代码⽰例: 使⽤全局样式

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 设置全局样式表
    QString globalStyleSheet = "QWidget { background-color: lightblue; }"
                               "QPushButton { color: white; background-color: green; }";
    app.setStyleSheet(globalStyleSheet);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个垂直布局管理器
    QVBoxLayout layout(&parentWidget);

    // 创建一个 QPushButton 作为父级控件的子元素
    QPushButton *button1 = new QPushButton("Button 1", &parentWidget);
    layout.addWidget(button1);

    // 创建另一个 QPushButton 作为父级控件的子元素
    QPushButton *button2 = new QPushButton("Button 2", &parentWidget);
    layout.addWidget(button2);

    parentWidget.show();

    return app.exec();
}

代码结果: 

        从文件加载样式表

        上述代码都是把样式通过硬编码的⽅式设置的. 这样使 QSS 代码和 C++ 代码耦合在⼀起了, 并不⽅便代码的维护.

        因此更好的做法是把样式放到单独的⽂件中, 然后通过读取⽂件的⽅式来加载样式.

代码⽰例: 从⽂件加载全局样式

/* styles.qss */

/* 设置所有 QWidget 的背景颜色为浅蓝色 */
QWidget 
{
    background-color: lightblue;
}

/* 设置所有 QPushButton 的文字颜色为白色,背景颜色为绿色 */
QPushButton 
{
    color: white;
    background-color: green;
}
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QFile>
#include <QTextStream>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 读取样式表文件
    QFile styleFile(":/styles.qss");  // 文件路径可以根据实际情况修改
    if (!styleFile.open(QFile::ReadOnly | QFile::Text)) 
    {
        qWarning("无法打开样式表文件");
        return -1;
    }

    // 读取样式表内容
    QTextStream textStream(&styleFile);
    QString styleSheet = textStream.readAll();

    // 关闭文件
    styleFile.close();

    // 设置全局样式表
    app.setStyleSheet(styleSheet);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个 QPushButton 作为父级控件的子元素
    QPushButton *button1 = new QPushButton("Button 1", &parentWidget);
    button1->resize(100, 30);
    button1->move(50, 50);

    // 创建另一个 QPushButton 作为父级控件的子元素
    QPushButton *button2 = new QPushButton("Button 2", &parentWidget);
    button2->resize(100, 30);
    button2->move(50, 100);

    parentWidget.show();

    return app.exec();
}

 代码结果:

        使用Qt Designer 编辑样式

        QSS 也可以通过 Qt Designer 直接编辑, 从⽽起到实时预览的效果. 同时也能避免 C++ 和 QSS 代码的耦合.

  选择器

        选择器概况

        QSS 的选择器⽀持以下⼏种:

选择器
⽰例
说明
全局选择器
*
选择所有的 widget.
类型选择器 (type selector)
QPushButton
选择所有的 QPushButton 和 其⼦类的控件.
类选择器 (class selector)
.QPushButton
选择所有的 QPushButton 的控件. 不会选择⼦类.
ID 选择器
#pushButton_2
选择 objectName pushButton_2 的控件.
后代选择器
QDialog QPushButton
选择 QDialog 的所有后代(⼦控件, 孙⼦控件等等)中的 QPushButton.
⼦选择器
QDialog > QPushButton
选择 QDialog 的所有⼦控件中的 QPushButton.
并集选择器
QPushButton,QLineEdit,QComboBox
选择 QPushButton, QLineEdit, QComboBox 这三种控件.
属性选择器
QPushButton[flat="false"]
选择所有 QPushButton 中, flat 属性为 false 的控件.

使⽤类型选择器选中⼦类控件 :

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // 设置全局样式
    a.setStyleSheet("QWidget { color: red; }");
    Widget w;
    w.show();
    return a.exec();
}

 使⽤ id 选择器:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // 设置全局样式
    QString style = "";
    style += "QPushButton { color: yellow; }";
    style += "#pushButton { color: red; }";
    style += "#pushButton_2 { color: green; }";
    a.setStyleSheet(style);
    Widget w;
    w.show();     
    return a.exec();
}

使⽤并集选择器 :

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // 设置全局样式
    a.setStyleSheet("QPushButton, QLabel, QLineEdit { color: red; } ");
    Widget w;
    w.show();
    return a.exec();
}

        子控件选择器

        有些控件内部包含了多个 "⼦控件" . ⽐如 QComboBox 的下拉后的⾯板, ⽐如 QSpinBox 的上下按钮等.

        可以通过⼦控件选择器 :: , 针对上述⼦控件进⾏样式设置.

使用子控件选择器设置 QComboBox 的下拉按钮样式:

#include <QApplication>
#include <QWidget>
#include <QComboBox>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个 QComboBox 控件作为父级控件的子元素
    QComboBox comboBox(&parentWidget);
    comboBox.setGeometry(50, 50, 200, 30);

    // 添加一些选项
    comboBox.addItem("Option 1");
    comboBox.addItem("Option 2");
    comboBox.addItem("Option 3");

    // 设置 QComboBox 的样式表,包括下拉按钮的样式
    comboBox.setStyleSheet("QComboBox::down-arrow {"
                           "    image: url(:/down_arrow.png);"
                           "    width: 20px;"
                           "    height: 20px;"
                           "}");

    parentWidget.show();

    return app.exec();
}

如何修改 QProgressBar 进度条的颜色,以及如何使用子控件选择器对其进行定制: 

#include <QApplication>
#include <QWidget>
#include <QProgressBar>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个垂直布局管理器
    QVBoxLayout layout(&parentWidget);

    // 创建一个 QProgressBar 进度条控件作为父级控件的子元素
    QProgressBar *progressBar = new QProgressBar(&parentWidget);
    progressBar->setRange(0, 100); // 设置进度条范围
    progressBar->setValue(50);     // 设置当前进度
    layout.addWidget(progressBar);

    // 设置 QProgressBar 的样式表,修改进度条颜色和样式
    progressBar->setStyleSheet("QProgressBar {"
                               "    border: 2px solid grey;"
                               "    border-radius: 5px;"
                               "    text-align: center;"
                               "    background-color: #FFFFFF;"
                               "}"
                               "QProgressBar::chunk {"
                               "    background-color: #00FF00;"
                               "    width: 20px;"
                               "}");

    parentWidget.show();

    return app.exec();
}

        伪类选择器

        伪类选择器, 是根据控件所处的某个状态被选择的. 例如按钮被按下, 输⼊框获取到焦点, ⿏标移动到某个控件上等.

• 当状态具备时, 控件被选中, 样式⽣效.
• 当状态不具备时, 控件不被选中, 样式失效.
使⽤ : 的⽅式定义伪类选择器。

常⽤的伪类选择器:

伪类选择器
说明
:hover
⿏标放到控件上
:pressed
⿏标左键按下时
:focus
获取输⼊焦点时
:enabled
元素处于可⽤状态时
:checked
被勾选时
:read-only
元素为只读状态时

        这些状态可以使⽤ ! 来取反. ⽐如 :!hover 就是⿏标离开控件时, :!pressed 就是⿏标松开时,等等. 

示例1:设置按钮的伪类样式(使用样式表)

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个垂直布局管理器
    QVBoxLayout layout(&parentWidget);

    // 创建一个 QPushButton 按钮控件作为父级控件的子元素
    QPushButton *button = new QPushButton("Click me", &parentWidget);
    layout.addWidget(button);

    // 设置 QPushButton 的样式表,使用伪类选择器
    button->setStyleSheet("QPushButton {"
                          "    background-color: blue;"
                          "    color: white;"
                          "}"
                          "QPushButton:hover {"
                          "    background-color: lightblue;"
                          "}"
                          "QPushButton:pressed {"
                          "    background-color: darkblue;"
                          "}");

    parentWidget.show();

    return app.exec();
}

代码结果: 

示例2:使用事件方式实现同样效果

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QEvent>

class CustomButton : public QPushButton
{
public:
    CustomButton(QWidget *parent = nullptr) : QPushButton(parent) {}

protected:
    void enterEvent(QEvent *event) override
    {
        setStyleSheet("background-color: lightblue;");
    }

    void leaveEvent(QEvent *event) override
    {
        setStyleSheet("background-color: blue;");
    }

    void mousePressEvent(QMouseEvent *event) override
    {
        setStyleSheet("background-color: darkblue;");
        QPushButton::mousePressEvent(event);
    }

    void mouseReleaseEvent(QMouseEvent *event) override
    {
        setStyleSheet("background-color: blue;");
        QPushButton::mouseReleaseEvent(event);
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个父级 QWidget
    QWidget parentWidget;
    parentWidget.setWindowTitle("Parent Widget");
    parentWidget.setGeometry(100, 100, 300, 200);

    // 创建一个垂直布局管理器
    QVBoxLayout layout(&parentWidget);

    // 创建一个自定义按钮控件作为父级控件的子元素
    CustomButton *button = new CustomButton(&parentWidget);
    button->setText("Click me");
    layout.addWidget(button);

    parentWidget.show();

    return app.exec();
}

代码结果:

  样式属性

        QSS 中的样式属性⾮常多, 不需要都记住. 核⼼原则还是⽤到了就去查.
        ⼤部分的属性和 CSS 是⾮常相似的.

        盒模型

⼀个遵守盒模型的控件, 由上述⼏个部分构成.
        • Content 矩形区域: 存放控件内容. ⽐如包含的⽂本/图标等.
        • Border 矩形区域: 控件的边框.
        • Padding 矩形区域: 内边距. 边框和内容之间的距离.
        • Margin 矩形区域: 外边距. 边框到控件 geometry 返回的矩形边界的距离
默认情况下, 外边距, 内边距, 边框宽度都是0.

        可以通过⼀些 QSS 属性来设置上述的边距和边框的样式.

QSS 属性
说明
margin
设置四个⽅向的外边距. 复合属性.
padding
设置四个⽅向的内边距. 复合属性.
border-style
设置边框样式
border-width
边框的粗细
border-color
边框的颜⾊
border
复合属性, 相当于 border-style + border-width + border-color

 代码⽰例: 设置边框和内边距、设置外边距

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QHBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个主窗口
    QWidget mainWindow;
    mainWindow.setWindowTitle("Qt Style Sheets 示例");

    // 创建一个按钮
    QPushButton button("按钮示例", &mainWindow);

    // 使用布局管理按钮位置
    QHBoxLayout layout;
    layout.addWidget(&button);
    mainWindow.setLayout(&layout);

    // 设置样式
    mainWindow.setStyleSheet(
        "QPushButton {"
        "    border: 2px solid #000000; /* 设置边框 */"
        "    padding: 10px; /* 设置内边距 */"
        "    margin: 20px; /* 设置外边距 */"
        "}");

    mainWindow.show();

    return app.exec();
}

代码结果: 

  控件样式示例

        改变样式表, 使⽤ Qt Designer 设置样式

        按钮

QPushButton 
{
    background-color: #4CAF50; /* 设置背景颜色为绿色 */
    border: none; /* 去掉边框 */
    color: white; /* 文字颜色为白色 */
    padding: 10px 20px; /* 设置内边距 */
    text-align: center; /* 文字居中显示 */
    text-decoration: none; /* 去掉文字下划线 */
    display: inline-block; /* 行内块元素 */
    font-size: 16px; /* 设置字体大小 */
    margin: 4px 2px; /* 设置外边距 */
    cursor: pointer; /* 鼠标移上去显示手型 */
    border-radius: 8px; /* 设置圆角 */
}

        复选框、单选框

QCheckBox::indicator, QRadioButton::indicator 
{
    width: 20px; /* 设置指示器宽度 */
    height: 20px; /* 设置指示器高度 */
}

QCheckBox::indicator:checked, QRadioButton::indicator:checked 
{
    background-color: #2196F3; /* 设置选中时的背景颜色 */
}

        输入框

QLineEdit 
{
    padding: 8px; /* 设置内边距 */
    border: 1px solid #ccc; /* 设置边框 */
    border-radius: 5px; /* 设置圆角 */
}

QLineEdit:hover 
{
    border-color: #4CAF50; /* 鼠标移上去时边框颜色变为绿色 */
}

        列表

QListWidget 
{
    background-color: #f2f2f2; /* 设置背景颜色为灰色 */
    padding: 10px; /* 设置内边距 */
    border: 1px solid #ccc; /* 设置边框 */
    border-radius: 5px; /* 设置圆角 */
}

        菜单栏

QMenuBar 
{
    background-color: #333; /* 设置背景颜色为深灰色 */
    color: white; /* 设置文字颜色为白色 */
}

QMenuBar::item 
{
    spacing: 3px; /* 设置项之间的间距 */
    padding: 1px 4px; /* 设置内边距 */
    background-color: transparent; /* 背景透明 */
    color: white; /* 文字颜色为白色 */
}

QMenuBar::item:selected 
{
    background-color: #4CAF50; /* 选中时的背景颜色为绿色 */
}

        登录界面

QWidget 
{
    background-color: #f2f2f2; /* 设置背景颜色为灰色 */
}

QLineEdit, QPushButton 
{
    border-radius: 3px; /* 设置圆角 */
    padding: 8px; /* 设置内边距 */
    border: 1px solid #ccc; /* 设置边框 */
}

QPushButton 
{
    background-color: #4CAF50; /* 设置背景颜色为绿色 */
    color: white; /* 文字颜色为白色 */
}

QPushButton:hover 
{
    background-color: #45a049; /* 鼠标移上去时背景颜色变深 */
}

绘图

  基本概念

        虽然 Qt 已经内置了很多的控件, 但是不能保证现有控件就可以应对所有场景.

        很多时候我们需要更强的 "⾃定制" 能⼒.

        Qt 提供了画图相关的 API, 可以允许我们在窗⼝上绘制任意的图形形状, 来完成更复杂的界⾯设计.

注意:

        所谓的 "控件" , 本质上也是通过画图的⽅式画上去的.

        画图 API 和 控件 之间的关系, 可以类⽐成机器指令和⾼级语⾔之间的关系.

        控件是对画图 API 的进⼀步封装; 画图 API 是控件的底层实现.

绘图 API 核⼼类

说明
QPainter
"绘画者" 或者 "画家".
⽤来绘图的对象, 提供了⼀系列 drawXXX ⽅法, 可以允许我们绘制各种图 形.
QPaintDevice
"画板".
描述了 QPainter 把图形画到哪个对象上. 像咱们之前⽤过的 QWidget 也是⼀种 QPaintDevice (QWidget 是 QPaintDevice 的⼦类) .
QPen
“画笔”.
描述了QPainter 画出来的线是什么样的.
QBrush
"画刷".
描述了 QPainter 填充⼀个区域是什么样的.

         绘图 API 的使⽤, ⼀般不会在 QWidget 的构造函数中使⽤, ⽽是要放到 paintEvent 事件中.

  绘制各种形状

        绘制线段

        使用painter.drawLine(x1, y1, x2, y2)可以绘制从点 (x1, y1) 到点 (x2, y2) 的直线。

        绘制矩形

        使用painter.drawRect(x, y, width, height)可以绘制一个矩形,左上角坐标为 (x, y),宽为 width,高为 height

        绘制圆形

        使用painter.drawEllipse(x, y, width, height)可以绘制一个椭圆或者近似圆形,其外接矩形的左上角坐标为 (x, y),宽为 width,高为 height

        绘制文本

        使用painter.drawText(x, y, text)可以在指定的位置 (x, y) 绘制文本 text

        设置画笔

        使用painter.setPen(pen)可以设置画笔的颜色、线条宽度、样式等属性。

        设置画刷

        使用painter.setBrush(brush)可以设置画刷的颜色,用于填充形状的内部。

示例代码:

#include <QtWidgets>

class MyWidget : public QWidget
{
public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent) {}

protected:
    void paintEvent(QPaintEvent *event) override
    {
        Q_UNUSED(event);

        QPainter painter(this);
        
        // 绘制线段
        painter.setPen(Qt::black);  // 设置画笔颜色为黑色
        painter.drawLine(20, 20, 200, 20);  // 从 (20, 20) 到 (200, 20) 绘制一条线段
        
        // 绘制矩形
        painter.setPen(Qt::blue);  // 设置画笔颜色为蓝色
        painter.drawRect(20, 40, 100, 50);  // 绘制一个矩形,左上角坐标 (20, 40),宽高为 100x50
        
        // 绘制圆形
        painter.setPen(Qt::red);  // 设置画笔颜色为红色
        painter.drawEllipse(20, 100, 80, 80);  // 绘制一个圆形,外接矩形左上角坐标 (20, 100),宽高为 80x80
        
        // 绘制文本
        painter.setPen(Qt::black);  // 设置画笔颜色为黑色
        painter.setFont(QFont("Arial", 12));  // 设置字体和字号
        painter.drawText(20, 200, "Hello, Qt!");  // 在 (20, 200) 处绘制文本
        
        // 设置画笔和画刷
        painter.setPen(Qt::black);  // 设置画笔颜色为黑色
        painter.setBrush(Qt::green);  // 设置画刷颜色为绿色
        painter.drawRect(20, 220, 100, 50);  // 绘制一个带有绿色填充的矩形,左上角坐标 (20, 220),宽高为 100x50
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    MyWidget widget;
    widget.resize(300, 300);
    widget.setWindowTitle("Drawing Shapes in Qt");
    widget.show();
    
    return app.exec();
}

代码结果: 

  绘制图片

        使用QPixmap pixmap(":/images/cat.jpg")加载一个图片,路径可以是文件系统路径或者Qt资源文件路径。

        绘制简单图片

        使用painter.drawPixmap(x, y, pixmap)在指定位置 (x, y) 绘制原始大小的图片。

        缩放图片

        使用pixmap.scaled(width, height, aspectRatioMode)可以缩放图片到指定的宽度和高度,aspectRatioMode参数指定保持长宽比的方式。

        旋转图片

        使用pixmap.transformed(QTransform().rotate(angle))可以旋转图片,angle为旋转的角度。

使用QPixmap实现代码示例:

#include <QtWidgets>

class MyWidget : public QWidget
{
public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent) {}

protected:
    void paintEvent(QPaintEvent *event) override
    {
        Q_UNUSED(event);

        QPainter painter(this);

        // 加载图片
        QPixmap pixmap(":/images/cat.jpg");  // 替换为你自己的图片路径或者资源文件路径

        // 绘制简单图片
        painter.drawPixmap(20, 20, pixmap);  // 在 (20, 20) 处绘制原始大小的图片

        // 缩放图片
        QPixmap scaledPixmap = pixmap.scaled(200, 150, Qt::KeepAspectRatio);  // 缩放图片到 200x150 大小,保持长宽比
        painter.drawPixmap(240, 20, scaledPixmap);  // 在 (240, 20) 处绘制缩放后的图片

        // 旋转图片
        QPixmap rotatedPixmap = pixmap.transformed(QTransform().rotate(30.0));  // 旋转图片30度
        painter.drawPixmap(20, 200, rotatedPixmap);  // 在 (20, 200) 处绘制旋转后的图片
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MyWidget widget;
    widget.resize(500, 400);
    widget.setWindowTitle("Pixmap Drawing in Qt");
    widget.show();

    return app.exec();
}

代码结果: 

  特殊的画图设备

        前⾯的代码中我们是使⽤ QWidget 作为绘图设备. 在 Qt 中还存在下列三个⽐较特殊的绘图设备. 此处我们也简要介绍.

• QPixmap ⽤于在显⽰器上显⽰图⽚.
• QImage ⽤于对图⽚进⾏像素级修改.
• QPicture ⽤于对 QPainter 的⼀系列操作进⾏存档.

        QPixmap

  • 定义:QPixmap是一个用于处理图像显示的类,它以设备无关的方式存储图像数据,通常用于在屏幕上绘制图像。
  • 特点:QPixmap支持设备无关的图像操作,可以在不同平台上使用相同的接口来处理图像。它可以从文件、内存或绘制操作中创建,并且可以用作GUI界面中的图像资源。
  • 用途:常用于在Qt应用程序中绘制、显示图像,例如在标签、按钮等控件中显示图像。
#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个QPixmap对象并加载图片
    QPixmap pixmap("path/to/image.png");

    // 创建一个标签并显示图片
    QLabel label;
    label.setPixmap(pixmap);
    label.show();

    return app.exec();
}

        QImage

  • 定义:QImage是一个用于处理图像数据的类,它提供了对像素级别的直接访问,支持丰富的图像处理和转换功能。
  • 特点:QImage存储像素数据,并提供了对像素级别的访问和编辑。它可以从文件加载图像,也可以通过像素级别的操作进行创建和编辑。
  • 用途:适合需要对图像进行详细处理、转换、编辑的场景,例如图像处理应用、算法实现等。
#include <QApplication>
#include <QImage>
#include <QLabel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个QImage对象并加载图片
    QImage image("path/to/image.png");

    // 修改图片像素,这里简单地将图片变为灰度
    for (int y = 0; y < image.height(); ++y) {
        for (int x = 0; x < image.width(); ++x) {
            QRgb pixel = image.pixel(x, y);
            int gray = qGray(pixel);
            image.setPixel(x, y, qRgb(gray, gray, gray));
        }
    }

    // 创建一个标签并显示图片
    QLabel label;
    label.setPixmap(QPixmap::fromImage(image));
    label.show();

    return app.exec();
}

        QPicture

  • 定义:QPicture是一个用于记录和重现绘图操作的类,它存储了绘图操作的命令序列而非像素数据。
  • 特点:QPicture可以记录绘制操作(如绘制线条、文本、图形等),并且可以在需要时进行重放。它不直接处理像素级别的图像数据,而是记录绘制操作的历史。
  • 用途:通常用于需要重放绘图命令的场景,例如图形绘制的撤销和重做、打印预览等。
#include <QApplication>
#include <QPainter>
#include <QPicture>
#include <QLabel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个QPicture对象并记录绘图操作
    QPicture picture;
    QPainter painter;
    painter.begin(&picture);
    painter.setPen(Qt::red);
    painter.drawRect(10, 10, 100, 100);
    painter.drawLine(20, 20, 80, 80);
    painter.end();

    // 创建一个标签并显示QPicture中记录的绘图操作
    QLabel label;
    painter.begin(&label);
    painter.drawPicture(0, 0, picture);
    painter.end();
    label.show();

    return app.exec();
}

总结:

  • QPixmap用于显示和处理图像,提供了简单的设备无关接口。
  • QImage用于直接处理图像数据,支持更多的图像操作和转换。
  • QPicture用于记录和重放绘图命令,适合于需要复杂绘图历史记录和重现的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/767680.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Kali-linux for WSL】图形化界面安装

文章目录 前言图形化界面安装 前言 之前在WSL中安装了Kali 启动之后发现什么都没有&#xff01;&#xff01;&#xff01; 那我还怎么学习渗透技术&#xff1f;&#xff1f;&#xff1f; 看来&#xff0c;得改进下我的kali-linux for wsl&#xff0c;安装个图形化界面 图形化…

Jetson系列机载电脑创建热点模式配置方法

Jetson nano为例—— 创建热点模式配置方法 1.1、新建一个 WiFi 在屏幕右上角找到网络图标&#xff0c;点击后选择“Edit Connections”选项&#xff0c;进入选择网络连接页面&#xff0c;然后点击左下角加号&#xff0c;新建一个连接&#xff0c;类型选择 WiFi 后点击 “cre…

AI降重,不再难:降AI率的实用技巧大揭秘

如何有效降低AIGC论文的重复率&#xff0c;也就是我们说的aigc如何降重&#xff1f;AIGC疑似度过高确实是个比较愁人的问题。如果你用AI帮忙写了论文&#xff0c;就一定要在交稿之前做一下AIGC降重的检查。一般来说&#xff0c;如果论文的AIGC超过30%&#xff0c;很可能会被判定…

剪画小程序:如何将视频变成自己的作品!在手机上这样做就可以了!

亲爱的小伙伴们&#xff0c;我是你们的博主小画&#xff01; 今天和大家分享两个在视频剪辑中实用的技巧—旋转视频和添加水印&#xff01; 在我们的创作过程中&#xff0c;有时候常规的视角并不能完全展现出视频的魅力和创意。而通过旋转视频&#xff0c;就能为观众带来全新的…

【云原生监控】Prometheus 普罗米修斯从搭建到使用详解

目录 一、前言 二、服务监控概述 2.1 什么是微服务监控 2.2 微服务监控指标 2.3 微服务监控工具 三、Prometheus概述 3.1 Prometheus是什么 3.2 Prometheus 特点 3.3 Prometheus 架构图 3.3.1 Prometheus核心组件 3.3.2 Prometheus 工作流程 3.4 Prometheus 应用场景…

新规则!2024年信息素养大赛复赛图形化编程题这么写系统才能通过

2024年全国青少年信息素养大赛复赛即将在7月6日陆续开赛&#xff0c;今年Scratch图形化编程小低组和小高组分别为6道编程题&#xff0c;将采用新的判题规则&#xff0c;类似GESP的OJ系统判题&#xff0c;主要有以下三个方面&#xff1a; 1、变量名大小写要和题目完全一致。 2…

数据万象推出智能检索MetaInsight,现已开启限时公测

海量文件的分析统计一直是对象存储COS的热点需求&#xff0c;伴随AIGC飞速迭代发展&#xff0c;在众多不同模态素材的海洋中&#xff0c;用户也急需更高效地管理和利用多媒体内容&#xff0c;打破传统搜索的桎梏。 数据万象推出的智能检索 MetaInsight 服务将多模态检索与元数…

开源之夏|祝贺MatrixOne开源社区项目中选同学!

在本届「开源之夏 2024」活动中&#xff0c;MatrixOne开源社区共计上线3个项目任务&#xff0c;最终有 3位同学成功突围。接下来让我们看看每个项目的详细中选情况&#xff1a; 中选学生公示 项目名称&#xff1a;基于大语言模型的操作系统任务自动识别&#xff0c;拆解&#…

Unicode 和 UTF-8 以及它们之间的关系

通俗易懂的 Unicode 和 UTF-8 解释 Unicode 是什么&#xff1f; 想象一下&#xff0c;我们有一个巨大的图书馆&#xff0c;这个图书馆里有各种各样的书&#xff0c;每本书都有一个唯一的编号。Unicode 就像是这个图书馆的目录系统&#xff0c;它给世界上所有的字符&#xff0…

数据要素如何转化为生产力?关键在以指标为中心实现数据分析“快全准省”

进入到数字化时代&#xff0c;企业的经营变得越来越精细化、智能化、自动化&#xff0c;其中&#xff0c;数据就变成了关键要素&#xff0c;在企业的业务运营、经营决策、流程改进、创新驱动、资源配置等方面发挥出巨大作用。 数据具体如何转化为生产力&#xff0c;有几个关键…

俄罗斯ozon运费计算工具,跨境电商ozon物流运费计算工具

OZON平台服装类目卖家而言&#xff0c;如何快速、准确地为产品定价&#xff0c;并有效管理运费成本&#xff0c;直接关系到市场竞争力与利润空间。接下来我们看看俄罗斯ozon运费计算工具&#xff0c;跨境电商ozon物流运费计算工具。 萌啦Ozon定价工具&#xff1a;智能模拟&…

OCR text detect

主干网络 VoVNet&#xff1a;实时目标检测的新backbone网络_vovnet pytorch-CSDN博客 DenseNet&#xff1a; arxiv.org/pdf/1608.06993 密集连接&#xff1a; DenseNet 的核心思想是将网络中的每一层与其前面的所有层直接连接。对于一个 L 层的网络&#xff0c;DenseNet 具有…

【深度学习】扫描全能王的AI驱动创新与智能高清滤镜技术解析

目录 引言1、扫描全能王2、智能高清滤镜黑科技2.1、图像视觉矫正2.2、去干扰技术 3、实际应用案例3.1、打印文稿褶皱检测3.2、试卷擦除手写3.3、老旧文件处理3.4、收银小票3.5、从不同角度扫描文档 4、用户体验结论与未来展望 引言 在数字化时代背景下&#xff0c;文档扫描功能…

AI是在帮助开发者还是取代他们

目录 1.概述 1.1.AI助力开发者 1.2.AI对开发者的挑战 2.AI工具现状 2.1. GitHub Copilot 2.2. TabNine 2.3.小结 3.AI对开发者的影响 3.1.对开发者的影响 3.2.开发者需要掌握的新技能 3.3.在AI辅助的环境中保持竞争力的策略 4.AI开发的未来 5.总结 1.概述 生成式…

Git学习(常用的一些命令)

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 配置相关&#xff1a; 创建与克隆仓库&#xff1a; 基本操作&#xff1a; 分支操作&#xff1a; 远程仓库操作&#xff1a…

使用Adobe Acrobat对PDF文档进行数字签名

文章目录 前言一、使用Adobe Acrobat对PDF文档进行数字签名1.使用Adobe Acrobat打开需要进行签名的PDF文档2. 点击【查看更多】3.点击【使用证书】4.点击【数字签名】5.使用鼠标选定一个区域6.选择您需要使用的证书 → 点击【继续】7.点击【签名】8.签名成功 前言 一、使用Ado…

App渗透:BurpSuite插件-Brida apk逆向自动加解密Custom plugins演示

文章目录 前言Eureka 前言 【App渗透:BurpSuite插件-Brida apk逆向自动加解密Custom plugins演示】 很久很久之前&#xff0c;更新过Brida的安装和hook脚本的调试&#xff0c;今晚终于更新了Brida的核心功能&#xff0c;自动加解密。视频里演示的app是我自己开发的&#xff0c…

OpenLCA、GREET、R语言的生命周期评价方法、模型构建

原文链接&#xff1a;OpenLCA、GREET、R语言的生命周期评价方法、模型构建教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608240&idx6&sn1b5758206d500399fe7cc69e800f61fe&chksmfa826657cdf5ef413d31557941a1c5db5cc84bba8d0f408c469e05a4118c…

Ubuntu 22.04 LTS 上安装 MySQL8.0.23(在线安装)

目录 在线安装MySQL 步骤1&#xff1a;更新软件包列表 步骤2&#xff1a;安装MySQL服务器 步骤3&#xff1a;启动MySQL服务 步骤4&#xff1a;检查MySQL状态 步骤5&#xff1a;修改密码、权限 在线安装MySQL 步骤1&#xff1a;更新软件包列表 在进行任何软件安装之前&a…

nginx优化和防盗链

1、隐藏版本号 [roottest1 conf]# vim nginx.conf ​ server_tokens off; ​ 2、防盗链 修改用户和所在组 [roottest1 conf]# vim nginx.conf ​ #user nginx nginx; #表示主进程master会有root创建&#xff0c;子进程会有nginx用户来创建。 3、设置页面的缓存时间 主要是…
最新文章